Skip to content

Commit

Permalink
Add ActivityPub representation for identity proofs (mastodon#10414)
Browse files Browse the repository at this point in the history
* Add ActivityPub representation for identity proofs

* Add tests
  • Loading branch information
Gargron authored Mar 30, 2019
1 parent d146596 commit 123a308
Show file tree
Hide file tree
Showing 5 changed files with 93 additions and 4 deletions.
1 change: 1 addition & 0 deletions app/lib/activitypub/adapter.rb
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ class ActivityPub::Adapter < ActiveModelSerializers::Adapter::Base
atom_uri: { 'ostatus' => 'http://ostatus.org#', 'atomUri' => 'ostatus:atomUri' },
conversation: { 'ostatus' => 'http://ostatus.org#', 'inReplyToAtomUri' => 'ostatus:inReplyToAtomUri', 'conversation' => 'ostatus:conversation' },
focal_point: { 'toot' => 'http://joinmastodon.org/ns#', 'focalPoint' => { '@container' => '@list', '@id' => 'toot:focalPoint' } },
identity_proof: { 'toot' => 'http://joinmastodon.org/ns#', 'IdentityProof' => 'toot:IdentityProof' },
}.freeze

def self.default_key_transform
Expand Down
3 changes: 2 additions & 1 deletion app/lib/proof_provider/keybase.rb
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,8 @@ def validate!
return
end

return if @proof.provider_username.blank?
# Do not perform synchronous validation for remote accounts
return if @proof.provider_username.blank? || !@proof.account.local?

if verifier.valid?
@proof.verified = true
Expand Down
24 changes: 22 additions & 2 deletions app/serializers/activitypub/actor_serializer.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ class ActivityPub::ActorSerializer < ActivityPub::Serializer
context :security

context_extensions :manually_approves_followers, :featured, :also_known_as,
:moved_to, :property_value, :hashtag, :emoji
:moved_to, :property_value, :hashtag, :emoji, :identity_proof

attributes :id, :type, :following, :followers,
:inbox, :outbox, :featured,
Expand Down Expand Up @@ -115,7 +115,7 @@ def virtual_tags
end

def virtual_attachments
object.fields
object.fields + object.identity_proofs.active
end

def moved_to
Expand Down Expand Up @@ -158,4 +158,24 @@ def value
Formatter.instance.format_field(object.account, object.value)
end
end

class AccountIdentityProofSerializer < ActivityPub::Serializer
attributes :type, :name, :signature_algorithm, :signature_value

def type
'IdentityProof'
end

def name
object.provider_username
end

def signature_algorithm
object.provider
end

def signature_value
object.token
end
end
end
28 changes: 27 additions & 1 deletion app/services/activitypub/process_account_service.rb
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ def call(username, domain, json, options = {})
create_account if @account.nil?
update_account
process_tags
process_attachments
else
raise Mastodon::RaceConditionError
end
Expand Down Expand Up @@ -151,7 +152,7 @@ def url

def property_values
return unless @json['attachment'].is_a?(Array)
@json['attachment'].select { |attachment| attachment['type'] == 'PropertyValue' }.map { |attachment| attachment.slice('name', 'value') }
as_array(@json['attachment']).select { |attachment| attachment['type'] == 'PropertyValue' }.map { |attachment| attachment.slice('name', 'value') }
end

def mismatching_origin?(url)
Expand Down Expand Up @@ -231,6 +232,23 @@ def process_tags
end
end

def process_attachments
return if @json['attachment'].blank?

previous_proofs = @account.identity_proofs.to_a
current_proofs = []

as_array(@json['attachment']).each do |attachment|
next unless equals_or_includes?(attachment['type'], 'IdentityProof')
current_proofs << process_identity_proof(attachment)
end

previous_proofs.each do |previous_proof|
next if current_proofs.any? { |current_proof| current_proof.id == previous_proof.id }
previous_proof.delete
end
end

def process_emoji(tag)
return if skip_download?
return if tag['name'].blank? || tag['icon'].blank? || tag['icon']['url'].blank?
Expand All @@ -247,4 +265,12 @@ def process_emoji(tag)
emoji.image_remote_url = image_url
emoji.save
end

def process_identity_proof(attachment)
provider = attachment['signatureAlgorithm']
provider_username = attachment['name']
token = attachment['signatureValue']

@account.identity_proofs.where(provider: provider, provider_username: provider_username).find_or_create_by(provider: provider, provider_username: provider_username, token: token)
end
end
41 changes: 41 additions & 0 deletions spec/services/activitypub/process_account_service_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -28,4 +28,45 @@
expect(account.fields[1].value).to eq 'Unit test'
end
end

context 'identity proofs' do
let(:payload) do
{
id: 'https://foo.test',
type: 'Actor',
inbox: 'https://foo.test/inbox',
attachment: [
{ type: 'IdentityProof', name: 'Alice', signatureAlgorithm: 'keybase', signatureValue: 'a' * 66 },
],
}.with_indifferent_access
end

it 'parses out of attachment' do
account = subject.call('alice', 'example.com', payload)

expect(account.identity_proofs.count).to eq 1

proof = account.identity_proofs.first

expect(proof.provider).to eq 'keybase'
expect(proof.provider_username).to eq 'Alice'
expect(proof.token).to eq 'a' * 66
end

it 'removes no longer present proofs' do
account = Fabricate(:account, username: 'alice', domain: 'example.com')
old_proof = Fabricate(:account_identity_proof, account: account, provider: 'keybase', provider_username: 'Bob', token: 'b' * 66)

subject.call('alice', 'example.com', payload)

expect(account.identity_proofs.count).to eq 1
expect(account.identity_proofs.find_by(id: old_proof.id)).to be_nil
end

it 'queues a validity check on the proof' do
allow(ProofProvider::Keybase::Worker).to receive(:perform_async)
account = subject.call('alice', 'example.com', payload)
expect(ProofProvider::Keybase::Worker).to have_received(:perform_async)
end
end
end

0 comments on commit 123a308

Please sign in to comment.