diaspora_federation 0.0.3 → 0.0.4
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.
- checksums.yaml +4 -4
- data/README.md +4 -4
- data/lib/diaspora_federation.rb +23 -4
- data/lib/diaspora_federation/discovery.rb +14 -0
- data/lib/diaspora_federation/discovery/discovery.rb +94 -0
- data/lib/diaspora_federation/{web_finger → discovery}/exceptions.rb +5 -1
- data/lib/diaspora_federation/{web_finger → discovery}/h_card.rb +29 -25
- data/lib/diaspora_federation/{web_finger → discovery}/host_meta.rb +13 -13
- data/lib/diaspora_federation/{web_finger → discovery}/web_finger.rb +24 -28
- data/lib/diaspora_federation/{web_finger → discovery}/xrd_document.rb +10 -11
- data/lib/diaspora_federation/entities.rb +12 -0
- data/lib/diaspora_federation/entities/person.rb +33 -0
- data/lib/diaspora_federation/entities/profile.rb +54 -0
- data/lib/diaspora_federation/entity.rb +62 -30
- data/lib/diaspora_federation/fetcher.rb +42 -0
- data/lib/diaspora_federation/logging.rb +4 -2
- data/lib/diaspora_federation/properties_dsl.rb +11 -2
- data/lib/diaspora_federation/validators.rb +38 -0
- data/lib/diaspora_federation/validators/h_card_validator.rb +30 -0
- data/lib/diaspora_federation/validators/person_validator.rb +18 -0
- data/lib/diaspora_federation/validators/profile_validator.rb +33 -0
- data/lib/diaspora_federation/validators/rules/birthday.rb +38 -0
- data/lib/diaspora_federation/validators/rules/boolean.rb +38 -0
- data/lib/diaspora_federation/validators/rules/diaspora_id.rb +46 -0
- data/lib/diaspora_federation/validators/rules/guid.rb +28 -0
- data/lib/diaspora_federation/validators/rules/nilable_uri.rb +19 -0
- data/lib/diaspora_federation/validators/rules/not_nil.rb +23 -0
- data/lib/diaspora_federation/validators/rules/public_key.rb +33 -0
- data/lib/diaspora_federation/validators/rules/tag_count.rb +34 -0
- data/lib/diaspora_federation/validators/web_finger_validator.rb +20 -0
- data/lib/diaspora_federation/version.rb +1 -1
- metadata +82 -8
- data/lib/diaspora_federation/web_finger.rb +0 -13
@@ -1,5 +1,5 @@
|
|
1
1
|
module DiasporaFederation
|
2
|
-
module
|
2
|
+
module Discovery
|
3
3
|
# This class implements basic handling of XRD documents as far as it is
|
4
4
|
# necessary in the context of the protocols used with Diaspora* federation.
|
5
5
|
#
|
@@ -92,19 +92,18 @@ module DiasporaFederation
|
|
92
92
|
# @raise [InvalidDocument] if the XRD is malformed
|
93
93
|
def self.xml_data(xrd_doc)
|
94
94
|
doc = parse_xrd_document(xrd_doc)
|
95
|
-
data = {}
|
96
95
|
|
97
|
-
|
98
|
-
|
96
|
+
{}.tap do |data|
|
97
|
+
exp_elem = doc.at_xpath("xrd:XRD/xrd:Expires", NS)
|
98
|
+
data[:expires] = DateTime.strptime(exp_elem.content, DATETIME_FORMAT) unless exp_elem.nil?
|
99
99
|
|
100
|
-
|
101
|
-
|
100
|
+
subj_elem = doc.at_xpath("xrd:XRD/xrd:Subject", NS)
|
101
|
+
data[:subject] = subj_elem.content unless subj_elem.nil?
|
102
102
|
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
data
|
103
|
+
parse_aliases_from_xml_doc(doc, data)
|
104
|
+
parse_properties_from_xml_doc(doc, data)
|
105
|
+
parse_links_from_xml_doc(doc, data)
|
106
|
+
end
|
108
107
|
end
|
109
108
|
|
110
109
|
private
|
@@ -0,0 +1,12 @@
|
|
1
|
+
module DiasporaFederation
|
2
|
+
# This namespace contains all the entities used to encapsulate data that is
|
3
|
+
# passed around in the Diaspora* network as part of the federation protocol.
|
4
|
+
#
|
5
|
+
# All entities must be defined in this namespace. otherwise the XML
|
6
|
+
# de-serialization will fail.
|
7
|
+
module Entities
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
require "diaspora_federation/entities/profile"
|
12
|
+
require "diaspora_federation/entities/person"
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module DiasporaFederation
|
2
|
+
module Entities
|
3
|
+
# this entity contains the base data of a person
|
4
|
+
#
|
5
|
+
# @see Validators::PersonValidator
|
6
|
+
class Person < Entity
|
7
|
+
# @!attribute [r] guid
|
8
|
+
# @see HCard#guid
|
9
|
+
# @return [String] guid
|
10
|
+
property :guid
|
11
|
+
|
12
|
+
# @!attribute [r] diaspora_id
|
13
|
+
# The diaspora ID of the person
|
14
|
+
# @return [String] diaspora ID
|
15
|
+
property :diaspora_id, xml_name: :diaspora_handle
|
16
|
+
|
17
|
+
# @!attribute [r] url
|
18
|
+
# @see WebFinger#seed_url
|
19
|
+
# @return [String] link to the pod
|
20
|
+
property :url
|
21
|
+
|
22
|
+
# @!attribute [r] profile
|
23
|
+
# all profile data of the person
|
24
|
+
# @return [Profile] the profile of the person
|
25
|
+
entity :profile, Entities::Profile
|
26
|
+
|
27
|
+
# @!attribute [r] exported_key
|
28
|
+
# @see HCard#public_key
|
29
|
+
# @return [String] public key
|
30
|
+
property :exported_key
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
module DiasporaFederation
|
2
|
+
module Entities
|
3
|
+
# this entity contains all the profile data of a person
|
4
|
+
#
|
5
|
+
# @see Validators::ProfileValidator
|
6
|
+
class Profile < Entity
|
7
|
+
# @!attribute [r] diaspora_id
|
8
|
+
# The diaspora ID of the person
|
9
|
+
# @see Person#diaspora_id
|
10
|
+
# @return [String] diaspora ID
|
11
|
+
property :diaspora_id, xml_name: :diaspora_handle
|
12
|
+
|
13
|
+
# @!attribute [r] first_name
|
14
|
+
# @deprecated
|
15
|
+
# @see #full_name
|
16
|
+
# @see HCard#first_name
|
17
|
+
# @return [String] first name
|
18
|
+
property :first_name, default: nil
|
19
|
+
|
20
|
+
# @!attribute [r] last_name
|
21
|
+
# @deprecated
|
22
|
+
# @see #full_name
|
23
|
+
# @see HCard#last_name
|
24
|
+
# @return [String] last name
|
25
|
+
property :last_name, default: nil
|
26
|
+
|
27
|
+
# @!attribute [r] image_url
|
28
|
+
# @see HCard#photo_large_url
|
29
|
+
# @return [String] url to the big avatar (300x300)
|
30
|
+
property :image_url, default: nil
|
31
|
+
# @!attribute [r] image_url_medium
|
32
|
+
# @see HCard#photo_medium_url
|
33
|
+
# @return [String] url to the medium avatar (100x100)
|
34
|
+
property :image_url_medium, default: nil
|
35
|
+
# @!attribute [r] image_url_small
|
36
|
+
# @see HCard#photo_small_url
|
37
|
+
# @return [String] url to the small avatar (50x50)
|
38
|
+
property :image_url_small, default: nil
|
39
|
+
|
40
|
+
property :birthday, default: nil
|
41
|
+
property :gender, default: nil
|
42
|
+
property :bio, default: nil
|
43
|
+
property :location, default: nil
|
44
|
+
|
45
|
+
# @!attribute [r] searchable
|
46
|
+
# @see HCard#searchable
|
47
|
+
# @return [Boolean] searchable flag
|
48
|
+
property :searchable, default: true
|
49
|
+
|
50
|
+
property :nsfw, default: false
|
51
|
+
property :tag_string, default: nil
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -15,6 +15,7 @@ module DiasporaFederation
|
|
15
15
|
# property :prop
|
16
16
|
# property :optional, default: false
|
17
17
|
# property :dynamic_default, default: -> { Time.now }
|
18
|
+
# property :another_prop, xml_name: :another_name
|
18
19
|
# entity :nested, NestedEntity
|
19
20
|
# entity :multiple, [OtherEntity]
|
20
21
|
# end
|
@@ -37,6 +38,12 @@ module DiasporaFederation
|
|
37
38
|
# Initializes the Entity with the given attribute hash and freezes the created
|
38
39
|
# instance it returns.
|
39
40
|
#
|
41
|
+
# After creation, the entity is validated against a Validator, if one is defined.
|
42
|
+
# The Validator needs to be in the {DiasporaFederation::Validators} namespace and
|
43
|
+
# named like "<EntityName>Validator". Only valid entities can be created.
|
44
|
+
#
|
45
|
+
# @see DiasporaFederation::Validators
|
46
|
+
#
|
40
47
|
# @note Attributes not defined as part of the class definition ({PropertiesDSL#property},
|
41
48
|
# {PropertiesDSL#entity}) get discarded silently.
|
42
49
|
#
|
@@ -50,16 +57,18 @@ module DiasporaFederation
|
|
50
57
|
end
|
51
58
|
|
52
59
|
self.class.default_values.merge(data).each do |k, v|
|
53
|
-
instance_variable_set("@#{k}", v) if setable?(k, v)
|
60
|
+
instance_variable_set("@#{k}", nilify(v)) if setable?(k, v)
|
54
61
|
end
|
62
|
+
|
55
63
|
freeze
|
64
|
+
validate
|
56
65
|
end
|
57
66
|
|
58
67
|
# Returns a Hash representing this Entity (attributes => values)
|
59
68
|
# @return [Hash] entity data (mostly equal to the hash used for initialization).
|
60
69
|
def to_h
|
61
70
|
self.class.class_prop_names.each_with_object({}) do |prop, hash|
|
62
|
-
hash[prop] =
|
71
|
+
hash[prop] = public_send(prop)
|
63
72
|
end
|
64
73
|
end
|
65
74
|
|
@@ -76,16 +85,12 @@ module DiasporaFederation
|
|
76
85
|
|
77
86
|
# some of this is from Rails "Inflector.demodulize" and "Inflector.undersore"
|
78
87
|
def self.entity_name
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
word.gsub!(/([a-z\d])([A-Z])/, '\1_\2')
|
86
|
-
word.tr!("-", "_")
|
87
|
-
word.downcase!
|
88
|
-
word
|
88
|
+
name.rpartition("::").last.tap do |word|
|
89
|
+
word.gsub!(/([A-Z\d]+)([A-Z][a-z])/, '\1_\2')
|
90
|
+
word.gsub!(/([a-z\d])([A-Z])/, '\1_\2')
|
91
|
+
word.tr!("-", "_")
|
92
|
+
word.downcase!
|
93
|
+
end
|
89
94
|
end
|
90
95
|
|
91
96
|
private
|
@@ -113,34 +118,61 @@ module DiasporaFederation
|
|
113
118
|
val.all? {|v| v.instance_of?(t.first) })
|
114
119
|
end
|
115
120
|
|
121
|
+
def nilify(value)
|
122
|
+
return nil if value.respond_to?(:empty?) && value.empty?
|
123
|
+
value
|
124
|
+
end
|
125
|
+
|
126
|
+
def validate
|
127
|
+
validator_name = "#{self.class.name.split('::').last}Validator"
|
128
|
+
return unless Validators.const_defined? validator_name
|
129
|
+
|
130
|
+
validator_class = Validators.const_get validator_name
|
131
|
+
validator = validator_class.new self
|
132
|
+
raise ValidationError, error_message(validator) unless validator.valid?
|
133
|
+
end
|
134
|
+
|
135
|
+
def error_message(validator)
|
136
|
+
errors = validator.errors.map do |prop, rule|
|
137
|
+
"property: #{prop}, value: #{public_send(prop).inspect}, rule: #{rule[:rule]}, with params: #{rule[:params]}"
|
138
|
+
end
|
139
|
+
"Failed validation for properties: #{errors.join(' | ')}"
|
140
|
+
end
|
141
|
+
|
116
142
|
# Serialize the Entity into XML elements
|
117
143
|
# @return [Nokogiri::XML::Element] root node
|
118
144
|
def entity_xml
|
119
145
|
doc = Nokogiri::XML::DocumentFragment.new(Nokogiri::XML::Document.new)
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
name = prop_def[:name]
|
124
|
-
type = prop_def[:type]
|
125
|
-
if type == String
|
126
|
-
root_element << simple_node(doc, name)
|
127
|
-
else
|
128
|
-
# call #to_xml for each item and append to root
|
129
|
-
[*send(name)].compact.each do |item|
|
130
|
-
root_element << item.to_xml
|
131
|
-
end
|
146
|
+
Nokogiri::XML::Element.new(self.class.entity_name, doc).tap do |root_element|
|
147
|
+
self.class.class_props.each do |prop_def|
|
148
|
+
add_property_to_xml(doc, prop_def, root_element)
|
132
149
|
end
|
133
150
|
end
|
151
|
+
end
|
134
152
|
|
135
|
-
|
153
|
+
def add_property_to_xml(doc, prop_def, root_element)
|
154
|
+
property = prop_def[:name]
|
155
|
+
type = prop_def[:type]
|
156
|
+
if type == String
|
157
|
+
root_element << simple_node(doc, prop_def[:xml_name], property)
|
158
|
+
else
|
159
|
+
# call #to_xml for each item and append to root
|
160
|
+
[*public_send(property)].compact.each do |item|
|
161
|
+
root_element << item.to_xml
|
162
|
+
end
|
163
|
+
end
|
136
164
|
end
|
137
165
|
|
138
166
|
# create simple node, fill it with text and append to root
|
139
|
-
def simple_node(doc, name)
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
167
|
+
def simple_node(doc, name, property)
|
168
|
+
Nokogiri::XML::Element.new(name.to_s, doc).tap do |node|
|
169
|
+
data = public_send(property).to_s
|
170
|
+
node.content = data unless data.empty?
|
171
|
+
end
|
172
|
+
end
|
173
|
+
|
174
|
+
# Raised, if entity is not valid
|
175
|
+
class ValidationError < RuntimeError
|
144
176
|
end
|
145
177
|
end
|
146
178
|
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
require "faraday"
|
2
|
+
require "faraday_middleware/response/follow_redirects"
|
3
|
+
require "typhoeus/adapters/faraday"
|
4
|
+
|
5
|
+
module DiasporaFederation
|
6
|
+
# A wrapper for {https://github.com/lostisland/faraday Faraday} used for
|
7
|
+
# fetching
|
8
|
+
#
|
9
|
+
# @see Discovery::Discovery
|
10
|
+
class Fetcher
|
11
|
+
# Perform a GET request
|
12
|
+
#
|
13
|
+
# @param [String] uri the URI
|
14
|
+
# @return [Faraday::Response] the response
|
15
|
+
def self.get(uri)
|
16
|
+
connection.get(uri)
|
17
|
+
end
|
18
|
+
|
19
|
+
# gets the Faraday connection
|
20
|
+
#
|
21
|
+
# @return [Faraday::Connection] the response
|
22
|
+
def self.connection
|
23
|
+
create_default_connection unless @connection
|
24
|
+
@connection.dup
|
25
|
+
end
|
26
|
+
|
27
|
+
def self.create_default_connection
|
28
|
+
options = {
|
29
|
+
request: {timeout: 30},
|
30
|
+
ssl: {ca_file: DiasporaFederation.certificate_authorities}
|
31
|
+
}
|
32
|
+
|
33
|
+
@connection = Faraday::Connection.new(options) do |builder|
|
34
|
+
builder.use FaradayMiddleware::FollowRedirects, limit: 4
|
35
|
+
builder.adapter :typhoeus
|
36
|
+
end
|
37
|
+
|
38
|
+
@connection.headers["User-Agent"] = "DiasporaFederation/#{DiasporaFederation::VERSION}"
|
39
|
+
end
|
40
|
+
private_class_method :create_default_connection
|
41
|
+
end
|
42
|
+
end
|
@@ -13,10 +13,12 @@ module DiasporaFederation
|
|
13
13
|
# use logging-gem if available
|
14
14
|
return ::Logging::Logger[self] if defined?(::Logging::Logger)
|
15
15
|
|
16
|
+
# use rails logger if running in rails and no logging-gem is available
|
17
|
+
return ::Rails.logger if defined?(::Rails)
|
18
|
+
|
16
19
|
# fallback logger
|
17
20
|
@logger = Logger.new(STDOUT)
|
18
|
-
|
19
|
-
@logger.level = Logger.const_get(loglevel)
|
21
|
+
@logger.level = Logger::INFO
|
20
22
|
@logger
|
21
23
|
end
|
22
24
|
end
|
@@ -6,6 +6,7 @@ module DiasporaFederation
|
|
6
6
|
# property :prop
|
7
7
|
# property :optional, default: false
|
8
8
|
# property :dynamic_default, default: -> { Time.now }
|
9
|
+
# property :another_prop, xml_name: :another_name
|
9
10
|
# entity :nested, NestedEntity
|
10
11
|
# entity :multiple, [OtherEntity]
|
11
12
|
module PropertiesDSL
|
@@ -19,6 +20,7 @@ module DiasporaFederation
|
|
19
20
|
# @param [Hash] opts further options
|
20
21
|
# @option opts [Object, #call] :default a default value, making the
|
21
22
|
# property optional
|
23
|
+
# @option opts [Symbol] :xml_name another name used for xml generation
|
22
24
|
def property(name, opts={})
|
23
25
|
define_property name, String, opts
|
24
26
|
end
|
@@ -69,7 +71,14 @@ module DiasporaFederation
|
|
69
71
|
def define_property(name, type, opts={})
|
70
72
|
raise InvalidName unless name_valid?(name)
|
71
73
|
|
72
|
-
|
74
|
+
xml_name = name
|
75
|
+
if opts.has_key? :xml_name
|
76
|
+
raise ArgumentError, "xml_name is not supported for nested entities" unless type == String
|
77
|
+
xml_name = opts[:xml_name]
|
78
|
+
raise InvalidName, "invalid xml_name" unless name_valid?(xml_name)
|
79
|
+
end
|
80
|
+
|
81
|
+
class_props << {name: name, xml_name: xml_name, type: type}
|
73
82
|
default_props[name] = opts[:default] if opts.has_key? :default
|
74
83
|
|
75
84
|
instance_eval { attr_reader name }
|
@@ -79,7 +88,7 @@ module DiasporaFederation
|
|
79
88
|
# @param [String, Symbol] name the name to check
|
80
89
|
# @return [Boolean]
|
81
90
|
def name_valid?(name)
|
82
|
-
name.instance_of?(Symbol)
|
91
|
+
name.instance_of?(Symbol)
|
83
92
|
end
|
84
93
|
|
85
94
|
# checks if the type extends {Entity}
|
@@ -0,0 +1,38 @@
|
|
1
|
+
require "validation"
|
2
|
+
require "validation/rule/regular_expression"
|
3
|
+
require "validation/rule/not_empty"
|
4
|
+
require "validation/rule/uri"
|
5
|
+
|
6
|
+
# +valid+ gem namespace
|
7
|
+
module Validation
|
8
|
+
# This module contains custom validation rules for various data field types.
|
9
|
+
# That includes types for which there are no provided rules by the +valid+ gem
|
10
|
+
# or types that are very specific to Diaspora* federation and need special handling.
|
11
|
+
# The rules are used inside the {DiasporaFederation::Validators validator classes}
|
12
|
+
# to perform basic sanity-checks on {DiasporaFederation::Entities federation entities}.
|
13
|
+
module Rule
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
require "diaspora_federation/validators/rules/birthday"
|
18
|
+
require "diaspora_federation/validators/rules/boolean"
|
19
|
+
require "diaspora_federation/validators/rules/diaspora_id"
|
20
|
+
require "diaspora_federation/validators/rules/guid"
|
21
|
+
require "diaspora_federation/validators/rules/nilable_uri"
|
22
|
+
require "diaspora_federation/validators/rules/not_nil"
|
23
|
+
require "diaspora_federation/validators/rules/public_key"
|
24
|
+
require "diaspora_federation/validators/rules/tag_count"
|
25
|
+
|
26
|
+
module DiasporaFederation
|
27
|
+
# Validators to perform basic sanity-checks on {DiasporaFederation::Entities federation entities}.
|
28
|
+
#
|
29
|
+
# The Validators are mapped with the entities by name. The naming schema
|
30
|
+
# is "<EntityName>Validator".
|
31
|
+
module Validators
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
require "diaspora_federation/validators/h_card_validator"
|
36
|
+
require "diaspora_federation/validators/person_validator"
|
37
|
+
require "diaspora_federation/validators/profile_validator"
|
38
|
+
require "diaspora_federation/validators/web_finger_validator"
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module DiasporaFederation
|
2
|
+
module Validators
|
3
|
+
# This validates a {Discovery::HCard}
|
4
|
+
#
|
5
|
+
# @todo activate guid and public key validation after all pod have it in
|
6
|
+
# the hcard.
|
7
|
+
#
|
8
|
+
# @note
|
9
|
+
class HCardValidator < Validation::Validator
|
10
|
+
include Validation
|
11
|
+
|
12
|
+
# rule :guid, :guid
|
13
|
+
|
14
|
+
# the name must not contain a semicolon because of mentions
|
15
|
+
# @{<full_name> ; <diaspora_id>}
|
16
|
+
rule :full_name, regular_expression: {regex: /\A[^;]{,70}\z/}
|
17
|
+
rule :first_name, regular_expression: {regex: /\A[^;]{,32}\z/}
|
18
|
+
rule :last_name, regular_expression: {regex: /\A[^;]{,32}\z/}
|
19
|
+
|
20
|
+
# this urls can be relative
|
21
|
+
rule :photo_large_url, [:not_nil, nilableURI: [:path]]
|
22
|
+
rule :photo_medium_url, [:not_nil, nilableURI: [:path]]
|
23
|
+
rule :photo_small_url, [:not_nil, nilableURI: [:path]]
|
24
|
+
|
25
|
+
# rule :exported_key, :public_key
|
26
|
+
|
27
|
+
rule :searchable, :boolean
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|