diaspora_federation 0.0.8 → 0.0.9

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.
Files changed (59) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +3 -1
  3. data/lib/diaspora_federation.rb +66 -1
  4. data/lib/diaspora_federation/discovery/h_card.rb +2 -3
  5. data/lib/diaspora_federation/discovery/web_finger.rb +3 -6
  6. data/lib/diaspora_federation/entities.rb +18 -0
  7. data/lib/diaspora_federation/entities/account_deletion.rb +14 -0
  8. data/lib/diaspora_federation/entities/comment.rb +26 -0
  9. data/lib/diaspora_federation/entities/conversation.rb +38 -0
  10. data/lib/diaspora_federation/entities/like.rb +35 -0
  11. data/lib/diaspora_federation/entities/location.rb +23 -0
  12. data/lib/diaspora_federation/entities/message.rb +38 -0
  13. data/lib/diaspora_federation/entities/participation.rb +28 -0
  14. data/lib/diaspora_federation/entities/person.rb +6 -3
  15. data/lib/diaspora_federation/entities/photo.rb +59 -0
  16. data/lib/diaspora_federation/entities/poll.rb +24 -0
  17. data/lib/diaspora_federation/entities/poll_answer.rb +19 -0
  18. data/lib/diaspora_federation/entities/poll_participation.rb +28 -0
  19. data/lib/diaspora_federation/entities/profile.rb +10 -8
  20. data/lib/diaspora_federation/entities/relayable.rb +101 -0
  21. data/lib/diaspora_federation/entities/relayable_retraction.rb +95 -0
  22. data/lib/diaspora_federation/entities/request.rb +21 -0
  23. data/lib/diaspora_federation/entities/reshare.rb +49 -0
  24. data/lib/diaspora_federation/entities/retraction.rb +24 -0
  25. data/lib/diaspora_federation/entities/signed_retraction.rb +66 -0
  26. data/lib/diaspora_federation/entities/status_message.rb +55 -0
  27. data/lib/diaspora_federation/entity.rb +5 -6
  28. data/lib/diaspora_federation/fetcher.rb +1 -2
  29. data/lib/diaspora_federation/properties_dsl.rb +18 -8
  30. data/lib/diaspora_federation/salmon.rb +17 -0
  31. data/lib/diaspora_federation/salmon/aes.rb +58 -0
  32. data/lib/diaspora_federation/salmon/encrypted_slap.rb +187 -0
  33. data/lib/diaspora_federation/salmon/exceptions.rb +50 -0
  34. data/lib/diaspora_federation/salmon/magic_envelope.rb +191 -0
  35. data/lib/diaspora_federation/salmon/slap.rb +128 -0
  36. data/lib/diaspora_federation/salmon/xml_payload.rb +158 -0
  37. data/lib/diaspora_federation/signing.rb +56 -0
  38. data/lib/diaspora_federation/validators.rb +20 -0
  39. data/lib/diaspora_federation/validators/account_deletion_validator.rb +10 -0
  40. data/lib/diaspora_federation/validators/comment_validator.rb +17 -0
  41. data/lib/diaspora_federation/validators/conversation_validator.rb +14 -0
  42. data/lib/diaspora_federation/validators/like_validator.rb +14 -0
  43. data/lib/diaspora_federation/validators/location_validator.rb +11 -0
  44. data/lib/diaspora_federation/validators/message_validator.rb +16 -0
  45. data/lib/diaspora_federation/validators/participation_validator.rb +16 -0
  46. data/lib/diaspora_federation/validators/photo_validator.rb +24 -0
  47. data/lib/diaspora_federation/validators/poll_answer_validator.rb +11 -0
  48. data/lib/diaspora_federation/validators/poll_participation_validator.rb +16 -0
  49. data/lib/diaspora_federation/validators/poll_validator.rb +11 -0
  50. data/lib/diaspora_federation/validators/relayable_retraction_validator.rb +15 -0
  51. data/lib/diaspora_federation/validators/relayable_validator.rb +14 -0
  52. data/lib/diaspora_federation/validators/request_validator.rb +11 -0
  53. data/lib/diaspora_federation/validators/reshare_validator.rb +18 -0
  54. data/lib/diaspora_federation/validators/retraction_validator.rb +14 -0
  55. data/lib/diaspora_federation/validators/rules/diaspora_id_count.rb +37 -0
  56. data/lib/diaspora_federation/validators/signed_retraction_validator.rb +15 -0
  57. data/lib/diaspora_federation/validators/status_message_validator.rb +14 -0
  58. data/lib/diaspora_federation/version.rb +1 -1
  59. metadata +49 -4
@@ -0,0 +1,24 @@
1
+ module DiasporaFederation
2
+ module Entities
3
+ # this entity represents a poll ant it is federated as an optional part of a status message
4
+ #
5
+ # @see Validators::PollValidator
6
+ class Poll < Entity
7
+ # @!attribute [r] guid
8
+ # a random string of at least 16 chars.
9
+ # @see Validation::Rule::Guid
10
+ # @return [String] poll guid
11
+ property :guid
12
+
13
+ # @!attribute [r] question
14
+ # Text of the question posed by a user
15
+ # @return [String] question
16
+ property :question
17
+
18
+ # @!attribute [r] poll_answers
19
+ # array of possible answer to the poll
20
+ # @return [[Entities::PollAnswer]] poll answers
21
+ entity :poll_answers, [Entities::PollAnswer]
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,19 @@
1
+ module DiasporaFederation
2
+ module Entities
3
+ # this entity represents a poll answer and is federated as a part of the Poll entity
4
+ #
5
+ # @see Validators::PollAnswerValidator
6
+ class PollAnswer < Entity
7
+ # @!attribute [r] guid
8
+ # a random string of at least 16 chars.
9
+ # @see Validation::Rule::Guid
10
+ # @return [String] guid
11
+ property :guid
12
+
13
+ # @!attribute [r] answer
14
+ # Text of the answer
15
+ # @return [String] answer
16
+ property :answer
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,28 @@
1
+ module DiasporaFederation
2
+ module Entities
3
+ # this entity represents a participation in poll, i.e. it is issued when a user votes for an answer in a poll
4
+ #
5
+ # @see Validators::PollParticipationValidator
6
+ class PollParticipation < Entity
7
+ # @!attribute [r] guid
8
+ # a random string of at least 16 chars.
9
+ # @see Validation::Rule::Guid
10
+ # @return [String] guid
11
+ property :guid
12
+
13
+ include Relayable
14
+
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
+ # @!attribute [r] poll_answer_guid
22
+ # guid of the answer selected by the user.
23
+ # @see PollAnswer#guid
24
+ # @return [String] poll answer guid
25
+ property :poll_answer_guid
26
+ end
27
+ end
28
+ end
@@ -11,29 +11,31 @@ module DiasporaFederation
11
11
  property :diaspora_id, xml_name: :diaspora_handle
12
12
 
13
13
  # @!attribute [r] first_name
14
- # @deprecated
14
+ # @deprecated We decided to only use one name field, these should be removed
15
+ # in later iterations (will affect older Diaspora* installations).
15
16
  # @see #full_name
16
- # @see HCard#first_name
17
+ # @see Discovery::HCard#first_name
17
18
  # @return [String] first name
18
19
  property :first_name, default: nil
19
20
 
20
21
  # @!attribute [r] last_name
21
- # @deprecated
22
+ # @deprecated We decided to only use one name field, these should be removed
23
+ # in later iterations (will affect older Diaspora* installations).
22
24
  # @see #full_name
23
- # @see HCard#last_name
25
+ # @see Discovery::HCard#last_name
24
26
  # @return [String] last name
25
27
  property :last_name, default: nil
26
28
 
27
29
  # @!attribute [r] image_url
28
- # @see HCard#photo_large_url
30
+ # @see Discovery::HCard#photo_large_url
29
31
  # @return [String] url to the big avatar (300x300)
30
32
  property :image_url, default: nil
31
33
  # @!attribute [r] image_url_medium
32
- # @see HCard#photo_medium_url
34
+ # @see Discovery::HCard#photo_medium_url
33
35
  # @return [String] url to the medium avatar (100x100)
34
36
  property :image_url_medium, default: nil
35
37
  # @!attribute [r] image_url_small
36
- # @see HCard#photo_small_url
38
+ # @see Discovery::HCard#photo_small_url
37
39
  # @return [String] url to the small avatar (50x50)
38
40
  property :image_url_small, default: nil
39
41
 
@@ -43,7 +45,7 @@ module DiasporaFederation
43
45
  property :location, default: nil
44
46
 
45
47
  # @!attribute [r] searchable
46
- # @see HCard#searchable
48
+ # @see Discovery::HCard#searchable
47
49
  # @return [Boolean] searchable flag
48
50
  property :searchable, default: true
49
51
 
@@ -0,0 +1,101 @@
1
+ module DiasporaFederation
2
+ module Entities
3
+ # this is a module that defines common properties for relayable entities
4
+ # which include Like, Comment, Participation, Message, etc. Each relayable
5
+ # has a parent, identified by guid. Relayables also are signed and signing/verificating
6
+ # logic is embedded into Salmon XML processing code.
7
+ module Relayable
8
+ # on inclusion of this module the required properties for a relayable are added to the object that includes it
9
+ #
10
+ # @!attribute [r] parent_guid
11
+ # @see StatusMessage#guid
12
+ # @return [String] parent guid
13
+ #
14
+ # @!attribute [r] parent_author_signature
15
+ # Contains a signature of the entity using the private key of the author of a parent post
16
+ # This signature is required only when federation from upstream (parent) post author to
17
+ # downstream subscribers. This is the case when the parent author has to resend a relayable
18
+ # received from one of his subscribers to all others.
19
+ #
20
+ # @return [String] parent author signature
21
+ #
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
+ # @param [Entity] entity the entity in which it is included
29
+ def self.included(entity)
30
+ entity.class_eval do
31
+ property :parent_guid
32
+ property :parent_author_signature, default: nil
33
+ property :author_signature, default: nil
34
+ end
35
+ end
36
+
37
+ # Generates XML and updates signatures
38
+ # @see Entity#to_xml
39
+ # @return [Nokogiri::XML::Element] root element containing properties as child elements
40
+ def to_xml
41
+ entity_xml.tap do |xml|
42
+ hash = to_h
43
+ Relayable.update_signatures!(hash)
44
+
45
+ xml.at_xpath("author_signature").content = hash[:author_signature]
46
+ xml.at_xpath("parent_author_signature").content = hash[:parent_author_signature]
47
+ end
48
+ end
49
+
50
+ # Exception raised when verify_signatures fails to verify signatures (signatures are wrong)
51
+ class SignatureVerificationFailed < ArgumentError
52
+ end
53
+
54
+ # verifies the signatures (+author_signature+ and +parent_author_signature+ if needed)
55
+ # @param [Hash] data hash with data to verify
56
+ # @raise [SignatureVerificationFailed] if the signature is not valid or no public key is found
57
+ def self.verify_signatures(data)
58
+ pkey = DiasporaFederation.callbacks.trigger(:fetch_public_key_by_diaspora_id, data[:diaspora_id])
59
+ raise SignatureVerificationFailed, "failed to fetch public key for #{data[:diaspora_id]}" if pkey.nil?
60
+ raise SignatureVerificationFailed, "wrong author_signature" unless Signing.verify_signature(
61
+ data, data[:author_signature], pkey
62
+ )
63
+
64
+ author_is_local = DiasporaFederation.callbacks.trigger(:entity_author_is_local?, "Post", data[:parent_guid])
65
+ verify_parent_signature(data) unless author_is_local
66
+ end
67
+
68
+ # this happens only on downstream federation
69
+ # @param [Hash] data hash with data to verify
70
+ def self.verify_parent_signature(data)
71
+ pkey = DiasporaFederation.callbacks.trigger(:fetch_author_public_key_by_entity_guid, "Post", data[:parent_guid])
72
+ raise SignatureVerificationFailed,
73
+ "failed to fetch public key for author of #{data[:parent_guid]}" if pkey.nil?
74
+ raise SignatureVerificationFailed, "wrong parent_author_signature" unless Signing.verify_signature(
75
+ data, data[:parent_author_signature], pkey
76
+ )
77
+ end
78
+ private_class_method :verify_parent_signature
79
+
80
+ # Adds signatures to a given hash with the keys of the author and the parent
81
+ # if the signatures are not in the hash yet and if the keys are available.
82
+ #
83
+ # @param [Hash] data hash given for a signing
84
+ def self.update_signatures!(data)
85
+ if data[:author_signature].nil?
86
+ pkey = DiasporaFederation.callbacks.trigger(:fetch_private_key_by_diaspora_id, data[:diaspora_id])
87
+ data[:author_signature] = Signing.sign_with_key(data, pkey) unless pkey.nil?
88
+ end
89
+
90
+ if data[:parent_author_signature].nil?
91
+ pkey = DiasporaFederation.callbacks.trigger(
92
+ :fetch_author_private_key_by_entity_guid,
93
+ "Post",
94
+ data[:parent_guid]
95
+ )
96
+ data[:parent_author_signature] = Signing.sign_with_key(data, pkey) unless pkey.nil?
97
+ end
98
+ end
99
+ end
100
+ end
101
+ end
@@ -0,0 +1,95 @@
1
+ module DiasporaFederation
2
+ module Entities
3
+ # this entity represents a claim of deletion of a previously federated
4
+ # relayable entity ({Entities::Comment}, {Entities::Like})
5
+ #
6
+ # There are two cases of federation of the RelayableRetraction.
7
+ # Retraction from the dowstream object owner is when an author of the
8
+ # relayable (e.g. Comment) deletes it himself. In this case only target_author_signature
9
+ # is filled and retraction is sent to the commented post's author. Here
10
+ # he (upstream object owner) signes it with parent's author key and fills
11
+ # signature in parent_author_signature and sends it to other pods where
12
+ # other participating people present. This is the second case - retraction
13
+ # from the upstream object owner.
14
+ # Retraction from the upstream object owner can also be performed by the
15
+ # upstream object owner himself - he has a right to delete comments on his posts.
16
+ # In any case in the retraction by the upstream author target_author_signature
17
+ # is not checked, only parent_author_signature is checked.
18
+ #
19
+ # @see Validators::RelayableRetractionValidator
20
+ # @deprecated will be replaced with {Entities::Retraction}
21
+ class RelayableRetraction < Entity
22
+ # @!attribute [r] parent_author_signature
23
+ # Contains a signature of the entity using the private key of the author of a parent post
24
+ # This signature is mandatory only when federation from an upstream author to the subscribers.
25
+ # @see Relayable#parent_author_signature
26
+ # @return [String] parent author signature
27
+ property :parent_author_signature, default: nil
28
+
29
+ # @!attribute [r] target_guid
30
+ # guid of a relayable to be deleted
31
+ # @see Comment#guid
32
+ # @return [String] target guid
33
+ property :target_guid
34
+
35
+ # @!attribute [r] target_type
36
+ # a string describing a type of the target
37
+ # @see Retraction#target_type
38
+ # @return [String] target type
39
+ property :target_type
40
+
41
+ # @!attribute [r] diaspora_id
42
+ # The diaspora ID of the person who deletes a relayable
43
+ # @see Person#diaspora_id
44
+ # @return [String] diaspora ID
45
+ property :diaspora_id, xml_name: :sender_handle
46
+
47
+ # @!attribute [r] target_author_signature
48
+ # Contains a signature of the entity using the private key of the
49
+ # author of a federated relayable entity ({Entities::Comment}, {Entities::Like})
50
+ # This signature is mandatory only when federation from the subscriber to an upstream
51
+ # author is done.
52
+ # @see Relayable#author_signature
53
+ # @return [String] target author signature
54
+ property :target_author_signature, default: nil
55
+
56
+ # Generates XML and updates signatures
57
+ # @see Entity#to_xml
58
+ # @return [Nokogiri::XML::Element] root element containing properties as child elements
59
+ def to_xml
60
+ entity_xml.tap do |xml|
61
+ hash = to_h
62
+ RelayableRetraction.update_signatures!(hash)
63
+ xml.at_xpath("target_author_signature").content = hash[:target_author_signature]
64
+ xml.at_xpath("parent_author_signature").content = hash[:parent_author_signature]
65
+ end
66
+ end
67
+
68
+ # Adds signatures to a given hash with the keys of the author and the parent
69
+ # if the signatures are not in the hash yet and if the keys are available.
70
+ #
71
+ # @param [Hash] hash hash given for a signing
72
+ def self.update_signatures!(hash)
73
+ target_author = DiasporaFederation.callbacks.trigger(
74
+ :fetch_entity_author_id_by_guid,
75
+ hash[:target_type],
76
+ hash[:target_guid]
77
+ )
78
+ pkey = DiasporaFederation.callbacks.trigger(:fetch_private_key_by_diaspora_id, hash[:diaspora_id])
79
+
80
+ fill_required_signature(target_author, pkey, hash) unless pkey.nil?
81
+ end
82
+
83
+ def self.fill_required_signature(target_author, pkey, hash)
84
+ if target_author == hash[:diaspora_id] && hash[:target_author_signature].nil?
85
+ hash[:target_author_signature] =
86
+ Signing.sign_with_key(SignedRetraction.apply_signable_exceptions(hash), pkey)
87
+ elsif target_author != hash[:diaspora_id] && hash[:parent_author_signature].nil?
88
+ hash[:parent_author_signature] =
89
+ Signing.sign_with_key(SignedRetraction.apply_signable_exceptions(hash), pkey)
90
+ end
91
+ end
92
+ private_class_method :fill_required_signature
93
+ end
94
+ end
95
+ end
@@ -0,0 +1,21 @@
1
+ module DiasporaFederation
2
+ module Entities
3
+ # this entity represents a sharing request for a user. A user issues it
4
+ # when he starts sharing with another user.
5
+ #
6
+ # @see Validators::RequestValidator
7
+ class Request < Entity
8
+ # @!attribute [r] sender_id
9
+ # The diaspora ID of the person who shares his profile
10
+ # @see Person#diaspora_id
11
+ # @return [String] sender ID
12
+ property :sender_id, xml_name: :sender_handle
13
+
14
+ # @!attribute [r] recipient_id
15
+ # The diaspora ID of the person who will be shared with
16
+ # @see Person#diaspora_id
17
+ # @return [String] recipient ID
18
+ property :recipient_id, xml_name: :recipient_handle
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,49 @@
1
+ module DiasporaFederation
2
+ module Entities
3
+ # this entity represents the fact the a user reshared some other user's post
4
+ #
5
+ # @see Validators::ReshareValidator
6
+ class Reshare < Entity
7
+ # @!attribute [r] diaspora_id
8
+ # The diaspora ID of the person who posted the original post
9
+ # @see Person#diaspora_id
10
+ # @return [String] diaspora ID
11
+ property :root_diaspora_id # inconsistent, everywhere else it's "handle"
12
+
13
+ # @!attribute [r] root_guid
14
+ # guid of the original post
15
+ # @see StatusMessage#guid
16
+ # @return [String] root guid
17
+ property :root_guid
18
+
19
+ # @!attribute [r] guid
20
+ # a random string of at least 16 chars.
21
+ # @see Validation::Rule::Guid
22
+ # @see StatusMessage#guid
23
+ # @return [String] guid
24
+ property :guid
25
+
26
+ # @!attribute [r] diaspora_id
27
+ # The diaspora ID of the person who reshares a post
28
+ # @see Person#diaspora_id
29
+ # @return [String] diaspora ID
30
+ property :diaspora_id, xml_name: :diaspora_handle
31
+
32
+ # @!attribute [r] public
33
+ # has no meaning at the moment
34
+ # @return [Boolean] public
35
+ property :public, default: true # always true? (we only reshare public posts)
36
+
37
+ # @!attribute [r] created_at
38
+ # reshare entity creation time
39
+ # @return [Time] creation time
40
+ property :created_at, default: -> { Time.now.utc }
41
+
42
+ # @!attribute [r] provider_display_name
43
+ # a string that describes a means by which a user has posted the reshare
44
+ # @see StatusMessage#provider_display_name
45
+ # @return [String] provider display name
46
+ property :provider_display_name, default: nil
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,24 @@
1
+ module DiasporaFederation
2
+ module Entities
3
+ # this entity represents a claim of deletion of a previously federated entity
4
+ #
5
+ # @see Validators::RetractionValidator
6
+ class Retraction < Entity
7
+ # @!attribute [r] target_guid
8
+ # guid of the entity to be deleted
9
+ # @return [String] target guid
10
+ property :target_guid, xml_name: :post_guid
11
+
12
+ # @!attribute [r] diaspora_id
13
+ # The diaspora ID of the person who deletes the entity
14
+ # @see Person#diaspora_id
15
+ # @return [String] diaspora ID
16
+ property :diaspora_id, xml_name: :diaspora_handle
17
+
18
+ # @!attribute [r] target_type
19
+ # A string describing the type of the target.
20
+ # @return [String] target type
21
+ property :target_type, xml_name: :type
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,66 @@
1
+ module DiasporaFederation
2
+ module Entities
3
+ # this entity represents a claim of deletion of a previously federated
4
+ # entity of post type ({Entities::StatusMessage})
5
+ #
6
+ # @see Validators::SignedRetractionValidator
7
+ # @deprecated will be replaced with {Entities::Retraction}
8
+ class SignedRetraction < Entity
9
+ # @!attribute [r] target_guid
10
+ # guid of a post to be deleted
11
+ # @see Retraction#target_guid
12
+ # @return [String] target guid
13
+ property :target_guid
14
+
15
+ # @!attribute [r] target_type
16
+ # A string describing the type of the target.
17
+ # @see Retraction#target_type
18
+ # @return [String] target type
19
+ property :target_type
20
+
21
+ # @!attribute [r] diaspora_id
22
+ # The diaspora ID of the person who deletes a post
23
+ # @see Person#diaspora_id
24
+ # @return [String] diaspora ID
25
+ property :diaspora_id, xml_name: :sender_handle
26
+
27
+ # @!attribute [r] author_signature
28
+ # Contains a signature of the entity using the private key of the author of a post
29
+ # This signature is mandatory.
30
+ # @return [String] author signature
31
+ property :target_author_signature, default: nil
32
+
33
+ # Generates XML and updates signatures
34
+ # @see Entity#to_xml
35
+ # @return [Nokogiri::XML::Element] root element containing properties as child elements
36
+ def to_xml
37
+ entity_xml.tap do |xml|
38
+ hash = to_h
39
+ SignedRetraction.update_signatures!(hash)
40
+
41
+ xml.at_xpath("target_author_signature").content = hash[:target_author_signature]
42
+ end
43
+ end
44
+
45
+ # Adds signature to a given hash with the key of the author
46
+ # if the signature is not in the hash yet and if the key is available.
47
+ #
48
+ # @param [Hash] data hash given for a signing
49
+ def self.update_signatures!(data)
50
+ if data[:target_author_signature].nil?
51
+ pkey = DiasporaFederation.callbacks.trigger(:fetch_private_key_by_diaspora_id, data[:diaspora_id])
52
+ data[:target_author_signature] = Signing.sign_with_key(apply_signable_exceptions(data), pkey) unless pkey.nil?
53
+ end
54
+ end
55
+
56
+ # Deletes :diaspora_id (xml_name: sender_handle) from the hash in order to compute
57
+ # a signature since it is included from signable_string for SignedRetraction and RelayableRetraction
58
+ #
59
+ # @param [Hash] data hash of the retraction properties
60
+ # @return [Hash] hash copy without :diaspora_id member
61
+ def self.apply_signable_exceptions(data)
62
+ data.dup.tap {|data| data.delete(:diaspora_id) }
63
+ end
64
+ end
65
+ end
66
+ end