diff options
author | Thibaut Girka <thib@sitedethib.com> | 2020-06-09 10:39:20 +0200 |
---|---|---|
committer | Thibaut Girka <thib@sitedethib.com> | 2020-06-09 10:39:20 +0200 |
commit | 12c8ac9e1443d352eca3538ed1558de8ccdd9434 (patch) | |
tree | ed480d77b29f0d571ad219190288bde3b0c09b32 /app/services/keys/claim_service.rb | |
parent | f328f2faa3fbdb182921366c6a20e745c069b840 (diff) | |
parent | 89f40b6c3ec525b09d02f21e9b45276084167d8d (diff) |
Merge branch 'master' into glitch-soc/merge-upstream
Conflicts: - `app/controllers/activitypub/collections_controller.rb`: Conflict due to glitch-soc having to take care of local-only pinned toots in that controller. Took upstream's changes and restored the local-only special handling. - `app/controllers/auth/sessions_controller.rb`: Minor conflicts due to the theming system, applied upstream changes, adapted the following two files for glitch-soc's theming system: - `app/controllers/concerns/sign_in_token_authentication_concern.rb` - `app/controllers/concerns/two_factor_authentication_concern.rb` - `app/services/backup_service.rb`: Minor conflict due to glitch-soc having to handle local-only toots specially. Applied upstream changes and restored the local-only special handling. - `app/views/admin/custom_emojis/index.html.haml`: Minor conflict due to the theming system. - `package.json`: Upstream dependency updated, too close to a glitch-soc-only dependency in the file. - `yarn.lock`: Upstream dependency updated, too close to a glitch-soc-only dependency in the file.
Diffstat (limited to 'app/services/keys/claim_service.rb')
-rw-r--r-- | app/services/keys/claim_service.rb | 77 |
1 files changed, 77 insertions, 0 deletions
diff --git a/app/services/keys/claim_service.rb b/app/services/keys/claim_service.rb new file mode 100644 index 000000000..672119130 --- /dev/null +++ b/app/services/keys/claim_service.rb @@ -0,0 +1,77 @@ +# frozen_string_literal: true + +class Keys::ClaimService < BaseService + HEADERS = { 'Content-Type' => 'application/activity+json' }.freeze + + class Result < ActiveModelSerializers::Model + attributes :account, :device_id, :key_id, + :key, :signature + + def initialize(account, device_id, key_attributes = {}) + @account = account + @device_id = device_id + @key_id = key_attributes[:key_id] + @key = key_attributes[:key] + @signature = key_attributes[:signature] + end + end + + def call(source_account, target_account_id, device_id) + @source_account = source_account + @target_account = Account.find(target_account_id) + @device_id = device_id + + if @target_account.local? + claim_local_key! + else + claim_remote_key! + end + rescue ActiveRecord::RecordNotFound + nil + end + + private + + def claim_local_key! + device = @target_account.devices.find_by(device_id: @device_id) + key = nil + + ApplicationRecord.transaction do + key = device.one_time_keys.order(Arel.sql('random()')).first! + key.destroy! + end + + @result = Result.new(@target_account, @device_id, key) + end + + def claim_remote_key! + query_result = QueryService.new.call(@target_account) + device = query_result.find(@device_id) + + return unless device.present? && device.valid_claim_url? + + json = fetch_resource_with_post(device.claim_url) + + return unless json.present? && json['publicKeyBase64'].present? + + @result = Result.new(@target_account, @device_id, key_id: json['id'], key: json['publicKeyBase64'], signature: json.dig('signature', 'signatureValue')) + rescue HTTP::Error, OpenSSL::SSL::SSLError, Mastodon::Error => e + Rails.logger.debug "Claiming one-time key for #{@target_account.acct}:#{@device_id} failed: #{e}" + nil + end + + def fetch_resource_with_post(uri) + build_post_request(uri).perform do |response| + raise Mastodon::UnexpectedResponseError, response unless response_successful?(response) || response_error_unsalvageable?(response) + + body_to_json(response.body_with_limit) if response.code == 200 + end + end + + def build_post_request(uri) + Request.new(:post, uri).tap do |request| + request.on_behalf_of(@source_account, :uri) + request.add_headers(HEADERS) + end + end +end |