diaspora_federation 0.2.1 → 0.2.2

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 (55) hide show
  1. checksums.yaml +4 -4
  2. data/Changelog.md +27 -2
  3. data/lib/diaspora_federation.rb +16 -0
  4. data/lib/diaspora_federation/discovery/discovery.rb +23 -8
  5. data/lib/diaspora_federation/discovery/exceptions.rb +6 -6
  6. data/lib/diaspora_federation/discovery/web_finger.rb +13 -1
  7. data/lib/diaspora_federation/discovery/xrd_document.rb +35 -3
  8. data/lib/diaspora_federation/entities/event.rb +1 -1
  9. data/lib/diaspora_federation/entities/photo.rb +2 -2
  10. data/lib/diaspora_federation/entities/post.rb +5 -0
  11. data/lib/diaspora_federation/entities/profile.rb +4 -1
  12. data/lib/diaspora_federation/entities/related_entity.rb +8 -0
  13. data/lib/diaspora_federation/entities/relayable.rb +3 -3
  14. data/lib/diaspora_federation/entities/reshare.rb +28 -8
  15. data/lib/diaspora_federation/entities/retraction.rb +1 -1
  16. data/lib/diaspora_federation/entities/status_message.rb +0 -5
  17. data/lib/diaspora_federation/entity.rb +4 -1
  18. data/lib/diaspora_federation/federation.rb +1 -0
  19. data/lib/diaspora_federation/federation/diaspora_url_parser.rb +34 -0
  20. data/lib/diaspora_federation/federation/fetcher.rb +23 -11
  21. data/lib/diaspora_federation/federation/receiver.rb +2 -2
  22. data/lib/diaspora_federation/federation/receiver/abstract_receiver.rb +6 -1
  23. data/lib/diaspora_federation/federation/receiver/public.rb +10 -3
  24. data/lib/diaspora_federation/parsers/base_parser.rb +1 -1
  25. data/lib/diaspora_federation/properties_dsl.rb +0 -2
  26. data/lib/diaspora_federation/validators.rb +1 -0
  27. data/lib/diaspora_federation/validators/account_deletion_validator.rb +2 -2
  28. data/lib/diaspora_federation/validators/account_migration_validator.rb +2 -2
  29. data/lib/diaspora_federation/validators/comment_validator.rb +1 -1
  30. data/lib/diaspora_federation/validators/contact_validator.rb +3 -3
  31. data/lib/diaspora_federation/validators/conversation_validator.rb +2 -2
  32. data/lib/diaspora_federation/validators/event_participation_validator.rb +1 -1
  33. data/lib/diaspora_federation/validators/event_validator.rb +2 -2
  34. data/lib/diaspora_federation/validators/h_card_validator.rb +1 -1
  35. data/lib/diaspora_federation/validators/like_validator.rb +1 -1
  36. data/lib/diaspora_federation/validators/location_validator.rb +1 -1
  37. data/lib/diaspora_federation/validators/message_validator.rb +2 -2
  38. data/lib/diaspora_federation/validators/optional_aware_validator.rb +23 -0
  39. data/lib/diaspora_federation/validators/participation_validator.rb +2 -2
  40. data/lib/diaspora_federation/validators/person_validator.rb +2 -2
  41. data/lib/diaspora_federation/validators/photo_validator.rb +3 -3
  42. data/lib/diaspora_federation/validators/poll_answer_validator.rb +1 -1
  43. data/lib/diaspora_federation/validators/poll_participation_validator.rb +1 -1
  44. data/lib/diaspora_federation/validators/poll_validator.rb +1 -1
  45. data/lib/diaspora_federation/validators/profile_validator.rb +1 -1
  46. data/lib/diaspora_federation/validators/related_entity_validator.rb +1 -1
  47. data/lib/diaspora_federation/validators/relayable_validator.rb +1 -1
  48. data/lib/diaspora_federation/validators/reshare_validator.rb +3 -5
  49. data/lib/diaspora_federation/validators/retraction_validator.rb +2 -2
  50. data/lib/diaspora_federation/validators/rules/diaspora_id.rb +18 -13
  51. data/lib/diaspora_federation/validators/rules/guid.rb +10 -15
  52. data/lib/diaspora_federation/validators/status_message_validator.rb +2 -2
  53. data/lib/diaspora_federation/validators/web_finger_validator.rb +1 -1
  54. data/lib/diaspora_federation/version.rb +1 -1
  55. metadata +7 -5
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 5dbce3e434737107507881b68c2f8d51a0cf2d78
4
- data.tar.gz: 6c974f67b87f2ffa988c1286d17b920ad49fe9ef
3
+ metadata.gz: 79f5ac9d463c824a36b9769994431ac6e66625fd
4
+ data.tar.gz: 270ed5a33de71c405bdcd584c620d3f1d97422c9
5
5
  SHA512:
6
- metadata.gz: 9ac23b66e6c06e368f7dff5a190222e123a388653c2bb9983a28b80c08a9f6831fb584e86195ac627ad16f1d73fb9f185695d5b5c469efb19be70bddb2681f91
7
- data.tar.gz: 248882b3d9a8c71a94894724719f63a04a4398eabb2f13b35fb7559cae0fdf017b0010a1940390ecab70664598fe01cf168efb2ac6f44f404fc6c82360b26c38
6
+ metadata.gz: 14ed9bc7669bf07166bebacfe43bbb0cb78821010964181f94f3f395838ba7836755ebdc913048f7455fa6ca6cf0e78e281190ec1f914591c5233a641d986040
7
+ data.tar.gz: 91b6f07218394e0e066aefd973de6ddc4fa7c0d694c4ee25e53504d15f5371036e8b765f1d911f6008464c9f86e23e66a2a9010c32e3fb4f30da8c064099668e
@@ -1,12 +1,37 @@
1
+ # 0.2.2
2
+
3
+ ## Features
4
+
5
+ * Add support for [diaspora://](https://diaspora.github.io/diaspora_federation/federation/diaspora_scheme.html) URIs and fetch linked entities (see [#75](https://github.com/diaspora/diaspora_federation/pull/75)) [#78](https://github.com/diaspora/diaspora_federation/pull/78) [#85](https://github.com/diaspora/diaspora_federation/pull/85)
6
+ * Fetch RFC 7033 WebFinger with fallback to legacy WebFinger [#74](https://github.com/diaspora/diaspora_federation/pull/74)
7
+ * Add support to receive and relay likes for comments [#81](https://github.com/diaspora/diaspora_federation/pull/81)
8
+
9
+ ## Refactor
10
+
11
+ * Always raise a DiscoveryError when something with the discovery fails [#77](https://github.com/diaspora/diaspora_federation/pull/77)
12
+ * Tighten the validation of diaspora\* IDs [#86](https://github.com/diaspora/diaspora_federation/pull/86)
13
+ * Allow to receive non-public profiles without private data [#79](https://github.com/diaspora/diaspora_federation/pull/79)
14
+ * Remove `public` and `provider_display_name` from `Reshare` entity [#84](https://github.com/diaspora/diaspora_federation/pull/84)
15
+
16
+ ## Bug fixes
17
+
18
+ * Allow reshares with no root [#73](https://github.com/diaspora/diaspora_federation/pull/73)
19
+ * Make `height` and `width` optional for photos [#76](https://github.com/diaspora/diaspora_federation/pull/76)
20
+ * Detect loops when fetching entities [#87](https://github.com/diaspora/diaspora_federation/pull/87)
21
+
22
+ ## Documentation
23
+
24
+ * Add documentation for the future of the `Reshare` entity (see [#83](https://github.com/diaspora/diaspora_federation/pull/83)) [#84](https://github.com/diaspora/diaspora_federation/pull/84)
25
+
1
26
  # 0.2.1
2
27
 
3
28
  ## Features
4
29
 
5
- Add `DiasporaFederation::Schemas` to access the JSON schema [#70](https://github.com/diaspora/diaspora_federation/pull/70)
30
+ * Add `DiasporaFederation::Schemas` to access the JSON schema [#70](https://github.com/diaspora/diaspora_federation/pull/70)
6
31
 
7
32
  ## Refactor
8
33
 
9
- Don't add optional properties to generated XML and JSON when nil [#71](https://github.com/diaspora/diaspora_federation/pull/71)
34
+ * Don't add optional properties to generated XML and JSON when nil [#71](https://github.com/diaspora/diaspora_federation/pull/71)
10
35
 
11
36
  # 0.2.0
12
37
 
@@ -39,6 +39,7 @@ module DiasporaFederation
39
39
  ]
40
40
 
41
41
  # defaults
42
+ @webfinger_http_fallback = false
42
43
  @http_concurrency = 20
43
44
  @http_timeout = 30
44
45
  @http_verbose = false
@@ -74,6 +75,21 @@ module DiasporaFederation
74
75
  # @param [String] value path to certificate authorities
75
76
  attr_accessor :certificate_authorities
76
77
 
78
+ # Configure if WebFinger discovery should fallback to http if https fails (default: +false+)
79
+ #
80
+ # This is useful for example for development environments where https isn't available.
81
+ #
82
+ # This setting only applies to the WebFinger route from RFC 7033 +/.well-known/webfinger+.
83
+ # Legacy WebFinger flow unconditionally falls back to http.
84
+ #
85
+ # @overload webfinger_http_fallback
86
+ # @return [Boolean] webfinger http fallback enabled
87
+ # @overload webfinger_http_fallback=
88
+ # @example
89
+ # config.webfinger_http_fallback = AppConfig.server.rails_environment == "development"
90
+ # @param [Boolean] value webfinger http fallback enabled
91
+ attr_accessor :webfinger_http_fallback
92
+
77
93
  # Maximum number of parallel HTTP requests made to other pods (default: +20+)
78
94
  #
79
95
  # @overload http_concurrency
@@ -15,6 +15,7 @@ module DiasporaFederation
15
15
 
16
16
  # Fetches all metadata for the account and saves it via callback
17
17
  # @return [Person]
18
+ # @raise [DiscoveryError] if something with the discovery failed
18
19
  def fetch_and_save
19
20
  logger.info "Fetch data for #{diaspora_id}"
20
21
 
@@ -23,6 +24,10 @@ module DiasporaFederation
23
24
  DiasporaFederation.callbacks.trigger(:save_person_after_webfinger, person)
24
25
  logger.info "successfully webfingered #{diaspora_id}"
25
26
  person
27
+ rescue DiscoveryError
28
+ raise # simply re-raise DiscoveryError
29
+ rescue => e # rubocop:disable Lint/RescueWithoutErrorClass
30
+ raise DiscoveryError, "Failed discovery for #{diaspora_id}: #{e.class}: #{e.message}"
26
31
  end
27
32
 
28
33
  private
@@ -43,7 +48,7 @@ module DiasporaFederation
43
48
  response = HttpClient.get(url)
44
49
  raise "Failed to fetch #{url}: #{response.status}" unless response.success?
45
50
  response.body
46
- rescue => e
51
+ rescue => e # rubocop:disable Lint/RescueWithoutErrorClass
47
52
  unless http_fallback && url.start_with?("https://")
48
53
  raise DiscoveryError, "Failed to fetch #{url} for #{diaspora_id}: #{e.class}: #{e.message}"
49
54
  end
@@ -53,23 +58,33 @@ module DiasporaFederation
53
58
  retry
54
59
  end
55
60
 
56
- def host_meta_url
57
- domain = diaspora_id.split("@")[1]
58
- "https://#{domain}/.well-known/host-meta"
61
+ def domain
62
+ @domain ||= diaspora_id.split("@")[1]
63
+ end
64
+
65
+ def acct_parameter
66
+ "acct:#{diaspora_id}"
59
67
  end
60
68
 
61
69
  def legacy_webfinger_url_from_host_meta
62
70
  # This tries the xrd url with https first, then falls back to http.
63
- host_meta = HostMeta.from_xml get(host_meta_url, true)
64
- host_meta.webfinger_template_url.gsub("{uri}", "acct:#{diaspora_id}")
71
+ host_meta = HostMeta.from_xml(get("https://#{domain}/.well-known/host-meta", true))
72
+ host_meta.webfinger_template_url.gsub("{uri}", acct_parameter)
65
73
  end
66
74
 
67
75
  def webfinger
68
- @webfinger ||= WebFinger.from_xml get(legacy_webfinger_url_from_host_meta)
76
+ return @webfinger if @webfinger
77
+ webfinger_url = "https://#{domain}/.well-known/webfinger?resource=#{acct_parameter}"
78
+
79
+ # This tries the WebFinger URL with https first, then falls back to http if webfinger_http_fallback is enabled.
80
+ @webfinger = WebFinger.from_json(get(webfinger_url, DiasporaFederation.webfinger_http_fallback))
81
+ rescue => e # rubocop:disable Lint/RescueWithoutErrorClass
82
+ logger.warn "WebFinger failed, retrying with legacy WebFinger for #{diaspora_id}: #{e.class}: #{e.message}"
83
+ @webfinger = WebFinger.from_xml(get(legacy_webfinger_url_from_host_meta))
69
84
  end
70
85
 
71
86
  def hcard
72
- @hcard ||= HCard.from_html get(webfinger.hcard_url)
87
+ @hcard ||= HCard.from_html(get(webfinger.hcard_url))
73
88
  end
74
89
 
75
90
  def person
@@ -1,7 +1,11 @@
1
1
  module DiasporaFederation
2
2
  module Discovery
3
+ # Raised, if there is an error while discover a new person
4
+ class DiscoveryError < RuntimeError
5
+ end
6
+
3
7
  # Raised, if the XML structure is invalid
4
- class InvalidDocument < RuntimeError
8
+ class InvalidDocument < DiscoveryError
5
9
  end
6
10
 
7
11
  # Raised, if something is wrong with the webfinger data
@@ -9,11 +13,7 @@ module DiasporaFederation
9
13
  # * if the +webfinger_url+ is missing or malformed in {HostMeta.from_base_url} or {HostMeta.from_xml}
10
14
  # * if the parsed XML from {WebFinger.from_xml} is incomplete
11
15
  # * if the html passed to {HCard.from_html} in some way is malformed, invalid or incomplete.
12
- class InvalidData < RuntimeError
13
- end
14
-
15
- # Raised, if there is an error while discover a new person
16
- class DiscoveryError < RuntimeError
16
+ class InvalidData < DiscoveryError
17
17
  end
18
18
  end
19
19
  end
@@ -119,8 +119,20 @@ module DiasporaFederation
119
119
  # @return [WebFinger] WebFinger instance
120
120
  # @raise [InvalidData] if the given XML string is invalid or incomplete
121
121
  def self.from_xml(webfinger_xml)
122
- data = parse_xml_and_validate(webfinger_xml)
122
+ from_hash(parse_xml_and_validate(webfinger_xml))
123
+ end
123
124
 
125
+ # Creates a WebFinger instance from the given JSON string
126
+ # @param [String] webfinger_json WebFinger JSON string
127
+ # @return [WebFinger] WebFinger instance
128
+ def self.from_json(webfinger_json)
129
+ from_hash(XrdDocument.json_data(webfinger_json))
130
+ end
131
+
132
+ # Creates a WebFinger instance from the given data
133
+ # @param [Hash] data WebFinger data hash
134
+ # @return [WebFinger] WebFinger instance
135
+ def self.from_hash(data)
124
136
  links = data[:links]
125
137
 
126
138
  new(
@@ -83,10 +83,10 @@ module DiasporaFederation
83
83
  def to_json
84
84
  {
85
85
  subject: subject,
86
- expires: expires,
86
+ expires: (expires.strftime(DATETIME_FORMAT) if expires.instance_of?(DateTime)),
87
87
  aliases: (aliases if aliases.any?),
88
- links: (links if links.any?),
89
- properties: (properties if properties.any?)
88
+ properties: (properties if properties.any?),
89
+ links: (links if links.any?)
90
90
  }.reject {|_, v| v.nil? }
91
91
  end
92
92
 
@@ -115,6 +115,27 @@ module DiasporaFederation
115
115
  end
116
116
  end
117
117
 
118
+ # Parse the JRD document from the given string and create a hash containing
119
+ # the extracted data with symbolized keys.
120
+ #
121
+ # @param [String] jrd_doc JSON string
122
+ # @return [Hash] extracted data
123
+ # @raise [InvalidDocument] if the JRD is malformed
124
+ def self.json_data(jrd_doc)
125
+ json_hash = JSON.parse(jrd_doc)
126
+
127
+ {
128
+ subject: json_hash["subject"],
129
+ expires: (DateTime.strptime(json_hash["expires"], DATETIME_FORMAT) if json_hash.key?("expires")),
130
+ aliases: json_hash["aliases"],
131
+ properties: json_hash["properties"],
132
+ links: symbolize_keys_for_links(json_hash["links"])
133
+ }.reject {|_, v| v.nil? }
134
+ rescue JSON::JSONError => e
135
+ raise InvalidDocument,
136
+ "Not a JRD document: #{e.class}: #{e.message[0..255].encode(Encoding.default_external, undef: :replace)}"
137
+ end
138
+
118
139
  private
119
140
 
120
141
  attr_reader :expires
@@ -180,6 +201,17 @@ module DiasporaFederation
180
201
  end
181
202
  data[:links] = links unless links.empty?
182
203
  end
204
+
205
+ # symbolize link keys from JSON hash, but only convert known keys
206
+ private_class_method def self.symbolize_keys_for_links(links)
207
+ links.map do |link|
208
+ {}.tap do |hash|
209
+ LINK_ATTRS.each do |attr|
210
+ hash[attr] = link[attr.to_s] if link.key?(attr.to_s)
211
+ end
212
+ end
213
+ end
214
+ end
183
215
  end
184
216
  end
185
217
  end
@@ -24,7 +24,7 @@ module DiasporaFederation
24
24
  # @!attribute [r] description
25
25
  # Description of the event
26
26
  # @return [String] event description
27
- property :description, :string, optional: true
27
+ property :description, :string, alias: :text, optional: true
28
28
 
29
29
  # @!attribute [r] start
30
30
  # The start time of the event
@@ -48,12 +48,12 @@ module DiasporaFederation
48
48
  # @!attribute [r] height
49
49
  # Photo height
50
50
  # @return [Integer] height
51
- property :height, :integer
51
+ property :height, :integer, optional: true
52
52
 
53
53
  # @!attribute [r] width
54
54
  # Photo width
55
55
  # @return [Integer] width
56
- property :width, :integer
56
+ property :width, :integer, optional: true
57
57
  end
58
58
  end
59
59
  end
@@ -19,6 +19,10 @@ module DiasporaFederation
19
19
  # Post entity creation time
20
20
  # @return [Time] creation time
21
21
  #
22
+ # @!attribute [r] public
23
+ # Shows whether the post is visible to everyone or only to some aspects
24
+ # @return [Boolean] is it public
25
+ #
22
26
  # @!attribute [r] provider_display_name
23
27
  # A string that describes a means by which a user has posted the post
24
28
  # @return [String] provider display name
@@ -29,6 +33,7 @@ module DiasporaFederation
29
33
  property :author, :string, xml_name: :diaspora_handle
30
34
  property :guid, :string
31
35
  property :created_at, :timestamp, default: -> { Time.now.utc }
36
+ property :public, :boolean, default: false
32
37
  property :provider_display_name, :string, optional: true
33
38
  end
34
39
  end
@@ -43,9 +43,12 @@ module DiasporaFederation
43
43
  # @return [String] url to the small avatar (50x50)
44
44
  property :image_url_small, :string, optional: true
45
45
 
46
+ # @!attribute [r] bio
47
+ # @return [String] bio of the person
48
+ property :bio, :string, alias: :text, optional: true
49
+
46
50
  property :birthday, :string, optional: true
47
51
  property :gender, :string, optional: true
48
- property :bio, :string, optional: true
49
52
  property :location, :string, optional: true
50
53
 
51
54
  # @!attribute [r] searchable
@@ -24,6 +24,14 @@ module DiasporaFederation
24
24
  # @return [RelatedEntity] parent entity
25
25
  entity :parent, Entities::RelatedEntity, default: nil
26
26
 
27
+ # The root entity, this entity is responsible for relaying relayables
28
+ # @return [RelatedEntity] absolute parent entity
29
+ def root
30
+ root = self
31
+ root = root.parent until root.parent.nil?
32
+ root
33
+ end
34
+
27
35
  # Get related entity from the backend or fetch it from remote if not available locally
28
36
  # @return [RelatedEntity] fetched related entity
29
37
  def self.fetch(author, type, guid)
@@ -76,11 +76,11 @@ module DiasporaFederation
76
76
  # @raise [SignatureVerificationFailed] if the signature is not valid
77
77
  # @raise [PublicKeyNotFound] if no public key is found
78
78
  def verify_signature
79
- super(author, :author_signature) unless author == parent.author
79
+ super(author, :author_signature) unless author == parent.root.author
80
80
  end
81
81
 
82
82
  def sender_valid?(sender)
83
- (sender == author && parent.local) || sender == parent.author
83
+ (sender == author && parent.root.local) || sender == parent.root.author
84
84
  end
85
85
 
86
86
  # @return [String] string representation of this object
@@ -121,7 +121,7 @@ module DiasporaFederation
121
121
  # Sign with parent author key, if the parent author is local (if the private key is found)
122
122
  # @return [String] A Base64 encoded signature of #signature_data with key
123
123
  def sign_with_parent_author_if_available
124
- privkey = DiasporaFederation.callbacks.trigger(:fetch_private_key, parent.author)
124
+ privkey = DiasporaFederation.callbacks.trigger(:fetch_private_key, parent.root.author)
125
125
  return unless privkey
126
126
 
127
127
  sign_with_key(privkey).tap do
@@ -4,24 +4,34 @@ module DiasporaFederation
4
4
  #
5
5
  # @see Validators::ReshareValidator
6
6
  class Reshare < Entity
7
- include Post
7
+ # @!attribute [r] author
8
+ # The diaspora* ID of the person who reshares the post
9
+ # @see Person#author
10
+ # @return [String] diaspora* ID
11
+ property :author, :string, xml_name: :diaspora_handle
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
+ property :guid, :string
18
+
19
+ # @!attribute [r] created_at
20
+ # Post entity creation time
21
+ # @return [Time] creation time
22
+ property :created_at, :timestamp, default: -> { Time.now.utc }
8
23
 
9
24
  # @!attribute [r] root_author
10
25
  # The diaspora* ID of the person who posted the original post
11
26
  # @see Person#author
12
27
  # @return [String] diaspora* ID
13
- property :root_author, :string, xml_name: :root_diaspora_id
28
+ property :root_author, :string, optional: true, xml_name: :root_diaspora_id
14
29
 
15
30
  # @!attribute [r] root_guid
16
31
  # Guid of the original post
17
32
  # @see StatusMessage#guid
18
33
  # @return [String] root guid
19
- property :root_guid, :string
20
-
21
- # @!attribute [r] public
22
- # Has no meaning at the moment
23
- # @return [Boolean] public
24
- property :public, :boolean, optional: true, default: true # always true? (we only reshare public posts)
34
+ property :root_guid, :string, optional: true
25
35
 
26
36
  # @return [String] string representation of this object
27
37
  def to_s
@@ -30,7 +40,17 @@ module DiasporaFederation
30
40
 
31
41
  # Fetch and receive root post from remote, if not available locally
32
42
  # and validates if it's from the correct author
43
+ # TODO: after reshares are only used to increase the reach of a post (and
44
+ # legacy reshares with own interactions are migrated to the new form),
45
+ # root_author and root_guid aren't allowed to be empty anymore, so a
46
+ # not_nil check should be added to the validator and the first few lines
47
+ # here can be removed.
33
48
  def validate_root
49
+ return if root_author.nil? && root_guid.nil?
50
+
51
+ raise Entity::ValidationError, "#{self}: root_guid can't be nil if root_author is present" if root_guid.nil?
52
+ raise Entity::ValidationError, "#{self}: root_author can't be nil if root_guid is present" if root_author.nil?
53
+
34
54
  root = RelatedEntity.fetch(root_author, "Post", root_guid)
35
55
 
36
56
  return if root_author == root.author
@@ -28,7 +28,7 @@ module DiasporaFederation
28
28
  def sender_valid?(sender)
29
29
  case target_type
30
30
  when "Comment", "Like", "PollParticipation"
31
- sender == target.author || sender == target.parent.author
31
+ sender == target.author || sender == target.root.author
32
32
  else
33
33
  sender == target.author
34
34
  end
@@ -31,11 +31,6 @@ module DiasporaFederation
31
31
  # @return [Entities::Event] event
32
32
  entity :event, Entities::Event, optional: true
33
33
 
34
- # @!attribute [r] public
35
- # Shows whether the status message is visible to everyone or only to some aspects
36
- # @return [Boolean] is it public
37
- property :public, :boolean, default: false
38
-
39
34
  private
40
35
 
41
36
  def validate
@@ -40,6 +40,9 @@ module DiasporaFederation
40
40
  # @see https://www.w3.org/TR/REC-xml/#charsets "Extensible Markup Language (XML) 1.0"
41
41
  INVALID_XML_REGEX = /[^\x09\x0A\x0D\x20-\uD7FF\uE000-\uFFFD\u{10000}-\u{10FFFF}]/
42
42
 
43
+ # Regex to validate and find entity names
44
+ ENTITY_NAME_REGEX = "[a-z]*(?:_[a-z]*)*".freeze
45
+
43
46
  # Initializes the Entity with the given attribute hash and freezes the created
44
47
  # instance it returns.
45
48
  #
@@ -145,7 +148,7 @@ module DiasporaFederation
145
148
  # @param [String] entity_name "snake_case" class name
146
149
  # @return [Class] entity class
147
150
  def self.entity_class(entity_name)
148
- raise InvalidEntityName, "'#{entity_name}' is invalid" unless entity_name =~ /\A[a-z]*(_[a-z]*)*\z/
151
+ raise InvalidEntityName, "'#{entity_name}' is invalid" unless entity_name =~ /\A#{ENTITY_NAME_REGEX}\z/
149
152
  class_name = entity_name.sub(/\A[a-z]/, &:upcase)
150
153
  class_name.gsub!(/_([a-z])/) { Regexp.last_match[1].upcase }
151
154
 
@@ -4,6 +4,7 @@ module DiasporaFederation
4
4
  end
5
5
  end
6
6
 
7
+ require "diaspora_federation/federation/diaspora_url_parser"
7
8
  require "diaspora_federation/federation/fetcher"
8
9
  require "diaspora_federation/federation/receiver"
9
10
  require "diaspora_federation/federation/sender"
@@ -0,0 +1,34 @@
1
+ module DiasporaFederation
2
+ module Federation
3
+ # This module is for parsing and fetching linked entities.
4
+ module DiasporaUrlParser
5
+ include Logging
6
+
7
+ # Regex to find diaspora:// URLs
8
+ DIASPORA_URL_REGEX = %r{
9
+ diaspora://
10
+ (#{Validation::Rule::DiasporaId::DIASPORA_ID_REGEX})/
11
+ (#{Entity::ENTITY_NAME_REGEX})/
12
+ (#{Validation::Rule::Guid::VALID_CHARS})
13
+ }ux
14
+
15
+ # Parses all diaspora:// URLs from the text and fetches the entities from
16
+ # the remote server if needed.
17
+ # @param [String] sender the diaspora* ID of the sender of the entity
18
+ # @param [String] text text with diaspora:// URLs to fetch
19
+ def self.fetch_linked_entities(text)
20
+ text.scan(DIASPORA_URL_REGEX).each do |author, type, guid|
21
+ fetch_entity(author, type, guid)
22
+ end
23
+ end
24
+
25
+ private_class_method def self.fetch_entity(author, type, guid)
26
+ class_name = Entity.entity_class(type).to_s.rpartition("::").last
27
+ return if DiasporaFederation.callbacks.trigger(:fetch_related_entity, class_name, guid)
28
+ Fetcher.fetch_public(author, type, guid)
29
+ rescue => e # rubocop:disable Lint/RescueWithoutErrorClass
30
+ logger.error "Failed to fetch linked entity #{type}:#{guid}: #{e.class}: #{e.message}"
31
+ end
32
+ end
33
+ end
34
+ end
@@ -6,28 +6,40 @@ module DiasporaFederation
6
6
  # @param [String] author the diaspora* ID of the author of the entity
7
7
  # @param [Symbol, String] entity_type snake_case version of the entity class
8
8
  # @param [String] guid guid of the entity to fetch
9
+ # @raise [NotFetchable] if something with the fetching failed
9
10
  def self.fetch_public(author, entity_type, guid)
10
- url = DiasporaFederation.callbacks.trigger(
11
- :fetch_person_url_to, author, "/fetch/#{entity_name(entity_type)}/#{guid}"
12
- )
13
- response = HttpClient.get(url)
14
- raise "Failed to fetch #{url}: #{response.status}" unless response.success?
15
-
16
- magic_env_xml = Nokogiri::XML(response.body).root
17
- magic_env = Salmon::MagicEnvelope.unenvelop(magic_env_xml)
18
- Receiver::Public.new(magic_env).receive
19
- rescue => e
11
+ type = entity_name(entity_type).to_s
12
+ raise "Already fetching ..." if fetching[type].include?(guid)
13
+ fetch_from_url(author, type, guid)
14
+ rescue => e # rubocop:disable Lint/RescueWithoutErrorClass
20
15
  raise NotFetchable, "Failed to fetch #{entity_type}:#{guid} from #{author}: #{e.class}: #{e.message}"
21
16
  end
22
17
 
23
18
  private_class_method def self.entity_name(class_name)
24
- return class_name if class_name =~ /\A[a-z]*(_[a-z]*)*\z/
19
+ return class_name if class_name =~ /\A#{Entity::ENTITY_NAME_REGEX}\z/
25
20
 
26
21
  raise DiasporaFederation::Entity::UnknownEntity, class_name unless Entities.const_defined?(class_name)
27
22
 
28
23
  class_name.gsub(/(.)([A-Z])/, '\1_\2').downcase
29
24
  end
30
25
 
26
+ private_class_method def self.fetch_from_url(author, type, guid)
27
+ fetching[type] << guid
28
+
29
+ url = DiasporaFederation.callbacks.trigger(:fetch_person_url_to, author, "/fetch/#{type}/#{guid}")
30
+ response = HttpClient.get(url)
31
+ raise "Failed to fetch #{url}: #{response.status}" unless response.success?
32
+
33
+ Receiver.receive_public(response.body)
34
+ ensure
35
+ fetching[type].delete(guid)
36
+ end
37
+
38
+ # currently fetching entities in the same thread
39
+ private_class_method def self.fetching
40
+ Thread.current[:fetching_entities] ||= Hash.new {|h, k| h[k] = [] }
41
+ end
42
+
31
43
  # Raised, if the entity is not fetchable
32
44
  class NotFetchable < RuntimeError
33
45
  end
@@ -15,7 +15,7 @@ module DiasporaFederation
15
15
  Salmon::MagicEnvelope.unenvelop(magic_env_xml)
16
16
  end
17
17
  Public.new(magic_env).receive
18
- rescue => e
18
+ rescue => e # rubocop:disable Lint/RescueWithoutErrorClass
19
19
  logger.error "failed to receive public message: #{e.class}: #{e.message}"
20
20
  logger.debug "received data:\n#{data}"
21
21
  raise e
@@ -36,7 +36,7 @@ module DiasporaFederation
36
36
  Salmon::MagicEnvelope.unenvelop(magic_env_xml)
37
37
  end
38
38
  Private.new(magic_env, recipient_id).receive
39
- rescue => e
39
+ rescue => e # rubocop:disable Lint/RescueWithoutErrorClass
40
40
  logger.error "failed to receive private message for #{recipient_id}: #{e.class}: #{e.message}"
41
41
  logger.debug "received data:\n#{data}"
42
42
  raise e
@@ -17,7 +17,7 @@ module DiasporaFederation
17
17
  # Validates and receives the entity
18
18
  def receive
19
19
  validate_and_receive
20
- rescue => e
20
+ rescue => e # rubocop:disable Lint/RescueWithoutErrorClass
21
21
  logger.error "failed to receive #{entity}"
22
22
  raise e
23
23
  end
@@ -28,6 +28,7 @@ module DiasporaFederation
28
28
 
29
29
  def validate_and_receive
30
30
  validate
31
+ fetch_linked_entities_from_text
31
32
  DiasporaFederation.callbacks.trigger(:receive_entity, entity, sender, recipient_id)
32
33
  logger.info "successfully received #{entity} from person #{sender}#{" for #{recipient_id}" if recipient_id}"
33
34
  end
@@ -43,6 +44,10 @@ module DiasporaFederation
43
44
  sender == entity.author
44
45
  end
45
46
  end
47
+
48
+ def fetch_linked_entities_from_text
49
+ DiasporaUrlParser.fetch_linked_entities(entity.text) if entity.respond_to?(:text) && entity.text
50
+ end
46
51
  end
47
52
  end
48
53
  end
@@ -7,11 +7,18 @@ module DiasporaFederation
7
7
 
8
8
  def validate
9
9
  super
10
- raise NotPublic if entity_can_be_public_but_it_is_not?
10
+ validate_public_flag
11
11
  end
12
12
 
13
- def entity_can_be_public_but_it_is_not?
14
- entity.respond_to?(:public) && !entity.public
13
+ def validate_public_flag
14
+ return if !entity.respond_to?(:public) || entity.public
15
+
16
+ if entity.is_a?(Entities::Profile) &&
17
+ %i[bio birthday gender location].all? {|prop| entity.public_send(prop).nil? }
18
+ return
19
+ end
20
+
21
+ raise NotPublic, "received entity #{entity} should be public!"
15
22
  end
16
23
  end
17
24
  end
@@ -29,7 +29,7 @@ module DiasporaFederation
29
29
  when :timestamp
30
30
  begin
31
31
  Time.parse(text).utc
32
- rescue
32
+ rescue ArgumentError
33
33
  nil
34
34
  end
35
35
  when :integer
@@ -158,9 +158,7 @@ module DiasporaFederation
158
158
  # @param [Symbol] alias_name alias name
159
159
  def define_alias(name, alias_name)
160
160
  class_prop_aliases[alias_name] = name
161
- # rubocop:disable Style/Alias
162
161
  instance_eval { alias_method alias_name, name }
163
- # rubocop:enable Style/Alias
164
162
  end
165
163
 
166
164
  # Raised, if the name is of an unexpected type
@@ -37,6 +37,7 @@ end
37
37
  require "diaspora_federation/validators/related_entity_validator"
38
38
 
39
39
  # abstract types
40
+ require "diaspora_federation/validators/optional_aware_validator"
40
41
  require "diaspora_federation/validators/relayable_validator"
41
42
 
42
43
  # types
@@ -1,10 +1,10 @@
1
1
  module DiasporaFederation
2
2
  module Validators
3
3
  # This validates a {Entities::AccountDeletion}.
4
- class AccountDeletionValidator < Validation::Validator
4
+ class AccountDeletionValidator < OptionalAwareValidator
5
5
  include Validation
6
6
 
7
- rule :author, %i[not_empty diaspora_id]
7
+ rule :author, :diaspora_id
8
8
  end
9
9
  end
10
10
  end
@@ -1,10 +1,10 @@
1
1
  module DiasporaFederation
2
2
  module Validators
3
3
  # This validates a {Entities::AccountMigration}.
4
- class AccountMigrationValidator < Validation::Validator
4
+ class AccountMigrationValidator < OptionalAwareValidator
5
5
  include Validation
6
6
 
7
- rule :author, %i[not_empty diaspora_id]
7
+ rule :author, :diaspora_id
8
8
 
9
9
  rule :profile, :not_nil
10
10
  end
@@ -1,7 +1,7 @@
1
1
  module DiasporaFederation
2
2
  module Validators
3
3
  # This validates a {Entities::Comment}.
4
- class CommentValidator < Validation::Validator
4
+ class CommentValidator < OptionalAwareValidator
5
5
  include Validation
6
6
 
7
7
  include RelayableValidator
@@ -1,11 +1,11 @@
1
1
  module DiasporaFederation
2
2
  module Validators
3
3
  # This validates a {Entities::Contact}.
4
- class ContactValidator < Validation::Validator
4
+ class ContactValidator < OptionalAwareValidator
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, :diaspora_id
8
+ rule :recipient, :diaspora_id
9
9
  rule :following, :boolean
10
10
  rule :sharing, :boolean
11
11
  end
@@ -1,10 +1,10 @@
1
1
  module DiasporaFederation
2
2
  module Validators
3
3
  # This validates a {Entities::Conversation}.
4
- class ConversationValidator < Validation::Validator
4
+ class ConversationValidator < OptionalAwareValidator
5
5
  include Validation
6
6
 
7
- rule :author, %i[not_empty diaspora_id]
7
+ rule :author, :diaspora_id
8
8
  rule :guid, :guid
9
9
 
10
10
  rule :subject, [:not_empty, length: {maximum: 255}]
@@ -1,7 +1,7 @@
1
1
  module DiasporaFederation
2
2
  module Validators
3
3
  # This validates a {Entities::EventParticipation}.
4
- class EventParticipationValidator < Validation::Validator
4
+ class EventParticipationValidator < OptionalAwareValidator
5
5
  include Validation
6
6
 
7
7
  include RelayableValidator
@@ -1,10 +1,10 @@
1
1
  module DiasporaFederation
2
2
  module Validators
3
3
  # This validates a {Entities::Event}.
4
- class EventValidator < Validation::Validator
4
+ class EventValidator < OptionalAwareValidator
5
5
  include Validation
6
6
 
7
- rule :author, %i[not_empty diaspora_id]
7
+ rule :author, :diaspora_id
8
8
 
9
9
  rule :guid, :guid
10
10
 
@@ -3,7 +3,7 @@ module DiasporaFederation
3
3
  # This validates a {Discovery::HCard}.
4
4
  #
5
5
  # @note
6
- class HCardValidator < Validation::Validator
6
+ class HCardValidator < OptionalAwareValidator
7
7
  include Validation
8
8
 
9
9
  rule :guid, :guid
@@ -1,7 +1,7 @@
1
1
  module DiasporaFederation
2
2
  module Validators
3
3
  # This validates a {Entities::Like}.
4
- class LikeValidator < Validation::Validator
4
+ class LikeValidator < OptionalAwareValidator
5
5
  include Validation
6
6
 
7
7
  include RelayableValidator
@@ -1,7 +1,7 @@
1
1
  module DiasporaFederation
2
2
  module Validators
3
3
  # This validates a {Entities::Location}.
4
- class LocationValidator < Validation::Validator
4
+ class LocationValidator < OptionalAwareValidator
5
5
  include Validation
6
6
 
7
7
  rule :lat, :not_empty
@@ -1,10 +1,10 @@
1
1
  module DiasporaFederation
2
2
  module Validators
3
3
  # This validates a {Entities::Message}.
4
- class MessageValidator < Validation::Validator
4
+ class MessageValidator < OptionalAwareValidator
5
5
  include Validation
6
6
 
7
- rule :author, %i[not_empty diaspora_id]
7
+ rule :author, :diaspora_id
8
8
  rule :guid, :guid
9
9
  rule :conversation_guid, :guid
10
10
 
@@ -0,0 +1,23 @@
1
+ module DiasporaFederation
2
+ module Validators
3
+ # Abstract validator which only validates optional fields when they are not nil.
4
+ class OptionalAwareValidator < Validation::Validator
5
+ def rules
6
+ super.reject do |field, rules|
7
+ @obj.public_send(field).nil? &&
8
+ !rules.map(&:class).include?(Validation::Rule::NotNil) &&
9
+ optional_props.include?(field)
10
+ end
11
+ end
12
+
13
+ private
14
+
15
+ def optional_props
16
+ entity_name = self.class.name.split("::").last.sub("Validator", "")
17
+ return [] unless Entities.const_defined?(entity_name)
18
+
19
+ Entities.const_get(entity_name).optional_props
20
+ end
21
+ end
22
+ end
23
+ end
@@ -1,10 +1,10 @@
1
1
  module DiasporaFederation
2
2
  module Validators
3
3
  # This validates a {Entities::Participation}.
4
- class ParticipationValidator < Validation::Validator
4
+ class ParticipationValidator < OptionalAwareValidator
5
5
  include Validation
6
6
 
7
- rule :author, %i[not_empty diaspora_id]
7
+ rule :author, :diaspora_id
8
8
  rule :guid, :guid
9
9
  rule :parent_guid, :guid
10
10
  rule :parent_type, [:not_empty, regular_expression: {regex: /\APost\z/}]
@@ -1,12 +1,12 @@
1
1
  module DiasporaFederation
2
2
  module Validators
3
3
  # This validates a {Entities::Person}.
4
- class PersonValidator < Validation::Validator
4
+ class PersonValidator < OptionalAwareValidator
5
5
  include Validation
6
6
 
7
7
  rule :guid, :guid
8
8
 
9
- rule :author, %i[not_empty diaspora_id]
9
+ rule :author, :diaspora_id
10
10
 
11
11
  rule :url, %i[not_nil URI]
12
12
 
@@ -1,12 +1,12 @@
1
1
  module DiasporaFederation
2
2
  module Validators
3
3
  # This validates a {Entities::Photo}.
4
- class PhotoValidator < Validation::Validator
4
+ class PhotoValidator < OptionalAwareValidator
5
5
  include Validation
6
6
 
7
7
  rule :guid, :guid
8
8
 
9
- rule :author, %i[not_empty diaspora_id]
9
+ rule :author, :diaspora_id
10
10
 
11
11
  rule :public, :boolean
12
12
 
@@ -14,7 +14,7 @@ module DiasporaFederation
14
14
 
15
15
  rule :remote_photo_name, :not_empty
16
16
 
17
- rule :status_message_guid, guid: {nilable: true}
17
+ rule :status_message_guid, :guid
18
18
 
19
19
  rule :text, length: {maximum: 65_535}
20
20
 
@@ -1,7 +1,7 @@
1
1
  module DiasporaFederation
2
2
  module Validators
3
3
  # This validates a {Entities::PollAnswer}.
4
- class PollAnswerValidator < Validation::Validator
4
+ class PollAnswerValidator < OptionalAwareValidator
5
5
  include Validation
6
6
 
7
7
  rule :guid, :guid
@@ -1,7 +1,7 @@
1
1
  module DiasporaFederation
2
2
  module Validators
3
3
  # This validates a {Entities::PollParticipation}.
4
- class PollParticipationValidator < Validation::Validator
4
+ class PollParticipationValidator < OptionalAwareValidator
5
5
  include Validation
6
6
 
7
7
  include RelayableValidator
@@ -1,7 +1,7 @@
1
1
  module DiasporaFederation
2
2
  module Validators
3
3
  # This validates a {Entities::Poll}.
4
- class PollValidator < Validation::Validator
4
+ class PollValidator < OptionalAwareValidator
5
5
  include Validation
6
6
 
7
7
  rule :guid, :guid
@@ -1,7 +1,7 @@
1
1
  module DiasporaFederation
2
2
  module Validators
3
3
  # This validates a {Entities::Profile}.
4
- class ProfileValidator < Validation::Validator
4
+ class ProfileValidator < OptionalAwareValidator
5
5
  include Validation
6
6
 
7
7
  rule :author, :diaspora_id
@@ -4,7 +4,7 @@ module DiasporaFederation
4
4
  class RelatedEntityValidator < Validation::Validator
5
5
  include Validation
6
6
 
7
- rule :author, %i[not_empty diaspora_id]
7
+ rule :author, :diaspora_id
8
8
  rule :local, :boolean
9
9
  rule :public, :boolean
10
10
  end
@@ -6,7 +6,7 @@ module DiasporaFederation
6
6
  # @param [Validation::Validator] validator the validator in which it is included
7
7
  def self.included(validator)
8
8
  validator.class_eval do
9
- rule :author, %i[not_empty diaspora_id]
9
+ rule :author, :diaspora_id
10
10
  rule :guid, :guid
11
11
  rule :parent_guid, :guid
12
12
  rule :parent, :not_nil
@@ -1,18 +1,16 @@
1
1
  module DiasporaFederation
2
2
  module Validators
3
3
  # This validates a {Entities::Reshare}.
4
- class ReshareValidator < Validation::Validator
4
+ class ReshareValidator < OptionalAwareValidator
5
5
  include Validation
6
6
 
7
- rule :root_author, %i[not_empty diaspora_id]
7
+ rule :root_author, :diaspora_id
8
8
 
9
9
  rule :root_guid, :guid
10
10
 
11
- rule :author, %i[not_empty diaspora_id]
11
+ rule :author, :diaspora_id
12
12
 
13
13
  rule :guid, :guid
14
-
15
- rule :public, :boolean
16
14
  end
17
15
  end
18
16
  end
@@ -1,10 +1,10 @@
1
1
  module DiasporaFederation
2
2
  module Validators
3
3
  # This validates a {Entities::Retraction}.
4
- class RetractionValidator < Validation::Validator
4
+ class RetractionValidator < OptionalAwareValidator
5
5
  include Validation
6
6
 
7
- rule :author, %i[not_empty diaspora_id]
7
+ rule :author, :diaspora_id
8
8
 
9
9
  rule :target_guid, :guid
10
10
  rule :target_type, :not_empty
@@ -4,24 +4,26 @@ module Validation
4
4
  #
5
5
  # A simple rule to validate the base structure of diaspora* IDs.
6
6
  class DiasporaId
7
+ # Maximum length of a full diaspora* ID
8
+ DIASPORA_ID_MAX_LENGTH = 255
9
+
7
10
  # The Regex for a valid diaspora* ID
8
- DIASPORA_ID = begin
9
- letter = "a-zA-Z"
10
- digit = "0-9"
11
- hexadecimal = "[a-fA-F#{digit}]"
12
- username = "[#{letter}#{digit}\\-\\_\\.]+"
13
- hostname_part = "[#{letter}#{digit}\\-]"
14
- hostname = "#{hostname_part}+([.]#{hostname_part}*)*"
15
- ipv4 = "(?:[#{digit}]{1,3}\\.){3}[#{digit}]{1,3}"
16
- ipv6 = "\\[(?:#{hexadecimal}{0,4}:){0,7}#{hexadecimal}{1,4}\\]"
11
+ DIASPORA_ID_REGEX = begin
12
+ username = "[[:lower:]\\d\\-\\.\\_]+"
13
+ hostname_part = "[[:lower:]\\d\\-]"
14
+ hostname = "#{hostname_part}+(?:[.]#{hostname_part}*)*"
15
+ ipv4 = "(?:[\\d]{1,3}\\.){3}[\\d]{1,3}"
16
+ ipv6 = "\\[(?:[[:xdigit:]]{0,4}:){0,7}[[:xdigit:]]{1,4}\\]"
17
17
  ip_addr = "(?:#{ipv4}|#{ipv6})"
18
18
  domain = "(?:#{hostname}|#{ip_addr})"
19
- port = "(:[#{digit}]+)?"
20
- addr_spec = "(#{username}\\@#{domain}#{port})?"
19
+ port = "(?::[\\d]+)?"
21
20
 
22
- /\A#{addr_spec}\z/u
21
+ "#{username}\\@#{domain}#{port}"
23
22
  end
24
23
 
24
+ # The Regex for validating a full diaspora* ID
25
+ DIASPORA_ID = /\A#{DIASPORA_ID_REGEX}\z/u
26
+
25
27
  # The error key for this rule
26
28
  # @return [Symbol] error key
27
29
  def error_key
@@ -30,7 +32,10 @@ module Validation
30
32
 
31
33
  # Determines if value is a valid diaspora* ID
32
34
  def valid_value?(value)
33
- value.nil? || !DIASPORA_ID.match(value).nil?
35
+ return false unless value.is_a?(String)
36
+ return false if value.length > DIASPORA_ID_MAX_LENGTH
37
+
38
+ value =~ DIASPORA_ID
34
39
  end
35
40
 
36
41
  # This rule has no params.
@@ -6,21 +6,10 @@ module Validation
6
6
  # * Letters: a-z
7
7
  # * Numbers: 0-9
8
8
  # * Special chars: '-', '_', '@', '.' and ':'
9
+ # Special chars aren't allowed at the end.
9
10
  class Guid
10
- # This rule can have a +nilable+ param.
11
- # @return [Hash] params
12
- attr_reader :params
13
-
14
- # Creates a new rule for guid validation
15
- # @param [Hash] params
16
- # @option params [Boolean] :nilable guid allowed to be nil
17
- def initialize(params={})
18
- if params.include?(:nilable) && !params[:nilable].is_a?(TrueClass) && !params[:nilable].is_a?(FalseClass)
19
- raise ArgumentError, ":nilable needs to be a boolean"
20
- end
21
-
22
- @params = params
23
- end
11
+ # Allowed chars to validate a GUID with a regex
12
+ VALID_CHARS = "[0-9A-Za-z\\-_@.:]{15,254}[0-9A-Za-z]".freeze
24
13
 
25
14
  # The error key for this rule
26
15
  # @return [Symbol] error key
@@ -30,7 +19,13 @@ module Validation
30
19
 
31
20
  # Determines if value is a valid +GUID+
32
21
  def valid_value?(value)
33
- params[:nilable] && value.nil? || value.is_a?(String) && value.downcase =~ /\A[0-9a-z\-_@.:]{16,255}\z/
22
+ value.is_a?(String) && value =~ /\A#{VALID_CHARS}\z/
23
+ end
24
+
25
+ # This rule has no params.
26
+ # @return [Hash] params
27
+ def params
28
+ {}
34
29
  end
35
30
  end
36
31
  end
@@ -1,10 +1,10 @@
1
1
  module DiasporaFederation
2
2
  module Validators
3
3
  # This validates a {Entities::StatusMessage}.
4
- class StatusMessageValidator < Validation::Validator
4
+ class StatusMessageValidator < OptionalAwareValidator
5
5
  include Validation
6
6
 
7
- rule :author, %i[not_empty diaspora_id]
7
+ rule :author, :diaspora_id
8
8
 
9
9
  rule :guid, :guid
10
10
 
@@ -4,7 +4,7 @@ module DiasporaFederation
4
4
  #
5
5
  # @note It does not validate the guid and public key, because it will be
6
6
  # removed in the webfinger.
7
- class WebFingerValidator < Validation::Validator
7
+ class WebFingerValidator < OptionalAwareValidator
8
8
  include Validation
9
9
 
10
10
  rule :acct_uri, :not_empty
@@ -1,4 +1,4 @@
1
1
  module DiasporaFederation
2
2
  # the gem version
3
- VERSION = "0.2.1".freeze
3
+ VERSION = "0.2.2".freeze
4
4
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: diaspora_federation
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.1
4
+ version: 0.2.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Benjamin Neff
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-08-07 00:00:00.000000000 Z
11
+ date: 2017-09-23 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: nokogiri
@@ -39,7 +39,7 @@ dependencies:
39
39
  version: 0.9.0
40
40
  - - "<"
41
41
  - !ruby/object:Gem::Version
42
- version: 0.13.0
42
+ version: 0.14.0
43
43
  type: :runtime
44
44
  prerelease: false
45
45
  version_requirements: !ruby/object:Gem::Requirement
@@ -49,7 +49,7 @@ dependencies:
49
49
  version: 0.9.0
50
50
  - - "<"
51
51
  - !ruby/object:Gem::Version
52
- version: 0.13.0
52
+ version: 0.14.0
53
53
  - !ruby/object:Gem::Dependency
54
54
  name: faraday_middleware
55
55
  requirement: !ruby/object:Gem::Requirement
@@ -149,6 +149,7 @@ files:
149
149
  - lib/diaspora_federation/entities/status_message.rb
150
150
  - lib/diaspora_federation/entity.rb
151
151
  - lib/diaspora_federation/federation.rb
152
+ - lib/diaspora_federation/federation/diaspora_url_parser.rb
152
153
  - lib/diaspora_federation/federation/fetcher.rb
153
154
  - lib/diaspora_federation/federation/receiver.rb
154
155
  - lib/diaspora_federation/federation/receiver/abstract_receiver.rb
@@ -186,6 +187,7 @@ files:
186
187
  - lib/diaspora_federation/validators/like_validator.rb
187
188
  - lib/diaspora_federation/validators/location_validator.rb
188
189
  - lib/diaspora_federation/validators/message_validator.rb
190
+ - lib/diaspora_federation/validators/optional_aware_validator.rb
189
191
  - lib/diaspora_federation/validators/participation_validator.rb
190
192
  - lib/diaspora_federation/validators/person_validator.rb
191
193
  - lib/diaspora_federation/validators/photo_validator.rb
@@ -228,7 +230,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
228
230
  version: '0'
229
231
  requirements: []
230
232
  rubyforge_project:
231
- rubygems_version: 2.6.8
233
+ rubygems_version: 2.6.13
232
234
  signing_key:
233
235
  specification_version: 4
234
236
  summary: diaspora* federation library