diaspora_federation 0.1.9 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (71) hide show
  1. checksums.yaml +4 -4
  2. data/Changelog.md +34 -0
  3. data/lib/diaspora_federation/discovery/discovery.rb +2 -2
  4. data/lib/diaspora_federation/discovery/h_card.rb +2 -10
  5. data/lib/diaspora_federation/discovery/host_meta.rb +1 -1
  6. data/lib/diaspora_federation/discovery/web_finger.rb +47 -87
  7. data/lib/diaspora_federation/discovery/xrd_document.rb +20 -7
  8. data/lib/diaspora_federation/entities/account_migration.rb +74 -0
  9. data/lib/diaspora_federation/entities/comment.rb +0 -4
  10. data/lib/diaspora_federation/entities/event_participation.rb +0 -8
  11. data/lib/diaspora_federation/entities/like.rb +6 -10
  12. data/lib/diaspora_federation/entities/message.rb +14 -49
  13. data/lib/diaspora_federation/entities/participation.rb +23 -13
  14. data/lib/diaspora_federation/entities/poll_participation.rb +0 -4
  15. data/lib/diaspora_federation/entities/profile.rb +5 -0
  16. data/lib/diaspora_federation/entities/related_entity.rb +17 -0
  17. data/lib/diaspora_federation/entities/relayable.rb +82 -113
  18. data/lib/diaspora_federation/entities/relayable_retraction.rb +4 -43
  19. data/lib/diaspora_federation/entities/request.rb +4 -12
  20. data/lib/diaspora_federation/entities/reshare.rb +11 -7
  21. data/lib/diaspora_federation/entities/retraction.rb +4 -5
  22. data/lib/diaspora_federation/entities/signable.rb +54 -0
  23. data/lib/diaspora_federation/entities/signed_retraction.rb +4 -44
  24. data/lib/diaspora_federation/entities.rb +2 -0
  25. data/lib/diaspora_federation/entity.rb +74 -96
  26. data/lib/diaspora_federation/federation/fetcher.rb +1 -1
  27. data/lib/diaspora_federation/federation/receiver.rb +1 -1
  28. data/lib/diaspora_federation/federation/sender/hydra_wrapper.rb +37 -12
  29. data/lib/diaspora_federation/federation/sender.rb +2 -2
  30. data/lib/diaspora_federation/parsers/base_parser.rb +61 -0
  31. data/lib/diaspora_federation/parsers/json_parser.rb +60 -0
  32. data/lib/diaspora_federation/parsers/relayable_json_parser.rb +25 -0
  33. data/lib/diaspora_federation/parsers/relayable_xml_parser.rb +22 -0
  34. data/lib/diaspora_federation/parsers/xml_parser.rb +84 -0
  35. data/lib/diaspora_federation/parsers.rb +13 -0
  36. data/lib/diaspora_federation/properties_dsl.rb +1 -1
  37. data/lib/diaspora_federation/salmon/encrypted_magic_envelope.rb +1 -1
  38. data/lib/diaspora_federation/salmon/encrypted_slap.rb +2 -99
  39. data/lib/diaspora_federation/salmon/magic_envelope.rb +3 -19
  40. data/lib/diaspora_federation/salmon/slap.rb +1 -42
  41. data/lib/diaspora_federation/salmon/xml_payload.rb +0 -19
  42. data/lib/diaspora_federation/schemas/federation_entities.json +379 -0
  43. data/lib/diaspora_federation/validators/account_deletion_validator.rb +1 -1
  44. data/lib/diaspora_federation/validators/account_migration_validator.rb +12 -0
  45. data/lib/diaspora_federation/validators/contact_validator.rb +2 -2
  46. data/lib/diaspora_federation/validators/conversation_validator.rb +1 -1
  47. data/lib/diaspora_federation/validators/event_validator.rb +1 -1
  48. data/lib/diaspora_federation/validators/h_card_validator.rb +2 -5
  49. data/lib/diaspora_federation/validators/message_validator.rb +1 -1
  50. data/lib/diaspora_federation/validators/participation_validator.rb +1 -1
  51. data/lib/diaspora_federation/validators/person_validator.rb +2 -2
  52. data/lib/diaspora_federation/validators/photo_validator.rb +1 -1
  53. data/lib/diaspora_federation/validators/profile_validator.rb +1 -1
  54. data/lib/diaspora_federation/validators/related_entity_validator.rb +1 -1
  55. data/lib/diaspora_federation/validators/relayable_validator.rb +1 -1
  56. data/lib/diaspora_federation/validators/reshare_validator.rb +2 -2
  57. data/lib/diaspora_federation/validators/retraction_validator.rb +1 -1
  58. data/lib/diaspora_federation/validators/rules/boolean.rb +2 -2
  59. data/lib/diaspora_federation/validators/status_message_validator.rb +1 -1
  60. data/lib/diaspora_federation/validators/web_finger_validator.rb +5 -6
  61. data/lib/diaspora_federation/validators.rb +1 -5
  62. data/lib/diaspora_federation/version.rb +1 -1
  63. data/lib/diaspora_federation.rb +6 -2
  64. metadata +14 -11
  65. data/lib/diaspora_federation/validators/relayable_retraction_validator.rb +0 -15
  66. data/lib/diaspora_federation/validators/request_validator.rb +0 -12
  67. data/lib/diaspora_federation/validators/signed_retraction_validator.rb +0 -15
  68. data/lib/tasks/build.rake +0 -14
  69. data/lib/tasks/diaspora_federation_tasks.rake +0 -4
  70. data/lib/tasks/rails4.rake +0 -15
  71. data/lib/tasks/tests.rake +0 -18
@@ -48,32 +48,12 @@ module DiasporaFederation
48
48
  # Finally, before decrypting the magic envelope payload, the signature should
49
49
  # first be verified.
50
50
  #
51
- # @example Generating an encrypted Salmon Slap
52
- # author_id = "author@pod.example.tld"
53
- # author_privkey = however_you_retrieve_the_authors_private_key(author_id)
54
- # recipient_pubkey = however_you_retrieve_the_recipients_public_key()
55
- # entity = YourEntity.new(attr: "val")
56
- #
57
- # slap_xml = EncryptedSlap.prepare(author_id, author_privkey, entity).generate_xml(recipient_pubkey)
58
- #
59
51
  # @example Parsing a Salmon Slap
60
52
  # recipient_privkey = however_you_retrieve_the_recipients_private_key()
61
53
  # entity = EncryptedSlap.from_xml(slap_xml, recipient_privkey).payload
62
54
  #
63
55
  # @deprecated
64
56
  class EncryptedSlap < Slap
65
- # the author of the slap
66
- # @param [String] value the author diaspora* ID
67
- attr_writer :author_id
68
-
69
- # the key and iv if it is an encrypted slap
70
- # @param [Hash] value hash containing the key and iv
71
- attr_writer :cipher_params
72
-
73
- # the prepared encrypted magic envelope xml
74
- # @param [Nokogiri::XML::Element] value magic envelope xml
75
- attr_writer :magic_envelope_xml
76
-
77
57
  # Creates a {MagicEnvelope} instance from the data within the given XML string
78
58
  # containing an encrypted payload.
79
59
  #
@@ -87,7 +67,7 @@ module DiasporaFederation
87
67
  # @raise [MissingMagicEnvelope] if the +me:env+ element is missing in the XML
88
68
  def self.from_xml(slap_xml, privkey)
89
69
  raise ArgumentError unless slap_xml.instance_of?(String) && privkey.instance_of?(OpenSSL::PKey::RSA)
90
- doc = Nokogiri::XML::Document.parse(slap_xml)
70
+ doc = Nokogiri::XML(slap_xml)
91
71
 
92
72
  header_elem = doc.at_xpath("d:diaspora/d:encrypted_header", Slap::NS)
93
73
  raise MissingHeader if header_elem.nil?
@@ -98,44 +78,6 @@ module DiasporaFederation
98
78
  MagicEnvelope.unenvelop(magic_env_from_doc(doc), sender, cipher_params)
99
79
  end
100
80
 
101
- # Creates an encrypted Salmon Slap.
102
- #
103
- # @param [String] author_id diaspora* ID of the author
104
- # @param [OpenSSL::PKey::RSA] privkey sender private key for signing the magic envelope
105
- # @param [Entity] entity payload
106
- # @return [EncryptedSlap] encrypted Slap instance
107
- # @raise [ArgumentError] if any of the arguments is of the wrong type
108
- def self.prepare(author_id, privkey, entity)
109
- raise ArgumentError unless author_id.instance_of?(String) &&
110
- privkey.instance_of?(OpenSSL::PKey::RSA) &&
111
- entity.is_a?(Entity)
112
-
113
- EncryptedSlap.new.tap do |slap|
114
- slap.author_id = author_id
115
-
116
- magic_envelope = MagicEnvelope.new(entity)
117
- slap.cipher_params = magic_envelope.encrypt!
118
- slap.magic_envelope_xml = magic_envelope.envelop(privkey)
119
- end
120
- end
121
-
122
- # Creates an encrypted Salmon Slap XML string.
123
- #
124
- # @param [OpenSSL::PKey::RSA] pubkey recipient public key for encrypting the AES key
125
- # @return [String] Salmon XML string
126
- # @raise [ArgumentError] if any of the arguments is of the wrong type
127
- def generate_xml(pubkey)
128
- raise ArgumentError unless pubkey.instance_of?(OpenSSL::PKey::RSA)
129
-
130
- Slap.build_xml do |xml|
131
- xml.encrypted_header(encrypted_header(@author_id, @cipher_params, pubkey))
132
-
133
- xml.parent << @magic_envelope_xml
134
- end
135
- end
136
-
137
- private
138
-
139
81
  # Decrypts and reads the data from the encrypted XML header
140
82
  # @param [String] data base64 encoded, encrypted header data
141
83
  # @param [OpenSSL::PKey::RSA] privkey private key for decryption
@@ -160,46 +102,7 @@ module DiasporaFederation
160
102
  key = JSON.parse(privkey.private_decrypt(Base64.decode64(cipher_header["aes_key"])))
161
103
 
162
104
  xml = AES.decrypt(cipher_header["ciphertext"], Base64.decode64(key["key"]), Base64.decode64(key["iv"]))
163
- Nokogiri::XML::Document.parse(xml).root
164
- end
165
-
166
- # Encrypt the header xml with an AES cipher and encrypt the cipher params
167
- # with the recipients public_key.
168
- # @param [String] author_id diaspora_handle
169
- # @param [Hash] envelope_key envelope cipher params
170
- # @param [OpenSSL::PKey::RSA] pubkey recipient public_key
171
- # @return [String] encrypted base64 encoded header
172
- def encrypted_header(author_id, envelope_key, pubkey)
173
- data = header_xml(author_id, strict_base64_encode(envelope_key))
174
- header_key = AES.generate_key_and_iv
175
- ciphertext = AES.encrypt(data, header_key[:key], header_key[:iv])
176
-
177
- json_key = JSON.generate(strict_base64_encode(header_key))
178
- encrypted_key = Base64.strict_encode64(pubkey.public_encrypt(json_key))
179
-
180
- json_header = JSON.generate(aes_key: encrypted_key, ciphertext: ciphertext)
181
-
182
- Base64.strict_encode64(json_header)
183
- end
184
-
185
- # Generate the header xml string, including the author, aes_key and iv
186
- # @param [String] author_id diaspora_handle of the author
187
- # @param [Hash] envelope_key { key: "...", iv: "..." } (values in base64)
188
- # @return [String] header XML string
189
- def header_xml(author_id, envelope_key)
190
- @header_xml ||= Nokogiri::XML::Builder.new(encoding: "UTF-8") {|xml|
191
- xml.decrypted_header {
192
- xml.iv(envelope_key[:iv])
193
- xml.aes_key(envelope_key[:key])
194
- xml.author_id(author_id)
195
- }
196
- }.to_xml.strip
197
- end
198
-
199
- # @param [Hash] hash { key: "...", iv: "..." }
200
- # @return [Hash] encoded hash: { key: "...", iv: "..." }
201
- def strict_base64_encode(hash)
202
- hash.map {|k, v| [k, Base64.strict_encode64(v)] }.to_h
105
+ Nokogiri::XML(xml).root
203
106
  end
204
107
  end
205
108
  end
@@ -76,22 +76,6 @@ module DiasporaFederation
76
76
  }
77
77
  end
78
78
 
79
- # Encrypts the payload with a new, random AES cipher and returns the cipher
80
- # params that were used.
81
- #
82
- # This must happen after the MagicEnvelope instance was created and before
83
- # {MagicEnvelope#envelop} is called.
84
- #
85
- # @see AES#generate_key_and_iv
86
- # @see AES#encrypt
87
- #
88
- # @return [Hash] AES key and iv. E.g.: { key: "...", iv: "..." }
89
- def encrypt!
90
- AES.generate_key_and_iv.tap do |key|
91
- @payload_data = AES.encrypt(payload_data, key[:key], key[:iv])
92
- end
93
- end
94
-
95
79
  # Extracts the entity encoded in the magic envelope data, if the signature
96
80
  # is valid. If +cipher_params+ is given, also attempts to decrypt the payload first.
97
81
  #
@@ -128,7 +112,7 @@ module DiasporaFederation
128
112
 
129
113
  logger.debug "unenvelop message from #{sender}:\n#{data}"
130
114
 
131
- new(XmlPayload.unpack(Nokogiri::XML::Document.parse(data).root), sender)
115
+ new(XmlPayload.unpack(Nokogiri::XML(data).root), sender)
132
116
  end
133
117
 
134
118
  private
@@ -136,7 +120,7 @@ module DiasporaFederation
136
120
  # The payload data as string
137
121
  # @return [String] payload data
138
122
  def payload_data
139
- @payload_data ||= XmlPayload.pack(@payload).to_xml.strip.tap do |data|
123
+ @payload_data ||= payload.to_xml.to_xml.strip.tap do |data|
140
124
  logger.debug "send payload:\n#{data}"
141
125
  end
142
126
  end
@@ -153,7 +137,7 @@ module DiasporaFederation
153
137
  def build_xml
154
138
  Nokogiri::XML::Builder.new(encoding: "UTF-8") {|xml|
155
139
  yield xml
156
- }.doc.root
140
+ }.doc
157
141
  end
158
142
 
159
143
  # Creates the signature for all fields according to specification
@@ -13,13 +13,6 @@ module DiasporaFederation
13
13
  # {magic_envelope}
14
14
  # </diaspora>
15
15
  #
16
- # @example Generating a Salmon Slap
17
- # author_id = "author@pod.example.tld"
18
- # author_privkey = however_you_retrieve_the_authors_private_key(author_id)
19
- # entity = YourEntity.new(attr: "val")
20
- #
21
- # slap_xml = Slap.generate_xml(author_id, author_privkey, entity)
22
- #
23
16
  # @example Parsing a Salmon Slap
24
17
  # entity = Slap.from_xml(slap_xml).payload
25
18
  #
@@ -40,7 +33,7 @@ module DiasporaFederation
40
33
  # @raise [MissingMagicEnvelope] if the +me:env+ element is missing from the XML
41
34
  def self.from_xml(slap_xml)
42
35
  raise ArgumentError unless slap_xml.instance_of?(String)
43
- doc = Nokogiri::XML::Document.parse(slap_xml)
36
+ doc = Nokogiri::XML(slap_xml)
44
37
 
45
38
  author_elem = doc.at_xpath("d:diaspora/d:header/d:author_id", Slap::NS)
46
39
  raise MissingAuthor if author_elem.nil? || author_elem.content.empty?
@@ -49,40 +42,6 @@ module DiasporaFederation
49
42
  MagicEnvelope.unenvelop(magic_env_from_doc(doc), sender)
50
43
  end
51
44
 
52
- # Creates an unencrypted Salmon Slap and returns the XML string.
53
- #
54
- # @param [String] author_id diaspora* ID of the author
55
- # @param [OpenSSL::PKey::RSA] privkey sender private_key for signing the magic envelope
56
- # @param [Entity] entity payload
57
- # @return [String] Salmon XML string
58
- # @raise [ArgumentError] if any of the arguments is not the correct type
59
- def self.generate_xml(author_id, privkey, entity)
60
- raise ArgumentError unless author_id.instance_of?(String) &&
61
- privkey.instance_of?(OpenSSL::PKey::RSA) &&
62
- entity.is_a?(Entity)
63
-
64
- build_xml do |xml|
65
- xml.header {
66
- xml.author_id(author_id)
67
- }
68
-
69
- xml.parent << MagicEnvelope.new(entity, author_id).envelop(privkey)
70
- end
71
- end
72
-
73
- # Builds the xml for the Salmon Slap.
74
- #
75
- # @yield [xml] Invokes the block with the
76
- # {http://www.rubydoc.info/gems/nokogiri/Nokogiri/XML/Builder Nokogiri::XML::Builder}
77
- # @return [String] Slap XML
78
- def self.build_xml
79
- Nokogiri::XML::Builder.new(encoding: "UTF-8") {|xml|
80
- xml.diaspora("xmlns" => Salmon::XMLNS, "xmlns:me" => MagicEnvelope::XMLNS) {
81
- yield xml
82
- }
83
- }.to_xml
84
- end
85
-
86
45
  # Parses the magic envelop from the document.
87
46
  #
88
47
  # @param [Nokogiri::XML::Document] doc Salmon XML Document
@@ -13,25 +13,6 @@ module DiasporaFederation
13
13
  # (The +post+ element is there for historic reasons...)
14
14
  # @deprecated
15
15
  module XmlPayload
16
- # Encapsulates an Entity inside the wrapping xml structure
17
- # and returns the XML Object.
18
- #
19
- # @param [Entity] entity subject
20
- # @return [Nokogiri::XML::Element] XML root node
21
- # @raise [ArgumentError] if the argument is not an Entity subclass
22
- def self.pack(entity)
23
- raise ArgumentError, "only instances of DiasporaFederation::Entity allowed" unless entity.is_a?(Entity)
24
-
25
- entity_xml = entity.to_xml
26
- doc = entity_xml.document
27
- wrap = Nokogiri::XML::Element.new("XML", doc)
28
- wrap_post = Nokogiri::XML::Element.new("post", doc)
29
- entity_xml.parent = wrap_post
30
- wrap << wrap_post
31
-
32
- wrap
33
- end
34
-
35
16
  # Extracts the Entity XML from the wrapping XML structure, parses the entity
36
17
  # XML and returns a new instance of the Entity that was packed inside the
37
18
  # given payload.
@@ -0,0 +1,379 @@
1
+ {
2
+ "$schema": "http://json-schema.org/draft-04/schema#",
3
+ "id": "https://diaspora.github.io/diaspora_federation/schemas/federation_entities.json",
4
+ "oneOf": [
5
+ {"$ref": "#/definitions/comment"},
6
+ {"$ref": "#/definitions/like"},
7
+ {"$ref": "#/definitions/participation"},
8
+ {"$ref": "#/definitions/poll_participation"},
9
+ {"$ref": "#/definitions/status_message"},
10
+ {"$ref": "#/definitions/reshare"},
11
+ {"$ref": "#/definitions/profile"},
12
+ {"$ref": "#/definitions/location"},
13
+ {"$ref": "#/definitions/photo"},
14
+ {"$ref": "#/definitions/poll"},
15
+ {"$ref": "#/definitions/poll_answer"}
16
+ ],
17
+
18
+ "definitions": {
19
+ "signature": {
20
+ "oneOf" : [
21
+ {
22
+ "type": "string",
23
+ "minLength": 30
24
+ },
25
+ {
26
+ "type": "string",
27
+ "maxLength": 0,
28
+ "description": "Allow empty string when no signature is provided"
29
+ }
30
+ ]
31
+ },
32
+
33
+ "guid": {
34
+ "type": "string",
35
+ "minLength": 16,
36
+ "maxLength": 255
37
+ },
38
+
39
+ "relayable": {
40
+ "type": "object",
41
+ "description": "please don't use this object unless you're defining a new child relayable schema",
42
+ "properties": {
43
+ "entity_data": {
44
+ "type": "object",
45
+ "properties": {
46
+ "author": { "type": "string" },
47
+ "guid": { "$ref": "#/definitions/guid" },
48
+ "parent_guid": { "$ref": "#/definitions/guid" },
49
+ "author_signature": { "$ref": "#/definitions/signature" }
50
+ },
51
+ "required": [
52
+ "author", "guid", "parent_guid"
53
+ ]
54
+ },
55
+ "property_order": {
56
+ "type": "array",
57
+ "items": { "type": "string" }
58
+ }
59
+ },
60
+ "required": [
61
+ "entity_data", "entity_type", "property_order"
62
+ ]
63
+ },
64
+
65
+ "comment": {
66
+ "allOf": [
67
+ {"$ref": "#/definitions/relayable"},
68
+ {
69
+ "type": "object",
70
+ "properties": {
71
+ "entity_data": {
72
+ "type": "object",
73
+ "properties": {
74
+ "text": { "type": "string" },
75
+ "created_at": { "type": "string" }
76
+ },
77
+ "required": ["text"]
78
+ },
79
+ "entity_type": {
80
+ "type": "string",
81
+ "pattern": "^comment$"
82
+ }
83
+ }
84
+ }
85
+ ]
86
+ },
87
+
88
+ "like": {
89
+ "allOf": [
90
+ {"$ref": "#/definitions/relayable"},
91
+ {
92
+ "type": "object",
93
+ "properties": {
94
+ "entity_type": {
95
+ "type": "string",
96
+ "pattern": "^like$"
97
+ },
98
+ "entity_data": {
99
+ "type": "object",
100
+ "properties": {
101
+ "positive": { "type": "boolean" },
102
+ "parent_type": { "enum": ["Post", "Comment"] }
103
+ },
104
+ "required": ["positive"]
105
+ }
106
+ }
107
+ }
108
+ ]
109
+ },
110
+
111
+ "participation": {
112
+ "type": "object",
113
+ "properties": {
114
+ "entity_type": {
115
+ "type": "string",
116
+ "pattern": "^participation$"
117
+ },
118
+ "entity_data": {
119
+ "type": "object",
120
+ "properties": {
121
+ "author": { "type": "string" },
122
+ "guid": { "$ref": "#/definitions/guid" },
123
+ "parent_guid": { "$ref": "#/definitions/guid" },
124
+ "parent_type": {"enum": ["Post"]}
125
+ }
126
+ }
127
+ }
128
+ },
129
+
130
+ "poll_participation": {
131
+ "allOf": [
132
+ {"$ref": "#/definitions/relayable"},
133
+ {
134
+ "type": "object",
135
+ "properties": {
136
+ "entity_type": {
137
+ "type": "string",
138
+ "pattern": "^poll_participation$"
139
+ },
140
+ "entity_data": {
141
+ "type": "object",
142
+ "properties": {
143
+ "poll_answer_guid": { "$ref": "#/definitions/guid" }
144
+ },
145
+ "required": ["poll_answer_guid"]
146
+ }
147
+ }
148
+ }
149
+ ]
150
+ },
151
+
152
+ "post": {
153
+ "type": "object",
154
+ "description": "please don't use this object unless you're defining a new child post schema",
155
+ "properties": {
156
+ "entity_data": {
157
+ "type": "object",
158
+ "properties": {
159
+ "guid": { "$ref": "#/definitions/guid" },
160
+ "public": { "type": "boolean" },
161
+ "created_at": { "type": "string" },
162
+ "provider_display_name" : { "type": "string" }
163
+ },
164
+ "required": [
165
+ "guid", "public", "created_at"
166
+ ]
167
+ },
168
+ "required": [
169
+ "entity_type", "entity_data"
170
+ ]
171
+ }
172
+ },
173
+
174
+ "status_message": {
175
+ "allOf": [
176
+ {"$ref": "#/definitions/post"},
177
+ {
178
+ "type": "object",
179
+ "properties": {
180
+ "entity_type": {
181
+ "type": "string",
182
+ "pattern": "^status_message$"
183
+ },
184
+
185
+ "entity_data": {
186
+ "type": "object",
187
+ "properties": {
188
+ "text": { "type": "string" },
189
+
190
+ "location": {
191
+ "oneOf": [
192
+ { "$ref": "#/definitions/location" },
193
+ { "type": "null" }
194
+ ]
195
+ },
196
+
197
+ "poll": {
198
+ "oneOf": [
199
+ { "$ref": "#/definitions/poll" },
200
+ { "type": "null" }
201
+ ]
202
+ },
203
+
204
+ "photos": {
205
+ "type": ["array", "null"],
206
+ "items": { "$ref": "#/definitions/photo" }
207
+ }
208
+ },
209
+
210
+ "required": ["text"]
211
+ }
212
+ }
213
+ }
214
+ ]
215
+ },
216
+
217
+ "reshare": {
218
+ "allOf": [
219
+ {"$ref": "#/definitions/post"},
220
+ {
221
+ "type": "object",
222
+ "properties": {
223
+ "entity_type": {
224
+ "type": "string",
225
+ "pattern": "^reshare$"
226
+ },
227
+
228
+ "entity_data": {
229
+ "type": "object",
230
+ "properties": {
231
+ "root_author": {"type": "string"},
232
+ "root_guid": {"$ref": "#/definitions/guid"}
233
+ },
234
+
235
+ "required": ["root_author", "root_guid"]
236
+ }
237
+ }
238
+ }
239
+ ]
240
+ },
241
+
242
+ "profile": {
243
+ "type": "object",
244
+ "properties": {
245
+ "entity_type": {
246
+ "type": "string",
247
+ "pattern": "^profile$"
248
+ },
249
+ "entity_data": {
250
+ "type": "object",
251
+ "properties": {
252
+ "first_name": { "type": ["string", "null"] },
253
+ "last_name": { "type": ["string", "null"] },
254
+ "gender": { "type": ["string", "null"] },
255
+ "bio": { "type": ["string", "null"] },
256
+ "birthday": { "type": ["string", "null"] },
257
+ "location": { "type": ["string", "null"] },
258
+ "image_url": { "type": ["string", "null"] },
259
+ "author": { "type": "string" }
260
+ },
261
+ "required": [
262
+ "author"
263
+ ]
264
+ }
265
+ },
266
+ "required" :["entity_data", "entity_type"]
267
+ },
268
+
269
+ "photo": {
270
+ "type": "object",
271
+ "properties": {
272
+ "entity_type": {
273
+ "type": "string",
274
+ "pattern": "^photo$"
275
+ },
276
+ "entity_data": {
277
+ "type": "object",
278
+ "properties": {
279
+ "author": { "type": "string" },
280
+ "guid": {"$ref": "#/definitions/guid"},
281
+ "public": {"type": "boolean"},
282
+ "created_at": {"type": "string"},
283
+ "remote_photo_path": {"type": "string"},
284
+ "remote_photo_name": {"type": "string"},
285
+ "text": {"type": ["null", "string"]},
286
+ "status_message_guid": {"$ref": "#/definitions/guid"},
287
+ "width": {"type": "number"},
288
+ "height": {"type": "number"}
289
+ },
290
+ "required": [
291
+ "author", "guid", "public", "created_at", "remote_photo_path", "remote_photo_name", "width", "height"
292
+ ]
293
+ }
294
+ }
295
+ },
296
+
297
+ "poll_answer": {
298
+ "type": "object",
299
+ "properties": {
300
+ "entity_type": {
301
+ "type": "string",
302
+ "pattern": "^poll_answer$"
303
+ },
304
+ "entity_data": {
305
+ "type": "object",
306
+ "properties": {
307
+ "guid": { "$ref": "#/definitions/guid" },
308
+ "answer": { "type": "string" }
309
+ },
310
+ "required": [
311
+ "answer",
312
+ "guid"
313
+ ]
314
+ }
315
+ }
316
+ },
317
+
318
+ "poll": {
319
+ "type": "object",
320
+ "properties": {
321
+ "entity_type": {
322
+ "type": "string",
323
+ "pattern": "^poll$"
324
+ },
325
+ "entity_data": {
326
+ "type": "object",
327
+ "properties": {
328
+ "guid": {
329
+ "$ref": "#/definitions/guid"
330
+ },
331
+ "question": {
332
+ "type": "string"
333
+ },
334
+ "poll_answers": {
335
+ "type": "array",
336
+ "items": {
337
+ "$ref": "#/definitions/poll_answer"
338
+ }
339
+ }
340
+ },
341
+ "required": [
342
+ "guid",
343
+ "question",
344
+ "poll_answers"
345
+ ]
346
+ }
347
+ }
348
+ },
349
+
350
+ "location": {
351
+ "type": "object",
352
+ "properties": {
353
+ "entity_type": {
354
+ "type": "string",
355
+ "pattern": "^location$"
356
+ },
357
+ "entity_data": {
358
+ "type": "object",
359
+ "properties": {
360
+ "address": {
361
+ "type": "string"
362
+ },
363
+ "lat": {
364
+ "type": "string"
365
+ },
366
+ "lng": {
367
+ "type": "string"
368
+ }
369
+ },
370
+ "required": [
371
+ "address",
372
+ "lat",
373
+ "lng"
374
+ ]
375
+ }
376
+ }
377
+ }
378
+ }
379
+ }
@@ -4,7 +4,7 @@ module DiasporaFederation
4
4
  class AccountDeletionValidator < Validation::Validator
5
5
  include Validation
6
6
 
7
- rule :author, %i(not_empty diaspora_id)
7
+ rule :author, %i[not_empty diaspora_id]
8
8
  end
9
9
  end
10
10
  end
@@ -0,0 +1,12 @@
1
+ module DiasporaFederation
2
+ module Validators
3
+ # This validates a {Entities::AccountMigration}.
4
+ class AccountMigrationValidator < Validation::Validator
5
+ include Validation
6
+
7
+ rule :author, %i[not_empty diaspora_id]
8
+
9
+ rule :profile, :not_nil
10
+ end
11
+ end
12
+ end
@@ -4,8 +4,8 @@ module DiasporaFederation
4
4
  class ContactValidator < Validation::Validator
5
5
  include Validation
6
6
 
7
- rule :author, %i(not_empty diaspora_id)
8
- rule :recipient, %i(not_empty diaspora_id)
7
+ rule :author, %i[not_empty diaspora_id]
8
+ rule :recipient, %i[not_empty diaspora_id]
9
9
  rule :following, :boolean
10
10
  rule :sharing, :boolean
11
11
  end