diaspora_federation 0.0.12 → 0.0.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/diaspora_federation.rb +103 -18
- data/lib/diaspora_federation/discovery/discovery.rb +1 -1
- data/lib/diaspora_federation/discovery/h_card.rb +4 -5
- data/lib/diaspora_federation/discovery/host_meta.rb +1 -1
- data/lib/diaspora_federation/discovery/web_finger.rb +8 -8
- data/lib/diaspora_federation/discovery/xrd_document.rb +6 -7
- data/lib/diaspora_federation/entities.rb +21 -10
- data/lib/diaspora_federation/entities/account_deletion.rb +7 -3
- data/lib/diaspora_federation/entities/comment.rb +13 -10
- data/lib/diaspora_federation/entities/contact.rb +29 -0
- data/lib/diaspora_federation/entities/conversation.rb +5 -6
- data/lib/diaspora_federation/entities/like.rb +10 -18
- data/lib/diaspora_federation/entities/message.rb +6 -12
- data/lib/diaspora_federation/entities/participation.rb +8 -16
- data/lib/diaspora_federation/entities/person.rb +6 -2
- data/lib/diaspora_federation/entities/photo.rb +3 -3
- data/lib/diaspora_federation/entities/poll_participation.rb +6 -12
- data/lib/diaspora_federation/entities/post.rb +37 -0
- data/lib/diaspora_federation/entities/profile.rb +7 -3
- data/lib/diaspora_federation/entities/relayable.rb +169 -65
- data/lib/diaspora_federation/entities/relayable_retraction.rb +33 -32
- data/lib/diaspora_federation/entities/request.rb +20 -6
- data/lib/diaspora_federation/entities/reshare.rb +5 -27
- data/lib/diaspora_federation/entities/retraction.rb +6 -6
- data/lib/diaspora_federation/entities/signed_retraction.rb +32 -26
- data/lib/diaspora_federation/entities/status_message.rb +2 -22
- data/lib/diaspora_federation/entity.rb +137 -38
- data/lib/diaspora_federation/federation.rb +9 -0
- data/lib/diaspora_federation/federation/fetcher.rb +26 -0
- data/lib/diaspora_federation/federation/receiver.rb +41 -0
- data/lib/diaspora_federation/federation/receiver/abstract_receiver.rb +35 -0
- data/lib/diaspora_federation/federation/receiver/exceptions.rb +13 -0
- data/lib/diaspora_federation/federation/receiver/private.rb +15 -0
- data/lib/diaspora_federation/federation/receiver/public.rb +9 -0
- data/lib/diaspora_federation/federation/sender.rb +33 -0
- data/lib/diaspora_federation/federation/sender/hydra_wrapper.rb +92 -0
- data/lib/diaspora_federation/{fetcher.rb → http_client.rb} +6 -6
- data/lib/diaspora_federation/properties_dsl.rb +51 -14
- data/lib/diaspora_federation/salmon.rb +2 -1
- data/lib/diaspora_federation/salmon/aes.rb +1 -1
- data/lib/diaspora_federation/salmon/encrypted_magic_envelope.rb +61 -0
- data/lib/diaspora_federation/salmon/encrypted_slap.rb +69 -50
- data/lib/diaspora_federation/salmon/exceptions.rb +8 -14
- data/lib/diaspora_federation/salmon/magic_envelope.rb +80 -39
- data/lib/diaspora_federation/salmon/slap.rb +20 -51
- data/lib/diaspora_federation/salmon/xml_payload.rb +5 -104
- data/lib/diaspora_federation/validators.rb +22 -16
- data/lib/diaspora_federation/validators/account_deletion_validator.rb +1 -1
- data/lib/diaspora_federation/validators/comment_validator.rb +0 -4
- data/lib/diaspora_federation/validators/contact_validator.rb +13 -0
- data/lib/diaspora_federation/validators/conversation_validator.rb +2 -2
- data/lib/diaspora_federation/validators/like_validator.rb +1 -3
- data/lib/diaspora_federation/validators/message_validator.rb +0 -4
- data/lib/diaspora_federation/validators/participation_validator.rb +1 -5
- data/lib/diaspora_federation/validators/person_validator.rb +1 -1
- data/lib/diaspora_federation/validators/photo_validator.rb +2 -2
- data/lib/diaspora_federation/validators/poll_participation_validator.rb +0 -4
- data/lib/diaspora_federation/validators/profile_validator.rb +1 -1
- data/lib/diaspora_federation/validators/relayable_retraction_validator.rb +1 -1
- data/lib/diaspora_federation/validators/relayable_validator.rb +2 -0
- data/lib/diaspora_federation/validators/request_validator.rb +3 -2
- data/lib/diaspora_federation/validators/reshare_validator.rb +3 -3
- data/lib/diaspora_federation/validators/retraction_validator.rb +2 -2
- data/lib/diaspora_federation/validators/rules/guid.rb +16 -7
- data/lib/diaspora_federation/validators/signed_retraction_validator.rb +1 -1
- data/lib/diaspora_federation/validators/status_message_validator.rb +2 -2
- data/lib/diaspora_federation/version.rb +1 -1
- metadata +20 -11
- data/lib/diaspora_federation/receiver.rb +0 -28
- data/lib/diaspora_federation/receiver/private.rb +0 -19
- data/lib/diaspora_federation/receiver/public.rb +0 -13
- data/lib/diaspora_federation/signing.rb +0 -56
@@ -0,0 +1,29 @@
|
|
1
|
+
module DiasporaFederation
|
2
|
+
module Entities
|
3
|
+
# this entity represents a contact with another person. A user issues it
|
4
|
+
# when he starts sharing/following with another user.
|
5
|
+
#
|
6
|
+
# @see Validators::ContactValidator
|
7
|
+
class Contact < Entity
|
8
|
+
# @!attribute [r] author
|
9
|
+
# The diaspora ID of the person who shares his profile
|
10
|
+
# @see Person#author
|
11
|
+
# @return [String] sender ID
|
12
|
+
property :author
|
13
|
+
|
14
|
+
# @!attribute [r] recipient
|
15
|
+
# The diaspora ID of the person who will be shared with
|
16
|
+
# @see Validation::Rule::DiasporaId
|
17
|
+
# @return [String] recipient ID
|
18
|
+
property :recipient
|
19
|
+
|
20
|
+
# @!attribute [r] following
|
21
|
+
# @return [Boolean] if the author is following the person
|
22
|
+
property :following, default: true
|
23
|
+
|
24
|
+
# @!attribute [r] sharing
|
25
|
+
# @return [Boolean] if the author is sharing with the person
|
26
|
+
property :sharing, default: true
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -22,17 +22,16 @@ module DiasporaFederation
|
|
22
22
|
# @return [[Entities::Message]] Messages of this conversation
|
23
23
|
entity :messages, [Entities::Message]
|
24
24
|
|
25
|
-
# @!attribute [r]
|
25
|
+
# @!attribute [r] author
|
26
26
|
# The diaspora ID of the person initiated the conversation.
|
27
|
-
# @see Person#
|
27
|
+
# @see Person#author
|
28
28
|
# @return [String] diaspora ID
|
29
|
-
property :
|
29
|
+
property :author, xml_name: :diaspora_handle
|
30
30
|
|
31
|
-
# @!attribute [r]
|
31
|
+
# @!attribute [r] participants
|
32
32
|
# The diaspora IDs of the persons participating the conversation separated by ";".
|
33
|
-
# @see Person#diaspora_id
|
34
33
|
# @return [String] participants diaspora IDs
|
35
|
-
property :
|
34
|
+
property :participants, xml_name: :participant_handles
|
36
35
|
end
|
37
36
|
end
|
38
37
|
end
|
@@ -4,32 +4,24 @@ module DiasporaFederation
|
|
4
4
|
#
|
5
5
|
# @see Validators::LikeValidator
|
6
6
|
class Like < Entity
|
7
|
+
# old signature order
|
8
|
+
# @deprecated
|
9
|
+
LEGACY_SIGNATURE_ORDER = %i(positive guid parent_type parent_guid author).freeze
|
10
|
+
|
11
|
+
include Relayable
|
12
|
+
|
7
13
|
# @!attribute [r] positive
|
8
14
|
# If +true+ set a like, if +false+, set a dislike (dislikes are currently not
|
9
15
|
# implemented in the Diaspora frontend).
|
10
16
|
# @return [Boolean] is it a like or a dislike
|
11
17
|
property :positive
|
12
18
|
|
13
|
-
# @!attribute [r]
|
14
|
-
#
|
15
|
-
# @see Validation::Rule::Guid
|
16
|
-
# @return [String] like guid
|
17
|
-
property :guid
|
18
|
-
|
19
|
-
# @!attribute [r] target_type
|
20
|
-
# A string describing the type of the target.
|
19
|
+
# @!attribute [r] parent_type
|
20
|
+
# A string describing the type of the parent.
|
21
21
|
# Can be "Post" or "Comment" (Comments are currently not implemented in the
|
22
22
|
# Diaspora Frontend).
|
23
|
-
# @return [String]
|
24
|
-
property :target_type
|
25
|
-
|
26
|
-
include Relayable
|
27
|
-
|
28
|
-
# @!attribute [r] diaspora_id
|
29
|
-
# The diaspora ID of the person who posts a like
|
30
|
-
# @see Person#diaspora_id
|
31
|
-
# @return [String] diaspora ID
|
32
|
-
property :diaspora_id, xml_name: :diaspora_handle
|
23
|
+
# @return [String] parent type
|
24
|
+
property :parent_type, xml_name: :target_type
|
33
25
|
end
|
34
26
|
end
|
35
27
|
end
|
@@ -4,11 +4,9 @@ module DiasporaFederation
|
|
4
4
|
#
|
5
5
|
# @see Validators::MessageValidator
|
6
6
|
class Message < Entity
|
7
|
-
#
|
8
|
-
#
|
9
|
-
|
10
|
-
# @return [String] message guid
|
11
|
-
property :guid
|
7
|
+
# old signature order
|
8
|
+
# @deprecated
|
9
|
+
LEGACY_SIGNATURE_ORDER = %i(guid parent_guid text created_at author conversation_guid).freeze
|
12
10
|
|
13
11
|
include Relayable
|
14
12
|
|
@@ -22,19 +20,15 @@ module DiasporaFederation
|
|
22
20
|
# @return [Time] creation time
|
23
21
|
property :created_at, default: -> { Time.now.utc }
|
24
22
|
|
25
|
-
# @!attribute [r] diaspora_id
|
26
|
-
# The diaspora ID of the message author.
|
27
|
-
# @see Person#diaspora_id
|
28
|
-
# @return [String] diaspora ID
|
29
|
-
property :diaspora_id, xml_name: :diaspora_handle
|
30
|
-
|
31
23
|
# @!attribute [r] conversation_guid
|
32
24
|
# guid of a conversation this message belongs to
|
33
25
|
# @see Conversation#guid
|
34
26
|
# @return [String] conversation guid
|
35
27
|
property :conversation_guid
|
36
28
|
|
37
|
-
|
29
|
+
# The {Message} parent is a {Conversation}
|
30
|
+
# @return [String] parent type
|
31
|
+
def parent_type
|
38
32
|
"Conversation"
|
39
33
|
end
|
40
34
|
end
|
@@ -4,25 +4,17 @@ module DiasporaFederation
|
|
4
4
|
#
|
5
5
|
# @see Validators::Participation
|
6
6
|
class Participation < Entity
|
7
|
-
#
|
8
|
-
#
|
9
|
-
|
10
|
-
# @return [String] participation guid
|
11
|
-
property :guid
|
12
|
-
|
13
|
-
# @!attribute [r] target_type
|
14
|
-
# a string describing a type of the target to subscribe on.
|
15
|
-
# currently only "Post" is supported.
|
16
|
-
# @return [String] target type
|
17
|
-
property :target_type
|
7
|
+
# old signature order
|
8
|
+
# @deprecated
|
9
|
+
LEGACY_SIGNATURE_ORDER = %i(guid parent_type parent_guid author).freeze
|
18
10
|
|
19
11
|
include Relayable
|
20
12
|
|
21
|
-
# @!attribute [r]
|
22
|
-
#
|
23
|
-
#
|
24
|
-
# @return [String]
|
25
|
-
property :
|
13
|
+
# @!attribute [r] parent_type
|
14
|
+
# a string describing a type of the target to subscribe on.
|
15
|
+
# currently only "Post" is supported.
|
16
|
+
# @return [String] parent type
|
17
|
+
property :parent_type, xml_name: :target_type
|
26
18
|
end
|
27
19
|
end
|
28
20
|
end
|
@@ -11,11 +11,15 @@ module DiasporaFederation
|
|
11
11
|
# @return [String] guid
|
12
12
|
property :guid
|
13
13
|
|
14
|
-
# @!attribute [r]
|
14
|
+
# @!attribute [r] author
|
15
15
|
# The diaspora ID of the person
|
16
16
|
# @see Validation::Rule::DiasporaId
|
17
17
|
# @return [String] diaspora ID
|
18
|
-
|
18
|
+
# @!attribute [r] diaspora_id
|
19
|
+
# Alias for author
|
20
|
+
# @see Person#author
|
21
|
+
# @return [String] diaspora ID
|
22
|
+
property :author, alias: :diaspora_id, xml_name: :diaspora_handle
|
19
23
|
|
20
24
|
# @!attribute [r] url
|
21
25
|
# @see Discovery::WebFinger#seed_url
|
@@ -10,11 +10,11 @@ module DiasporaFederation
|
|
10
10
|
# @return [String] guid
|
11
11
|
property :guid
|
12
12
|
|
13
|
-
# @!attribute [r]
|
13
|
+
# @!attribute [r] author
|
14
14
|
# The diaspora ID of the person who uploaded the photo
|
15
|
-
# @see Person#
|
15
|
+
# @see Person#author
|
16
16
|
# @return [String] author diaspora ID
|
17
|
-
property :
|
17
|
+
property :author, xml_name: :diaspora_handle
|
18
18
|
|
19
19
|
# @!attribute [r] public
|
20
20
|
# Points if the photo is visible to everyone or only to some aspects
|
@@ -4,27 +4,21 @@ module DiasporaFederation
|
|
4
4
|
#
|
5
5
|
# @see Validators::PollParticipationValidator
|
6
6
|
class PollParticipation < Entity
|
7
|
-
#
|
8
|
-
#
|
9
|
-
|
10
|
-
# @return [String] guid
|
11
|
-
property :guid
|
7
|
+
# old signature order
|
8
|
+
# @deprecated
|
9
|
+
LEGACY_SIGNATURE_ORDER = %i(guid parent_guid author poll_answer_guid).freeze
|
12
10
|
|
13
11
|
include Relayable
|
14
12
|
|
15
|
-
# @!attribute [r] diaspora_id
|
16
|
-
# The diaspora ID of the person who voted in the poll
|
17
|
-
# @see Person#diaspora_id
|
18
|
-
# @return [String] diaspora ID
|
19
|
-
property :diaspora_id, xml_name: :diaspora_handle
|
20
|
-
|
21
13
|
# @!attribute [r] poll_answer_guid
|
22
14
|
# guid of the answer selected by the user.
|
23
15
|
# @see PollAnswer#guid
|
24
16
|
# @return [String] poll answer guid
|
25
17
|
property :poll_answer_guid
|
26
18
|
|
27
|
-
|
19
|
+
# The {PollParticipation} parent is a {Poll}
|
20
|
+
# @return [String] parent type
|
21
|
+
def parent_type
|
28
22
|
"Poll"
|
29
23
|
end
|
30
24
|
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
module DiasporaFederation
|
2
|
+
module Entities
|
3
|
+
# this is a module that defines common properties for a post which
|
4
|
+
# include {StatusMessage} and {Reshare}.
|
5
|
+
module Post
|
6
|
+
# on inclusion of this module the required properties for a post are added to the object that includes it
|
7
|
+
#
|
8
|
+
# @!attribute [r] author
|
9
|
+
# The diaspora ID of the person who posts the post
|
10
|
+
# @see Person#author
|
11
|
+
# @return [String] diaspora ID
|
12
|
+
#
|
13
|
+
# @!attribute [r] guid
|
14
|
+
# a random string of at least 16 chars.
|
15
|
+
# @see Validation::Rule::Guid
|
16
|
+
# @return [String] status message guid
|
17
|
+
#
|
18
|
+
# @!attribute [r] created_at
|
19
|
+
# post entity creation time
|
20
|
+
# @return [Time] creation time
|
21
|
+
#
|
22
|
+
# @!attribute [r] provider_display_name
|
23
|
+
# a string that describes a means by which a user has posted the post
|
24
|
+
# @return [String] provider display name
|
25
|
+
#
|
26
|
+
# @param [Entity] entity the entity in which it is included
|
27
|
+
def self.included(entity)
|
28
|
+
entity.class_eval do
|
29
|
+
property :author, xml_name: :diaspora_handle
|
30
|
+
property :guid
|
31
|
+
property :created_at, default: -> { Time.now.utc }
|
32
|
+
property :provider_display_name, default: nil
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -4,11 +4,15 @@ module DiasporaFederation
|
|
4
4
|
#
|
5
5
|
# @see Validators::ProfileValidator
|
6
6
|
class Profile < Entity
|
7
|
-
# @!attribute [r]
|
7
|
+
# @!attribute [r] author
|
8
8
|
# The diaspora ID of the person
|
9
|
-
# @see Person#
|
9
|
+
# @see Person#author
|
10
|
+
# @return [String] diaspora ID
|
11
|
+
# @!attribute [r] diaspora_id
|
12
|
+
# Alias for author
|
13
|
+
# @see Profile#author
|
10
14
|
# @return [String] diaspora ID
|
11
|
-
property :diaspora_id, xml_name: :diaspora_handle
|
15
|
+
property :author, alias: :diaspora_id, xml_name: :diaspora_handle
|
12
16
|
|
13
17
|
# @!attribute [r] first_name
|
14
18
|
# @deprecated We decided to only use one name field, these should be removed
|
@@ -2,15 +2,44 @@ module DiasporaFederation
|
|
2
2
|
module Entities
|
3
3
|
# this is a module that defines common properties for relayable entities
|
4
4
|
# which include Like, Comment, Participation, Message, etc. Each relayable
|
5
|
-
# has a parent, identified by guid. Relayables also are signed and signing/
|
5
|
+
# has a parent, identified by guid. Relayables also are signed and signing/verification
|
6
6
|
# logic is embedded into Salmon XML processing code.
|
7
7
|
module Relayable
|
8
|
+
include Logging
|
9
|
+
|
10
|
+
# digest instance used for signing
|
11
|
+
DIGEST = OpenSSL::Digest::SHA256.new
|
12
|
+
|
13
|
+
# order from the parsed xml for signature
|
14
|
+
# @return [Array] order from xml
|
15
|
+
attr_reader :xml_order
|
16
|
+
|
17
|
+
# additional properties from parsed xml
|
18
|
+
# @return [Hash] additional xml elements
|
19
|
+
attr_reader :additional_xml_elements
|
20
|
+
|
8
21
|
# on inclusion of this module the required properties for a relayable are added to the object that includes it
|
9
22
|
#
|
23
|
+
# @!attribute [r] author
|
24
|
+
# The diaspora ID of the author.
|
25
|
+
# @see Person#author
|
26
|
+
# @return [String] diaspora ID
|
27
|
+
#
|
28
|
+
# @!attribute [r] guid
|
29
|
+
# a random string of at least 16 chars.
|
30
|
+
# @see Validation::Rule::Guid
|
31
|
+
# @return [String] comment guid
|
32
|
+
#
|
10
33
|
# @!attribute [r] parent_guid
|
11
34
|
# @see StatusMessage#guid
|
12
35
|
# @return [String] parent guid
|
13
36
|
#
|
37
|
+
# @!attribute [r] author_signature
|
38
|
+
# Contains a signature of the entity using the private key of the author of a post itself.
|
39
|
+
# The presence of this signature is mandatory. Without it the entity won't be accepted by
|
40
|
+
# a target pod.
|
41
|
+
# @return [String] author signature
|
42
|
+
#
|
14
43
|
# @!attribute [r] parent_author_signature
|
15
44
|
# Contains a signature of the entity using the private key of the author of a parent post
|
16
45
|
# This signature is required only when federation from upstream (parent) post author to
|
@@ -19,95 +48,170 @@ module DiasporaFederation
|
|
19
48
|
#
|
20
49
|
# @return [String] parent author signature
|
21
50
|
#
|
22
|
-
# @!attribute [r] author_signature
|
23
|
-
# Contains a signature of the entity using the private key of the author of a post itself.
|
24
|
-
# The presence of this signature is mandatory. Without it the entity won't be accepted by
|
25
|
-
# a target pod.
|
26
|
-
# @return [String] author signature
|
27
|
-
#
|
28
51
|
# @param [Entity] entity the entity in which it is included
|
29
52
|
def self.included(entity)
|
30
53
|
entity.class_eval do
|
54
|
+
property :author, xml_name: :diaspora_handle
|
55
|
+
property :guid
|
31
56
|
property :parent_guid
|
32
|
-
property :parent_author_signature, default: nil
|
33
57
|
property :author_signature, default: nil
|
34
|
-
|
35
|
-
def self.get_target_entity_type(data)
|
36
|
-
data[:target_type] || "Post"
|
37
|
-
end
|
58
|
+
property :parent_author_signature, default: nil
|
38
59
|
end
|
39
|
-
end
|
40
|
-
|
41
|
-
# Generates XML and updates signatures
|
42
|
-
# @see Entity#to_xml
|
43
|
-
# @return [Nokogiri::XML::Element] root element containing properties as child elements
|
44
|
-
def to_xml
|
45
|
-
entity_xml.tap do |xml|
|
46
|
-
hash = to_h
|
47
|
-
Relayable.update_signatures!(hash, self.class)
|
48
60
|
|
49
|
-
|
50
|
-
xml.at_xpath("parent_author_signature").content = hash[:parent_author_signature]
|
51
|
-
end
|
61
|
+
entity.extend ParseXML
|
52
62
|
end
|
53
63
|
|
54
|
-
#
|
55
|
-
|
64
|
+
# Initializes a new relayable Entity with order and additional xml elements
|
65
|
+
#
|
66
|
+
# @param [Hash] data entity data
|
67
|
+
# @param [Array] xml_order order from xml
|
68
|
+
# @param [Hash] additional_xml_elements additional xml elements
|
69
|
+
# @see DiasporaFederation::Entity#initialize
|
70
|
+
def initialize(data, xml_order=nil, additional_xml_elements={})
|
71
|
+
@xml_order = xml_order
|
72
|
+
@additional_xml_elements = additional_xml_elements
|
73
|
+
|
74
|
+
super(data)
|
56
75
|
end
|
57
76
|
|
58
77
|
# verifies the signatures (+author_signature+ and +parent_author_signature+ if needed)
|
59
|
-
# @param [Hash] data hash with data to verify
|
60
78
|
# @raise [SignatureVerificationFailed] if the signature is not valid or no public key is found
|
61
|
-
def
|
62
|
-
|
63
|
-
raise
|
64
|
-
raise SignatureVerificationFailed, "wrong author_signature" unless
|
65
|
-
data, data[:author_signature], pkey
|
66
|
-
)
|
79
|
+
def verify_signatures
|
80
|
+
pubkey = DiasporaFederation.callbacks.trigger(:fetch_public_key_by_diaspora_id, author)
|
81
|
+
raise PublicKeyNotFound, "author_signature author=#{author} guid=#{guid}" if pubkey.nil?
|
82
|
+
raise SignatureVerificationFailed, "wrong author_signature" unless verify_signature(pubkey, author_signature)
|
67
83
|
|
68
|
-
|
69
|
-
|
70
|
-
klass.get_target_entity_type(data),
|
71
|
-
data[:parent_guid]
|
72
|
-
)
|
73
|
-
verify_parent_signature(data, klass) unless author_is_local
|
84
|
+
parent_author_local = DiasporaFederation.callbacks.trigger(:entity_author_is_local?, parent_type, parent_guid)
|
85
|
+
verify_parent_author_signature unless parent_author_local
|
74
86
|
end
|
75
87
|
|
88
|
+
private
|
89
|
+
|
76
90
|
# this happens only on downstream federation
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
91
|
+
def verify_parent_author_signature
|
92
|
+
pubkey = DiasporaFederation.callbacks.trigger(:fetch_author_public_key_by_entity_guid, parent_type, parent_guid)
|
93
|
+
|
94
|
+
raise PublicKeyNotFound, "parent_author_signature parent_guid=#{parent_guid} guid=#{guid}" if pubkey.nil?
|
95
|
+
unless verify_signature(pubkey, parent_author_signature)
|
96
|
+
raise SignatureVerificationFailed, "wrong parent_author_signature parent_guid=#{parent_guid}"
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
# Check that signature is a correct signature
|
101
|
+
#
|
102
|
+
# @param [OpenSSL::PKey::RSA] pubkey An RSA key
|
103
|
+
# @param [String] signature The signature to be verified.
|
104
|
+
# @return [Boolean] signature valid
|
105
|
+
def verify_signature(pubkey, signature)
|
106
|
+
if signature.nil?
|
107
|
+
logger.warn "event=verify_signature status=abort reason=no_signature guid=#{guid}"
|
108
|
+
return false
|
109
|
+
end
|
110
|
+
|
111
|
+
pubkey.verify(DIGEST, Base64.decode64(signature), signature_data).tap do |valid|
|
112
|
+
logger.info "event=verify_signature status=complete guid=#{guid} valid=#{valid}"
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
# sign with author key
|
117
|
+
# @raise [AuthorPrivateKeyNotFound] if the author private key is not found
|
118
|
+
# @return [String] A Base64 encoded signature of #signature_data with key
|
119
|
+
def sign_with_author
|
120
|
+
privkey = DiasporaFederation.callbacks.trigger(:fetch_private_key_by_diaspora_id, author)
|
121
|
+
raise AuthorPrivateKeyNotFound, "author=#{author} guid=#{guid}" if privkey.nil?
|
122
|
+
sign_with_key(privkey).tap do
|
123
|
+
logger.info "event=sign status=complete signature=author_signature author=#{author} guid=#{guid}"
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
# sign with parent author key, if the parent author is local (if the private key is found)
|
128
|
+
# @return [String] A Base64 encoded signature of #signature_data with key
|
129
|
+
def sign_with_parent_author_if_available
|
130
|
+
privkey = DiasporaFederation.callbacks.trigger(
|
131
|
+
:fetch_author_private_key_by_entity_guid, parent_type, parent_guid
|
88
132
|
)
|
133
|
+
if privkey
|
134
|
+
sign_with_key(privkey).tap do
|
135
|
+
logger.info "event=sign status=complete signature=parent_author_signature guid=#{guid}"
|
136
|
+
end
|
137
|
+
end
|
89
138
|
end
|
90
|
-
private_class_method :verify_parent_signature
|
91
139
|
|
92
|
-
#
|
93
|
-
# if the signatures are not in the hash yet and if the keys are available.
|
140
|
+
# Sign the data with the key
|
94
141
|
#
|
95
|
-
# @param [
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
142
|
+
# @param [OpenSSL::PKey::RSA] privkey An RSA key
|
143
|
+
# @return [String] A Base64 encoded signature of #signature_data with key
|
144
|
+
def sign_with_key(privkey)
|
145
|
+
Base64.strict_encode64(privkey.sign(DIGEST, signature_data))
|
146
|
+
end
|
147
|
+
|
148
|
+
# Sort all XML elements according to the order used for the signatures.
|
149
|
+
# It updates also the signatures with the keys of the author and the parent
|
150
|
+
# if the signatures are not there yet and if the keys are available.
|
151
|
+
#
|
152
|
+
# @return [Hash] sorted xml elements with updated signatures
|
153
|
+
def xml_elements
|
154
|
+
xml_data = super.merge(additional_xml_elements)
|
155
|
+
Hash[signature_order.map {|element| [element, xml_data[element]] }].tap do |xml_elements|
|
156
|
+
xml_elements[:author_signature] = author_signature || sign_with_author
|
157
|
+
xml_elements[:parent_author_signature] = parent_author_signature || sign_with_parent_author_if_available.to_s
|
100
158
|
end
|
159
|
+
end
|
101
160
|
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
161
|
+
# the order for signing
|
162
|
+
# @return [Array]
|
163
|
+
def signature_order
|
164
|
+
xml_order.nil? ? self.class::LEGACY_SIGNATURE_ORDER : xml_order.reject {|name| name =~ /signature/ }
|
165
|
+
end
|
166
|
+
|
167
|
+
# @return [String] signature data string
|
168
|
+
def signature_data
|
169
|
+
data = to_h.merge(additional_xml_elements)
|
170
|
+
signature_order.map {|name| data[name] }.join(";")
|
171
|
+
end
|
172
|
+
|
173
|
+
# override class methods from {Entity} to parse the xml
|
174
|
+
module ParseXML
|
175
|
+
private
|
176
|
+
|
177
|
+
# @param [Nokogiri::XML::Element] root_node xml nodes
|
178
|
+
# @return [Entity] instance
|
179
|
+
def populate_entity(root_node)
|
180
|
+
# Use all known properties to build the Entity (entity_data). All additional xml elements
|
181
|
+
# are respected and attached to a hash as string (additional_xml_elements). It also remembers
|
182
|
+
# the order of the xml-nodes (xml_order). This is needed to support receiving objects from
|
183
|
+
# the future versions of Diaspora, where new elements may have been added.
|
184
|
+
entity_data = {}
|
185
|
+
additional_xml_elements = {}
|
186
|
+
|
187
|
+
xml_order = root_node.element_children.map do |child|
|
188
|
+
xml_name = child.name
|
189
|
+
property = find_property_for_xml_name(xml_name)
|
190
|
+
|
191
|
+
if property
|
192
|
+
entity_data[property] = parse_element_from_node(xml_name, class_props[property], root_node)
|
193
|
+
property
|
194
|
+
else
|
195
|
+
additional_xml_elements[xml_name] = child.text
|
196
|
+
xml_name
|
197
|
+
end
|
198
|
+
end
|
199
|
+
|
200
|
+
new(entity_data, xml_order, additional_xml_elements).tap(&:verify_signatures)
|
109
201
|
end
|
110
202
|
end
|
203
|
+
|
204
|
+
# Exception raised when creating the author_signature failes, because the private key was not found
|
205
|
+
class AuthorPrivateKeyNotFound < RuntimeError
|
206
|
+
end
|
207
|
+
|
208
|
+
# Exception raised when verify_signatures fails to verify signatures (no public key found)
|
209
|
+
class PublicKeyNotFound < RuntimeError
|
210
|
+
end
|
211
|
+
|
212
|
+
# Exception raised when verify_signatures fails to verify signatures (signatures are wrong)
|
213
|
+
class SignatureVerificationFailed < RuntimeError
|
214
|
+
end
|
111
215
|
end
|
112
216
|
end
|
113
217
|
end
|