diaspora_federation 0.1.9 → 0.2.0

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 (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