diaspora_federation 0.2.1 → 0.2.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Changelog.md +27 -2
- data/lib/diaspora_federation.rb +16 -0
- data/lib/diaspora_federation/discovery/discovery.rb +23 -8
- data/lib/diaspora_federation/discovery/exceptions.rb +6 -6
- data/lib/diaspora_federation/discovery/web_finger.rb +13 -1
- data/lib/diaspora_federation/discovery/xrd_document.rb +35 -3
- data/lib/diaspora_federation/entities/event.rb +1 -1
- data/lib/diaspora_federation/entities/photo.rb +2 -2
- data/lib/diaspora_federation/entities/post.rb +5 -0
- data/lib/diaspora_federation/entities/profile.rb +4 -1
- data/lib/diaspora_federation/entities/related_entity.rb +8 -0
- data/lib/diaspora_federation/entities/relayable.rb +3 -3
- data/lib/diaspora_federation/entities/reshare.rb +28 -8
- data/lib/diaspora_federation/entities/retraction.rb +1 -1
- data/lib/diaspora_federation/entities/status_message.rb +0 -5
- data/lib/diaspora_federation/entity.rb +4 -1
- data/lib/diaspora_federation/federation.rb +1 -0
- data/lib/diaspora_federation/federation/diaspora_url_parser.rb +34 -0
- data/lib/diaspora_federation/federation/fetcher.rb +23 -11
- data/lib/diaspora_federation/federation/receiver.rb +2 -2
- data/lib/diaspora_federation/federation/receiver/abstract_receiver.rb +6 -1
- data/lib/diaspora_federation/federation/receiver/public.rb +10 -3
- data/lib/diaspora_federation/parsers/base_parser.rb +1 -1
- data/lib/diaspora_federation/properties_dsl.rb +0 -2
- data/lib/diaspora_federation/validators.rb +1 -0
- data/lib/diaspora_federation/validators/account_deletion_validator.rb +2 -2
- data/lib/diaspora_federation/validators/account_migration_validator.rb +2 -2
- data/lib/diaspora_federation/validators/comment_validator.rb +1 -1
- data/lib/diaspora_federation/validators/contact_validator.rb +3 -3
- data/lib/diaspora_federation/validators/conversation_validator.rb +2 -2
- data/lib/diaspora_federation/validators/event_participation_validator.rb +1 -1
- data/lib/diaspora_federation/validators/event_validator.rb +2 -2
- data/lib/diaspora_federation/validators/h_card_validator.rb +1 -1
- data/lib/diaspora_federation/validators/like_validator.rb +1 -1
- data/lib/diaspora_federation/validators/location_validator.rb +1 -1
- data/lib/diaspora_federation/validators/message_validator.rb +2 -2
- data/lib/diaspora_federation/validators/optional_aware_validator.rb +23 -0
- data/lib/diaspora_federation/validators/participation_validator.rb +2 -2
- data/lib/diaspora_federation/validators/person_validator.rb +2 -2
- data/lib/diaspora_federation/validators/photo_validator.rb +3 -3
- data/lib/diaspora_federation/validators/poll_answer_validator.rb +1 -1
- data/lib/diaspora_federation/validators/poll_participation_validator.rb +1 -1
- data/lib/diaspora_federation/validators/poll_validator.rb +1 -1
- data/lib/diaspora_federation/validators/profile_validator.rb +1 -1
- data/lib/diaspora_federation/validators/related_entity_validator.rb +1 -1
- data/lib/diaspora_federation/validators/relayable_validator.rb +1 -1
- data/lib/diaspora_federation/validators/reshare_validator.rb +3 -5
- data/lib/diaspora_federation/validators/retraction_validator.rb +2 -2
- data/lib/diaspora_federation/validators/rules/diaspora_id.rb +18 -13
- data/lib/diaspora_federation/validators/rules/guid.rb +10 -15
- data/lib/diaspora_federation/validators/status_message_validator.rb +2 -2
- data/lib/diaspora_federation/validators/web_finger_validator.rb +1 -1
- data/lib/diaspora_federation/version.rb +1 -1
- metadata +7 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 79f5ac9d463c824a36b9769994431ac6e66625fd
|
4
|
+
data.tar.gz: 270ed5a33de71c405bdcd584c620d3f1d97422c9
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 14ed9bc7669bf07166bebacfe43bbb0cb78821010964181f94f3f395838ba7836755ebdc913048f7455fa6ca6cf0e78e281190ec1f914591c5233a641d986040
|
7
|
+
data.tar.gz: 91b6f07218394e0e066aefd973de6ddc4fa7c0d694c4ee25e53504d15f5371036e8b765f1d911f6008464c9f86e23e66a2a9010c32e3fb4f30da8c064099668e
|
data/Changelog.md
CHANGED
@@ -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
|
|
data/lib/diaspora_federation.rb
CHANGED
@@ -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
|
57
|
-
domain
|
58
|
-
|
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
|
64
|
-
host_meta.webfinger_template_url.gsub("{uri}",
|
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
|
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
|
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 <
|
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 <
|
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
|
-
|
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
|
-
|
89
|
-
|
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
|
-
|
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.
|
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
|
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
|
|
@@ -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
|
-
|
11
|
-
|
12
|
-
)
|
13
|
-
|
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
|
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
|
-
|
10
|
+
validate_public_flag
|
11
11
|
end
|
12
12
|
|
13
|
-
def
|
14
|
-
entity.respond_to?(: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
|
@@ -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
|
@@ -1,10 +1,10 @@
|
|
1
1
|
module DiasporaFederation
|
2
2
|
module Validators
|
3
3
|
# This validates a {Entities::AccountDeletion}.
|
4
|
-
class AccountDeletionValidator <
|
4
|
+
class AccountDeletionValidator < OptionalAwareValidator
|
5
5
|
include Validation
|
6
6
|
|
7
|
-
rule :author,
|
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 <
|
4
|
+
class AccountMigrationValidator < OptionalAwareValidator
|
5
5
|
include Validation
|
6
6
|
|
7
|
-
rule :author,
|
7
|
+
rule :author, :diaspora_id
|
8
8
|
|
9
9
|
rule :profile, :not_nil
|
10
10
|
end
|
@@ -1,11 +1,11 @@
|
|
1
1
|
module DiasporaFederation
|
2
2
|
module Validators
|
3
3
|
# This validates a {Entities::Contact}.
|
4
|
-
class ContactValidator <
|
4
|
+
class ContactValidator < OptionalAwareValidator
|
5
5
|
include Validation
|
6
6
|
|
7
|
-
rule :author,
|
8
|
-
rule :recipient,
|
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 <
|
4
|
+
class ConversationValidator < OptionalAwareValidator
|
5
5
|
include Validation
|
6
6
|
|
7
|
-
rule :author,
|
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 <
|
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 <
|
4
|
+
class EventValidator < OptionalAwareValidator
|
5
5
|
include Validation
|
6
6
|
|
7
|
-
rule :author,
|
7
|
+
rule :author, :diaspora_id
|
8
8
|
|
9
9
|
rule :guid, :guid
|
10
10
|
|
@@ -1,10 +1,10 @@
|
|
1
1
|
module DiasporaFederation
|
2
2
|
module Validators
|
3
3
|
# This validates a {Entities::Message}.
|
4
|
-
class MessageValidator <
|
4
|
+
class MessageValidator < OptionalAwareValidator
|
5
5
|
include Validation
|
6
6
|
|
7
|
-
rule :author,
|
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 <
|
4
|
+
class ParticipationValidator < OptionalAwareValidator
|
5
5
|
include Validation
|
6
6
|
|
7
|
-
rule :author,
|
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 <
|
4
|
+
class PersonValidator < OptionalAwareValidator
|
5
5
|
include Validation
|
6
6
|
|
7
7
|
rule :guid, :guid
|
8
8
|
|
9
|
-
rule :author,
|
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 <
|
4
|
+
class PhotoValidator < OptionalAwareValidator
|
5
5
|
include Validation
|
6
6
|
|
7
7
|
rule :guid, :guid
|
8
8
|
|
9
|
-
rule :author,
|
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
|
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::PollParticipation}.
|
4
|
-
class PollParticipationValidator <
|
4
|
+
class PollParticipationValidator < OptionalAwareValidator
|
5
5
|
include Validation
|
6
6
|
|
7
7
|
include RelayableValidator
|
@@ -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,
|
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 <
|
4
|
+
class ReshareValidator < OptionalAwareValidator
|
5
5
|
include Validation
|
6
6
|
|
7
|
-
rule :root_author,
|
7
|
+
rule :root_author, :diaspora_id
|
8
8
|
|
9
9
|
rule :root_guid, :guid
|
10
10
|
|
11
|
-
rule :author,
|
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 <
|
4
|
+
class RetractionValidator < OptionalAwareValidator
|
5
5
|
include Validation
|
6
6
|
|
7
|
-
rule :author,
|
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
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
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 = "(
|
20
|
-
addr_spec = "(#{username}\\@#{domain}#{port})?"
|
19
|
+
port = "(?::[\\d]+)?"
|
21
20
|
|
22
|
-
|
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.
|
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
|
-
#
|
11
|
-
|
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
|
-
|
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 <
|
4
|
+
class StatusMessageValidator < OptionalAwareValidator
|
5
5
|
include Validation
|
6
6
|
|
7
|
-
rule :author,
|
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 <
|
7
|
+
class WebFingerValidator < OptionalAwareValidator
|
8
8
|
include Validation
|
9
9
|
|
10
10
|
rule :acct_uri, :not_empty
|
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.
|
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-
|
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.
|
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.
|
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.
|
233
|
+
rubygems_version: 2.6.13
|
232
234
|
signing_key:
|
233
235
|
specification_version: 4
|
234
236
|
summary: diaspora* federation library
|