Merge pull request #89 from cmrd-senya/account_migration_changes
Extract singning of AccountMigration to a different module and introduce alternative form for account migration message
This commit is contained in:
commit
d9a02119b8
11 changed files with 360 additions and 150 deletions
|
|
@ -8,9 +8,16 @@ This entity is sent when a person changes their diaspora* ID (e.g. when a user m
|
|||
|
||||
| Property | Type | Description |
|
||||
| ----------- | ---------------------------- | ------------------------------------------------------------------------------------ |
|
||||
| `author` | [diaspora\* ID][diaspora-id] | The diaspora\* ID of the closed account. |
|
||||
| `person` | [Profile][profile] | New profile of a person |
|
||||
| `signature` | [Signature][signature] | Signature that validates original and target diaspora* IDs with the new key of person |
|
||||
| `author` | [diaspora\* ID][diaspora-id] | The diaspora\* ID of the sender of the entity. The entity may be sent by either old user identity or new user identity. |
|
||||
| `person` | [Profile][profile] | New profile of a person. |
|
||||
| `signature` | [Signature][signature] | Signature that validates original and target diaspora* IDs with the private key of the second identity, other than the entity author. So if the author is the old identity then this signature is made with the new identity key, and vice versa. |
|
||||
|
||||
## Optional Properties
|
||||
|
||||
| Property | Type | Description |
|
||||
| ----------- | ---------------------------- | ------------------------------------------------------------------------------------ |
|
||||
| `old_identity` | [diaspora\* ID][diaspora-id] | The diaspora\* ID of the closed account. This field is mandatory if the author of the entity is the new identity. |
|
||||
|
||||
|
||||
### Signature
|
||||
|
||||
|
|
@ -51,6 +58,7 @@ AccountMigration:old-diaspora-id@example.org:new-diaspora-id@example.com
|
|||
<signature>
|
||||
07b1OIY6sTUQwV5pbpgFK0uz6W4cu+oQnlg410Q4uISUOdNOlBdYqhZJm62VFhgvzt4TZXfiJgoupFkRjP0BsaVaZuP2zKMNvO3ngWOeJRf2oRK4Ub5cEA/g7yijkRc+7y8r1iLJ31MFb1czyeCsLxw9Ol8SvAJddogGiLHDhjE=
|
||||
</signature>
|
||||
<old_identity>alice@example.org</old_identity>
|
||||
</account_migration>
|
||||
~~~
|
||||
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ require "diaspora_federation/entities/related_entity"
|
|||
# abstract types
|
||||
require "diaspora_federation/entities/post"
|
||||
require "diaspora_federation/entities/signable"
|
||||
require "diaspora_federation/entities/account_migration/signable"
|
||||
require "diaspora_federation/entities/relayable"
|
||||
|
||||
# types
|
||||
|
|
|
|||
|
|
@ -5,10 +5,12 @@ module DiasporaFederation
|
|||
#
|
||||
# @see Validators::AccountMigrationValidator
|
||||
class AccountMigration < Entity
|
||||
include Signable
|
||||
include AccountMigration::Signable
|
||||
|
||||
# @!attribute [r] author
|
||||
# The old diaspora* ID of the person who changes their ID
|
||||
# Sender of the AccountMigration message. Usually it is the old diaspora* ID of the person who changes their ID.
|
||||
# This property is also allowed to be the new diaspora* ID, which is equal to the author of the included
|
||||
# profile.
|
||||
# @see Person#author
|
||||
# @return [String] author diaspora* ID
|
||||
property :author, :string
|
||||
|
|
@ -19,20 +21,39 @@ module DiasporaFederation
|
|||
entity :profile, Entities::Profile
|
||||
|
||||
# @!attribute [r] signature
|
||||
# Signature that validates original and target diaspora* IDs with the new key of person
|
||||
# Signature that validates original and target diaspora* IDs with the private key of the second identity, other
|
||||
# than the entity author. So if the author is the old identity then this signature is made with the new identity
|
||||
# key, and vice versa.
|
||||
# @return [String] signature
|
||||
property :signature, :string, default: nil
|
||||
|
||||
# @return [String] string representation of this object
|
||||
def to_s
|
||||
"AccountMigration:#{author}:#{profile.author}"
|
||||
# @!attribute [r] old_identity
|
||||
# Optional attribute which keeps old diaspora* ID. Must be present when author attribute contains new diaspora*
|
||||
# ID.
|
||||
# @return [String] old identity
|
||||
property :old_identity, :string, default: nil
|
||||
|
||||
# Returns diaspora* ID of the old person identity.
|
||||
# @return [String] diaspora* ID of the old person identity
|
||||
def old_identity
|
||||
return @old_identity if author_is_new_id?
|
||||
author
|
||||
end
|
||||
|
||||
# Returns diaspora* ID of the new person identity.
|
||||
# @return [String] diaspora* ID of the new person identity
|
||||
def new_identity
|
||||
profile.author
|
||||
end
|
||||
|
||||
# @return [String] string representation of this object
|
||||
alias to_s unique_migration_descriptor
|
||||
|
||||
# Shortcut for calling super method with sensible arguments
|
||||
#
|
||||
# @see DiasporaFederation::Entities::Signable#verify_signature
|
||||
def verify_signature
|
||||
super(profile.author, :signature)
|
||||
super(signer_id, :signature)
|
||||
end
|
||||
|
||||
# Calls super and additionally does signature verification for the instantiated entity.
|
||||
|
|
@ -44,30 +65,33 @@ module DiasporaFederation
|
|||
|
||||
private
|
||||
|
||||
# @see DiasporaFederation::Entities::Signable#signature_data
|
||||
def signature_data
|
||||
to_s
|
||||
def author_is_new_id?
|
||||
author == new_identity
|
||||
end
|
||||
|
||||
def signer_id
|
||||
author_is_new_id? ? @old_identity : new_identity
|
||||
end
|
||||
|
||||
def enriched_properties
|
||||
super.tap do |hash|
|
||||
hash[:signature] = signature || sign_with_new_key
|
||||
hash[:signature] = signature || sign_with_respective_key
|
||||
end
|
||||
end
|
||||
|
||||
# Sign with new user's key
|
||||
# @raise [NewPrivateKeyNotFound] if the new user's private key is not found
|
||||
# Sign with the key of the #signer_id identity
|
||||
# @raise [PrivateKeyNotFound] if the signer's private key is not found
|
||||
# @return [String] A Base64 encoded signature of #signature_data with key
|
||||
def sign_with_new_key
|
||||
privkey = DiasporaFederation.callbacks.trigger(:fetch_private_key, profile.author)
|
||||
raise NewPrivateKeyNotFound, "author=#{profile.author} obj=#{self}" if privkey.nil?
|
||||
def sign_with_respective_key
|
||||
privkey = DiasporaFederation.callbacks.trigger(:fetch_private_key, signer_id)
|
||||
raise PrivateKeyNotFound, "signer=#{signer_id} obj=#{self}" if privkey.nil?
|
||||
sign_with_key(privkey).tap do
|
||||
logger.info "event=sign status=complete signature=signature author=#{profile.author} obj=#{self}"
|
||||
logger.info "event=sign status=complete signature=signature signer=#{signer_id} obj=#{self}"
|
||||
end
|
||||
end
|
||||
|
||||
# Raised, if creating the signature fails, because the new private key of a user was not found
|
||||
class NewPrivateKeyNotFound < RuntimeError
|
||||
class PrivateKeyNotFound < RuntimeError
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -0,0 +1,24 @@
|
|||
module DiasporaFederation
|
||||
module Entities
|
||||
class AccountMigration < Entity
|
||||
# AccountMigration::Signable is a module that encapsulates basic signature generation/verification flow for
|
||||
# AccountMigration entity.
|
||||
#
|
||||
# It is possible that implementation of diaspora* protocol requires to compute the signature for the
|
||||
# AccountMigration entity without instantiating the entity. In this case this module may be useful.
|
||||
module Signable
|
||||
include Entities::Signable
|
||||
|
||||
# @return [String] string which is uniquely represents migration occasion
|
||||
def unique_migration_descriptor
|
||||
"AccountMigration:#{old_identity}:#{new_identity}"
|
||||
end
|
||||
|
||||
# @see DiasporaFederation::Entities::Signable#signature_data
|
||||
def signature_data
|
||||
unique_migration_descriptor
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -42,6 +42,7 @@ module DiasporaFederation
|
|||
Fabricator(:account_migration_entity, class_name: DiasporaFederation::Entities::AccountMigration) do
|
||||
author { Fabricate.sequence(:diaspora_id) }
|
||||
profile { Fabricate(:profile_entity) }
|
||||
old_identity { Fabricate.sequence(:diaspora_id) }
|
||||
end
|
||||
|
||||
Fabricator(:person_entity, class_name: DiasporaFederation::Entities::Person) do
|
||||
|
|
|
|||
|
|
@ -7,6 +7,8 @@ module DiasporaFederation
|
|||
rule :author, :diaspora_id
|
||||
|
||||
rule :profile, :not_nil
|
||||
|
||||
rule :old_identity, :diaspora_id
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -0,0 +1,39 @@
|
|||
module DiasporaFederation
|
||||
describe Entities::AccountMigration::Signable do
|
||||
let(:entity) { TestAMSignableEntity.new({}) }
|
||||
|
||||
class TestAMSignableEntity < Entity
|
||||
include Entities::AccountMigration::Signable
|
||||
|
||||
property :my_signature, :string, default: nil
|
||||
|
||||
def old_identity
|
||||
"old"
|
||||
end
|
||||
|
||||
def new_identity
|
||||
"new"
|
||||
end
|
||||
|
||||
def freeze; end
|
||||
end
|
||||
|
||||
it_behaves_like "a signable" do
|
||||
let(:test_class) { TestAMSignableEntity }
|
||||
let(:test_string) { "AccountMigration:old:new" }
|
||||
end
|
||||
|
||||
describe "#unique_migration_descriptor" do
|
||||
it "composes a string using #old_identity and #new_identity" do
|
||||
expect(entity.unique_migration_descriptor).to eq("AccountMigration:old:new")
|
||||
end
|
||||
end
|
||||
|
||||
describe "#signature_data" do
|
||||
it "delegates to #unique_migration_descriptor" do
|
||||
expect(entity).to receive(:unique_migration_descriptor).and_return("test123")
|
||||
expect(entity.signature_data).to eq("test123")
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -1,21 +1,185 @@
|
|||
module DiasporaFederation
|
||||
describe Entities::AccountMigration do
|
||||
let(:new_diaspora_id) { alice.diaspora_id }
|
||||
let(:new_author_pkey) { alice.private_key }
|
||||
let(:hash) {
|
||||
Fabricate.attributes_for(:account_deletion_entity).merge(
|
||||
profile: Fabricate(:profile_entity, author: new_diaspora_id)
|
||||
)
|
||||
}
|
||||
let(:old_user) { Fabricate(:user) }
|
||||
let(:new_user) { Fabricate(:user) }
|
||||
let(:old_diaspora_id) { old_user.diaspora_id }
|
||||
let(:new_diaspora_id) { new_user.diaspora_id }
|
||||
|
||||
let(:data) {
|
||||
hash.tap {|hash|
|
||||
properties = described_class.new(hash).send(:enriched_properties)
|
||||
hash[:signature] = properties[:signature]
|
||||
}
|
||||
}
|
||||
let(:signature_data) { "AccountMigration:#{hash[:author]}:#{new_diaspora_id}" }
|
||||
let(:signature_data) { "AccountMigration:#{old_diaspora_id}:#{new_diaspora_id}" }
|
||||
let(:string) { signature_data }
|
||||
|
||||
let(:xml) { <<-XML }
|
||||
shared_examples_for "an account migration entity" do
|
||||
it_behaves_like "an Entity subclass"
|
||||
|
||||
it_behaves_like "an XML Entity"
|
||||
|
||||
describe "#to_xml" do
|
||||
it "computes signature when no signature was provided" do
|
||||
expect_callback(:fetch_private_key, signer_id).and_return(signer_pkey)
|
||||
|
||||
entity = Entities::AccountMigration.new(hash)
|
||||
xml = entity.to_xml
|
||||
|
||||
signature = xml.at_xpath("signature").text
|
||||
expect(verify_signature(signer_pkey, signature, entity.to_s)).to be_truthy
|
||||
end
|
||||
|
||||
it "doesn't change signature if it is already set" do
|
||||
hash[:signature] = "aa"
|
||||
|
||||
xml = Entities::AccountMigration.new(hash).to_xml
|
||||
|
||||
expect(xml.at_xpath("signature").text).to eq("aa")
|
||||
end
|
||||
|
||||
it "raises when signature isn't set and key isn't supplied" do
|
||||
expect_callback(:fetch_private_key, signer_id).and_return(nil)
|
||||
|
||||
expect {
|
||||
Entities::AccountMigration.new(hash).to_xml
|
||||
}.to raise_error Entities::AccountMigration::PrivateKeyNotFound
|
||||
end
|
||||
end
|
||||
|
||||
describe "#verify_signature" do
|
||||
it "doesn't raise anything if correct signature was passed" do
|
||||
hash[:signature] = sign_with_key(signer_pkey, signature_data)
|
||||
expect_callback(:fetch_public_key, signer_id).and_return(signer_pkey)
|
||||
expect { Entities::AccountMigration.new(hash).verify_signature }.not_to raise_error
|
||||
end
|
||||
|
||||
it "raises when no public key for author was fetched" do
|
||||
expect_callback(:fetch_public_key, anything).and_return(nil)
|
||||
|
||||
expect {
|
||||
Entities::AccountMigration.new(hash).verify_signature
|
||||
}.to raise_error Entities::AccountMigration::PublicKeyNotFound
|
||||
end
|
||||
|
||||
it "raises when bad author signature was passed" do
|
||||
hash[:signature] = "abcdef"
|
||||
|
||||
expect_callback(:fetch_public_key, signer_id).and_return(signer_pkey.public_key)
|
||||
|
||||
expect {
|
||||
Entities::AccountMigration.new(hash).verify_signature
|
||||
}.to raise_error Entities::AccountMigration::SignatureVerificationFailed
|
||||
end
|
||||
end
|
||||
|
||||
describe ".from_hash" do
|
||||
it "calls #verify_signature" do
|
||||
expect_any_instance_of(Entities::AccountMigration).to receive(:freeze)
|
||||
expect_any_instance_of(Entities::AccountMigration).to receive(:verify_signature)
|
||||
Entities::AccountMigration.from_hash(hash)
|
||||
end
|
||||
|
||||
it "raises when bad author signature was passed" do
|
||||
hash[:signature] = "abcdef"
|
||||
|
||||
expect_callback(:fetch_public_key, signer_id).and_return(signer_pkey.public_key)
|
||||
|
||||
expect {
|
||||
Entities::AccountMigration.from_hash(hash)
|
||||
}.to raise_error Entities::AccountMigration::SignatureVerificationFailed
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context "with old identity as author" do
|
||||
let(:signer_id) { new_diaspora_id }
|
||||
let(:signer_pkey) { new_user.private_key }
|
||||
|
||||
let(:hash) {
|
||||
{
|
||||
author: old_diaspora_id,
|
||||
profile: Fabricate(:profile_entity, author: new_diaspora_id),
|
||||
old_identity: old_diaspora_id
|
||||
}
|
||||
}
|
||||
|
||||
let(:xml) { <<-XML }
|
||||
<account_migration>
|
||||
<author>#{data[:author]}</author>
|
||||
<profile>
|
||||
<author>#{data[:profile].author}</author>
|
||||
<first_name>#{data[:profile].first_name}</first_name>
|
||||
<image_url>#{data[:profile].image_url}</image_url>
|
||||
<image_url_medium>#{data[:profile].image_url}</image_url_medium>
|
||||
<image_url_small>#{data[:profile].image_url}</image_url_small>
|
||||
<bio>#{data[:profile].bio}</bio>
|
||||
<birthday>#{data[:profile].birthday}</birthday>
|
||||
<gender>#{data[:profile].gender}</gender>
|
||||
<location>#{data[:profile].location}</location>
|
||||
<searchable>#{data[:profile].searchable}</searchable>
|
||||
<public>#{data[:profile].public}</public>
|
||||
<nsfw>#{data[:profile].nsfw}</nsfw>
|
||||
<tag_string>#{data[:profile].tag_string}</tag_string>
|
||||
</profile>
|
||||
<signature>#{data[:signature]}</signature>
|
||||
<old_identity>#{data[:old_identity]}</old_identity>
|
||||
</account_migration>
|
||||
XML
|
||||
|
||||
it_behaves_like "an account migration entity"
|
||||
end
|
||||
|
||||
context "with new identity as author" do
|
||||
let(:signer_id) { old_diaspora_id }
|
||||
let(:signer_pkey) { old_user.private_key }
|
||||
|
||||
let(:hash) {
|
||||
{
|
||||
author: new_diaspora_id,
|
||||
profile: Fabricate(:profile_entity, author: new_diaspora_id),
|
||||
old_identity: old_diaspora_id
|
||||
}
|
||||
}
|
||||
|
||||
let(:xml) { <<-XML }
|
||||
<account_migration>
|
||||
<author>#{data[:author]}</author>
|
||||
<profile>
|
||||
<author>#{data[:profile].author}</author>
|
||||
<first_name>#{data[:profile].first_name}</first_name>
|
||||
<image_url>#{data[:profile].image_url}</image_url>
|
||||
<image_url_medium>#{data[:profile].image_url}</image_url_medium>
|
||||
<image_url_small>#{data[:profile].image_url}</image_url_small>
|
||||
<bio>#{data[:profile].bio}</bio>
|
||||
<birthday>#{data[:profile].birthday}</birthday>
|
||||
<gender>#{data[:profile].gender}</gender>
|
||||
<location>#{data[:profile].location}</location>
|
||||
<searchable>#{data[:profile].searchable}</searchable>
|
||||
<public>#{data[:profile].public}</public>
|
||||
<nsfw>#{data[:profile].nsfw}</nsfw>
|
||||
<tag_string>#{data[:profile].tag_string}</tag_string>
|
||||
</profile>
|
||||
<signature>#{data[:signature]}</signature>
|
||||
<old_identity>#{data[:old_identity]}</old_identity>
|
||||
</account_migration>
|
||||
XML
|
||||
|
||||
it_behaves_like "an account migration entity"
|
||||
end
|
||||
|
||||
context "when author is the new identity and old_identity prop is missing" do
|
||||
let(:signer_id) { old_diaspora_id }
|
||||
let(:signer_pkey) { old_user.private_key }
|
||||
|
||||
let(:hash) {
|
||||
{
|
||||
author: new_diaspora_id,
|
||||
profile: Fabricate(:profile_entity, author: new_diaspora_id)
|
||||
}
|
||||
}
|
||||
|
||||
let(:xml) { <<-XML }
|
||||
<account_migration>
|
||||
<author>#{data[:author]}</author>
|
||||
<profile>
|
||||
|
|
@ -37,81 +201,16 @@ module DiasporaFederation
|
|||
</account_migration>
|
||||
XML
|
||||
|
||||
let(:string) { "AccountMigration:#{data[:author]}:#{data[:profile].author}" }
|
||||
|
||||
it_behaves_like "an Entity subclass"
|
||||
|
||||
it_behaves_like "an XML Entity"
|
||||
|
||||
describe "#to_xml" do
|
||||
it "computes signature when no signature was provided" do
|
||||
expect_callback(:fetch_private_key, new_diaspora_id).and_return(new_author_pkey)
|
||||
|
||||
entity = Entities::AccountMigration.new(hash)
|
||||
xml = entity.to_xml
|
||||
|
||||
signature = xml.at_xpath("signature").text
|
||||
expect(verify_signature(new_author_pkey, signature, entity.to_s)).to be_truthy
|
||||
end
|
||||
|
||||
it "doesn't change signature if it is already set" do
|
||||
hash[:signature] = "aa"
|
||||
|
||||
xml = Entities::AccountMigration.new(hash).to_xml
|
||||
|
||||
expect(xml.at_xpath("signature").text).to eq("aa")
|
||||
end
|
||||
|
||||
it "raises when signature isn't set and key isn't supplied" do
|
||||
expect_callback(:fetch_private_key, new_diaspora_id).and_return(nil)
|
||||
|
||||
it "fails validation on construction" do
|
||||
expect {
|
||||
Entities::AccountMigration.new(hash).to_xml
|
||||
}.to raise_error Entities::AccountMigration::NewPrivateKeyNotFound
|
||||
end
|
||||
end
|
||||
|
||||
describe "#verify_signature" do
|
||||
it "doesn't raise anything if correct signatures were passed" do
|
||||
hash[:signature] = sign_with_key(new_author_pkey, signature_data)
|
||||
expect_callback(:fetch_public_key, new_diaspora_id).and_return(new_author_pkey)
|
||||
expect { Entities::AccountMigration.new(hash).verify_signature }.not_to raise_error
|
||||
described_class.new(hash)
|
||||
}.to raise_error Entity::ValidationError
|
||||
end
|
||||
|
||||
it "raises when no public key for author was fetched" do
|
||||
expect_callback(:fetch_public_key, anything).and_return(nil)
|
||||
|
||||
it "fails validation on parsing" do
|
||||
expect {
|
||||
Entities::AccountMigration.new(hash).verify_signature
|
||||
}.to raise_error Entities::AccountMigration::PublicKeyNotFound
|
||||
end
|
||||
|
||||
it "raises when bad author signature was passed" do
|
||||
hash[:signature] = "abcdef"
|
||||
|
||||
expect_callback(:fetch_public_key, new_diaspora_id).and_return(new_author_pkey.public_key)
|
||||
|
||||
expect {
|
||||
Entities::AccountMigration.new(hash).verify_signature
|
||||
}.to raise_error Entities::AccountMigration::SignatureVerificationFailed
|
||||
end
|
||||
end
|
||||
|
||||
describe ".from_hash" do
|
||||
it "calls #verify_signature" do
|
||||
expect_any_instance_of(Entities::AccountMigration).to receive(:freeze)
|
||||
expect_any_instance_of(Entities::AccountMigration).to receive(:verify_signature)
|
||||
Entities::AccountMigration.from_hash(hash)
|
||||
end
|
||||
|
||||
it "raises when bad author signature was passed" do
|
||||
hash[:signature] = "abcdef"
|
||||
|
||||
expect_callback(:fetch_public_key, new_diaspora_id).and_return(new_author_pkey.public_key)
|
||||
|
||||
expect {
|
||||
Entities::AccountMigration.from_hash(hash)
|
||||
}.to raise_error Entities::AccountMigration::SignatureVerificationFailed
|
||||
DiasporaFederation::Salmon::XmlPayload.unpack(Nokogiri::XML(xml).root)
|
||||
}.to raise_error Entity::ValidationError
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -1,9 +1,6 @@
|
|||
module DiasporaFederation
|
||||
describe Entities::Signable do
|
||||
TEST_STRING_VALUE = "abc123".freeze
|
||||
let(:private_key) { OpenSSL::PKey::RSA.generate(1024) }
|
||||
let(:test_string) { TEST_STRING_VALUE }
|
||||
let(:test_signature) { sign_with_key(private_key, test_string) }
|
||||
|
||||
class TestSignableEntity < Entity
|
||||
include Entities::Signable
|
||||
|
|
@ -27,51 +24,9 @@ module DiasporaFederation
|
|||
end
|
||||
end
|
||||
|
||||
describe "#sign_with_key" do
|
||||
it "produces a correct signature" do
|
||||
signature = TestSignableEntity.new({}).sign_with_key(private_key)
|
||||
expect(verify_signature(private_key.public_key, signature, test_string)).to be_truthy
|
||||
end
|
||||
end
|
||||
|
||||
describe "#verify_signature" do
|
||||
it "doesn't raise if signature is correct" do
|
||||
expect_callback(:fetch_public_key, "id@example.tld").and_return(private_key.public_key)
|
||||
|
||||
expect {
|
||||
TestSignableEntity
|
||||
.new(my_signature: test_signature)
|
||||
.verify_signature("id@example.tld", :my_signature)
|
||||
}.not_to raise_error
|
||||
end
|
||||
|
||||
it "raises PublicKeyNotFound when key isn't provided" do
|
||||
expect_callback(:fetch_public_key, "id@example.tld").and_return(nil)
|
||||
|
||||
expect {
|
||||
TestSignableEntity
|
||||
.new(my_signature: test_signature)
|
||||
.verify_signature("id@example.tld", :my_signature)
|
||||
}.to raise_error(Entities::Signable::PublicKeyNotFound)
|
||||
end
|
||||
|
||||
it "raises SignatureVerificationFailed when signature isn't provided" do
|
||||
expect_callback(:fetch_public_key, "id@example.tld").and_return(private_key.public_key)
|
||||
|
||||
expect {
|
||||
TestSignableEntity.new({}).verify_signature("id@example.tld", :my_signature)
|
||||
}.to raise_error(Entities::Signable::SignatureVerificationFailed)
|
||||
end
|
||||
|
||||
it "raises SignatureVerificationFailed when signature is wrong" do
|
||||
expect_callback(:fetch_public_key, "id@example.tld").and_return(private_key.public_key)
|
||||
|
||||
expect {
|
||||
TestSignableEntity
|
||||
.new(my_signature: "faked signature")
|
||||
.verify_signature("id@example.tld", :my_signature)
|
||||
}.to raise_error(Entities::Signable::SignatureVerificationFailed)
|
||||
end
|
||||
it_behaves_like "a signable" do
|
||||
let(:test_class) { TestSignableEntity }
|
||||
let(:test_string) { TEST_STRING_VALUE }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -8,12 +8,18 @@ module DiasporaFederation
|
|||
let(:property) { :author }
|
||||
end
|
||||
|
||||
describe "#person" do
|
||||
describe "#profile" do
|
||||
it_behaves_like "a property with a value validation/restriction" do
|
||||
let(:property) { :profile }
|
||||
let(:wrong_values) { [nil] }
|
||||
let(:correct_values) { [] }
|
||||
end
|
||||
end
|
||||
|
||||
describe "#old_identity" do
|
||||
it_behaves_like "a diaspora* ID validator" do
|
||||
let(:property) { :old_identity }
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
51
spec/support/shared_signable_spec.rb
Normal file
51
spec/support/shared_signable_spec.rb
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
shared_examples "a signable" do
|
||||
let(:private_key) { OpenSSL::PKey::RSA.generate(1024) }
|
||||
let(:test_signature) { sign_with_key(private_key, test_string) }
|
||||
|
||||
describe "#sign_with_key" do
|
||||
it "produces a correct signature" do
|
||||
signature = test_class.new({}).sign_with_key(private_key)
|
||||
expect(verify_signature(private_key.public_key, signature, test_string)).to be_truthy
|
||||
end
|
||||
end
|
||||
|
||||
describe "#verify_signature" do
|
||||
it "doesn't raise if signature is correct" do
|
||||
expect_callback(:fetch_public_key, "id@example.tld").and_return(private_key.public_key)
|
||||
|
||||
expect {
|
||||
test_class
|
||||
.new(my_signature: test_signature)
|
||||
.verify_signature("id@example.tld", :my_signature)
|
||||
}.not_to raise_error
|
||||
end
|
||||
|
||||
it "raises PublicKeyNotFound when key isn't provided" do
|
||||
expect_callback(:fetch_public_key, "id@example.tld").and_return(nil)
|
||||
|
||||
expect {
|
||||
test_class
|
||||
.new(my_signature: test_signature)
|
||||
.verify_signature("id@example.tld", :my_signature)
|
||||
}.to raise_error(DiasporaFederation::Entities::Signable::PublicKeyNotFound)
|
||||
end
|
||||
|
||||
it "raises SignatureVerificationFailed when signature isn't provided" do
|
||||
expect_callback(:fetch_public_key, "id@example.tld").and_return(private_key.public_key)
|
||||
|
||||
expect {
|
||||
test_class.new({}).verify_signature("id@example.tld", :my_signature)
|
||||
}.to raise_error(DiasporaFederation::Entities::Signable::SignatureVerificationFailed)
|
||||
end
|
||||
|
||||
it "raises SignatureVerificationFailed when signature is wrong" do
|
||||
expect_callback(:fetch_public_key, "id@example.tld").and_return(private_key.public_key)
|
||||
|
||||
expect {
|
||||
test_class
|
||||
.new(my_signature: "faked signature")
|
||||
.verify_signature("id@example.tld", :my_signature)
|
||||
}.to raise_error(DiasporaFederation::Entities::Signable::SignatureVerificationFailed)
|
||||
end
|
||||
end
|
||||
end
|
||||
Loading…
Reference in a new issue