diaspora_federation 0.0.1 → 0.0.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.
@@ -1,12 +1,10 @@
1
1
  module DiasporaFederation
2
- ##
3
- # logging module for the diaspora federation engine
2
+ # logging module for the diaspora federation
4
3
  #
5
4
  # it uses the logging-gem if available
6
5
  module Logging
7
6
  private
8
7
 
9
- ##
10
8
  # get the logger for this class
11
9
  #
12
10
  # use the logging-gem if available, else use a default logger
@@ -17,7 +15,8 @@ module DiasporaFederation
17
15
 
18
16
  # fallback logger
19
17
  @logger = Logger.new(STDOUT)
20
- @logger.level = Logger.const_get(Rails.configuration.log_level.to_s.upcase)
18
+ loglevel = defined?(::Rails) ? ::Rails.configuration.log_level.to_s.upcase : "INFO"
19
+ @logger.level = Logger.const_get(loglevel)
21
20
  @logger
22
21
  end
23
22
  end
@@ -0,0 +1,106 @@
1
+ module DiasporaFederation
2
+ # Provides a simple DSL for specifying {Entity} properties during class
3
+ # definition.
4
+ #
5
+ # @example
6
+ # property :prop
7
+ # property :optional, default: false
8
+ # property :dynamic_default, default: -> { Time.now }
9
+ # entity :nested, NestedEntity
10
+ # entity :multiple, [OtherEntity]
11
+ module PropertiesDSL
12
+ # @return [Array<Hash>] hash of declared entity properties
13
+ def class_props
14
+ @class_props ||= []
15
+ end
16
+
17
+ # Define a generic (string-type) property
18
+ # @param [Symbol] name property name
19
+ # @param [Hash] opts further options
20
+ # @option opts [Object, #call] :default a default value, making the
21
+ # property optional
22
+ def property(name, opts={})
23
+ define_property name, String, opts
24
+ end
25
+
26
+ # Define a property that should contain another Entity or an array of
27
+ # other Entities
28
+ # @param [Symbol] name property name
29
+ # @param [Entity, Array<Entity>] type Entity subclass or
30
+ # Array with exactly one Entity subclass constant inside
31
+ # @param [Hash] opts further options
32
+ # @option opts [Object, #call] :default a default value, making the
33
+ # property optional
34
+ def entity(name, type, opts={})
35
+ raise InvalidType unless type_valid?(type)
36
+
37
+ define_property name, type, opts
38
+ end
39
+
40
+ # Return array of missing required property names
41
+ # @return [Array<Symbol>] missing required property names
42
+ def missing_props(args)
43
+ class_prop_names - default_props.keys - args.keys
44
+ end
45
+
46
+ # Return a new hash of default values, with dynamic values
47
+ # resolved on each call
48
+ # @return [Hash] default values
49
+ def default_values
50
+ default_props.each_with_object({}) { |(name, prop), hash|
51
+ hash[name] = prop.respond_to?(:call) ? prop.call : prop
52
+ }
53
+ end
54
+
55
+ # Returns all nested Entities
56
+ # @return [Array<Hash>] nested properties
57
+ def nested_class_props
58
+ @nested_class_props ||= class_props.select {|p| p[:type] != String }
59
+ end
60
+
61
+ # Returns all property names
62
+ # @return [Array] property names
63
+ def class_prop_names
64
+ @class_prop_names ||= class_props.map {|p| p[:name] }
65
+ end
66
+
67
+ private
68
+
69
+ def define_property(name, type, opts={})
70
+ raise InvalidName unless name_valid?(name)
71
+
72
+ class_props << {name: name, type: type}
73
+ default_props[name] = opts[:default] if opts.has_key? :default
74
+
75
+ instance_eval { attr_reader name }
76
+ end
77
+
78
+ # checks if the name is a +Symbol+ or a +String+
79
+ # @param [String, Symbol] name the name to check
80
+ # @return [Boolean]
81
+ def name_valid?(name)
82
+ name.instance_of?(Symbol) || name.instance_of?(String)
83
+ end
84
+
85
+ # checks if the type extends {Entity}
86
+ # @param [Class] type the type to check
87
+ # @return [Boolean]
88
+ def type_valid?(type)
89
+ [type].flatten.all? { |type|
90
+ type.respond_to?(:ancestors) && type.ancestors.include?(Entity)
91
+ }
92
+ end
93
+
94
+ def default_props
95
+ @default_props ||= {}
96
+ end
97
+
98
+ # Raised, if the name is of an unexpected type
99
+ class InvalidName < RuntimeError
100
+ end
101
+
102
+ # Raised, if the type is of an unexpected type
103
+ class InvalidType < RuntimeError
104
+ end
105
+ end
106
+ end
@@ -1,5 +1,4 @@
1
1
  module DiasporaFederation
2
- ##
3
2
  # the gem version
4
- VERSION = "0.0.1"
3
+ VERSION = "0.0.2"
5
4
  end
@@ -1,5 +1,4 @@
1
1
  module DiasporaFederation
2
- ##
3
2
  # This module provides the namespace for the various classes implementing
4
3
  # WebFinger and other protocols used for metadata discovery on remote servers
5
4
  # in the Diaspora* network.
@@ -1,18 +1,14 @@
1
1
  module DiasporaFederation
2
2
  module WebFinger
3
- ##
4
3
  # Raised, if the XML structure is invalid
5
4
  class InvalidDocument < RuntimeError
6
5
  end
7
6
 
8
- ##
9
7
  # Raised, if something is wrong with the webfinger data
10
8
  #
11
9
  # * if the +webfinger_url+ is missing or malformed in {HostMeta.from_base_url} or {HostMeta.from_xml}
12
- # * if the +data+ given to {WebFinger.from_person} is an invalid type or doesn't contain all required entries
13
10
  # * if the parsed XML from {WebFinger.from_xml} is incomplete
14
- # * if the params passed to {HCard.from_profile} or {HCard.from_html}
15
- # are in some way malformed, invalid or incomplete.
11
+ # * if the html passed to {HCard.from_html} in some way is malformed, invalid or incomplete.
16
12
  class InvalidData < RuntimeError
17
13
  end
18
14
  end
@@ -1,6 +1,5 @@
1
1
  module DiasporaFederation
2
2
  module WebFinger
3
- ##
4
3
  # This class provides the means of generating an parsing account data to and
5
4
  # from the hCard format.
6
5
  # hCard is based on +RFC 2426+ (vCard) which got superseded by +RFC 6350+.
@@ -14,20 +13,20 @@ module DiasporaFederation
14
13
  # correctly nested according to the hCard standard and class names are
15
14
  # partially wrong. Also, apart from that, it's just ugly.
16
15
  #
17
- # @example Creating a hCard document from account data
18
- # hc = HCard.from_profile({
19
- # guid: "0123456789abcdef",
20
- # nickname: "user",
21
- # full_name: "User Name",
22
- # url: "https://server.example/",
23
- # photo_large_url: "https://server.example/uploads/l.jpg",
24
- # photo_medium_url: "https://server.example/uploads/m.jpg",
25
- # photo_small_url: "https://server.example/uploads/s.jpg",
26
- # pubkey: "-----BEGIN PUBLIC KEY-----\nABCDEF==\n-----END PUBLIC KEY-----",
27
- # searchable: true,
28
- # first_name: "User",
29
- # last_name: "Name"
30
- # })
16
+ # @example Creating a hCard document from a person hash
17
+ # hc = HCard.new(
18
+ # guid: "0123456789abcdef",
19
+ # nickname: "user",
20
+ # full_name: "User Name",
21
+ # seed_url: "https://server.example/",
22
+ # photo_large_url: "https://server.example/uploads/l.jpg",
23
+ # photo_medium_url: "https://server.example/uploads/m.jpg",
24
+ # photo_small_url: "https://server.example/uploads/s.jpg",
25
+ # serialized_public_key: "-----BEGIN PUBLIC KEY-----\nABCDEF==\n-----END PUBLIC KEY-----",
26
+ # searchable: true,
27
+ # first_name: "User",
28
+ # last_name: "Name"
29
+ # )
31
30
  # html_string = hc.to_html
32
31
  #
33
32
  # @example Create a HCard instance from an hCard document
@@ -40,65 +39,77 @@ module DiasporaFederation
40
39
  # @see http://microformats.org/wiki/h-card "h-card" (draft)
41
40
  # @see http://www.ietf.org/rfc/rfc2426.txt "vCard MIME Directory Profile" (obsolete)
42
41
  # @see http://www.ietf.org/rfc/rfc6350.txt "vCard Format Specification"
43
- class HCard
44
- private_class_method :new
45
-
46
- # This is just the guid. When a user creates an account on a pod, the pod
47
- # MUST assign them a guid - a random hexadecimal string of at least 8
48
- # hexadecimal digits.
49
- # @return [String] guid
50
- attr_reader :guid
51
-
52
- # the first part of the diaspora handle
53
- # @return [String] nickname
54
- attr_reader :nickname
55
-
56
- # @return [String] display name of the user
57
- attr_reader :full_name
58
-
59
- # @deprecated should be changed to the profile url. The pod url is in
60
- # the WebFinger (see {WebFinger#seed_url}, will affect older Diaspora*
61
- # installations).
42
+ class HCard < Entity
43
+ # @!attribute [r] guid
44
+ # This is just the guid. When a user creates an account on a pod, the pod
45
+ # MUST assign them a guid - a random hexadecimal string of at least 8
46
+ # hexadecimal digits.
47
+ # @return [String] guid
48
+ property :guid
49
+
50
+ # @!attribute [r] nickname
51
+ # the first part of the diaspora handle
52
+ # @return [String] nickname
53
+ property :nickname
54
+
55
+ # @!attribute [r] full_name
56
+ # @return [String] display name of the user
57
+ property :full_name
58
+
59
+ # @!attribute [r] url
60
+ # @deprecated should be changed to the profile url. The pod url is in
61
+ # the WebFinger (see {WebFinger#seed_url}, will affect older Diaspora*
62
+ # installations).
62
63
  #
63
- # @return [String] link to the pod
64
- attr_reader :url
65
-
66
- # When a user is created on the pod, the pod MUST generate a pgp keypair
67
- # for them. This key is used for signing messages. The format is a
68
- # DER-encoded PKCS#1 key beginning with the text
69
- # "-----BEGIN PUBLIC KEY-----" and ending with "-----END PUBLIC KEY-----".
70
- # @return [String] public key
71
- attr_reader :pubkey
72
-
73
- # @return [String] url to the big avatar (300x300)
74
- attr_reader :photo_large_url
75
- # @return [String] url to the medium avatar (100x100)
76
- attr_reader :photo_medium_url
77
- # @return [String] url to the small avatar (50x50)
78
- attr_reader :photo_small_url
79
-
80
- # @deprecated We decided to only use one name field, these should be removed
81
- # in later iterations (will affect older Diaspora* installations).
64
+ # @return [String] link to the pod
65
+ property :url
66
+
67
+ # @!attribute [r] public_key
68
+ # When a user is created on the pod, the pod MUST generate a pgp keypair
69
+ # for them. This key is used for signing messages. The format is a
70
+ # DER-encoded PKCS#1 key beginning with the text
71
+ # "-----BEGIN PUBLIC KEY-----" and ending with "-----END PUBLIC KEY-----".
82
72
  #
83
- # @see #full_name
84
- # @return [String] first name
85
- attr_reader :first_name
73
+ # @note the public key is new in the hcard and is optional now.
74
+ #
75
+ # @return [String] public key
76
+ property :public_key, default: nil
77
+
78
+ # @!attribute [r] photo_large_url
79
+ # @return [String] url to the big avatar (300x300)
80
+ property :photo_large_url
81
+ # @!attribute [r] photo_medium_url
82
+ # @return [String] url to the medium avatar (100x100)
83
+ property :photo_medium_url
84
+ # @!attribute [r] photo_small_url
85
+ # @return [String] url to the small avatar (50x50)
86
+ property :photo_small_url
87
+
88
+ # @!attribute [r] first_name
89
+ # @deprecated We decided to only use one name field, these should be removed
90
+ # in later iterations (will affect older Diaspora* installations).
91
+ #
92
+ # @see #full_name
93
+ # @return [String] first name
94
+ property :first_name
86
95
 
87
- # @deprecated We decided to only use one name field, these should be removed
88
- # in later iterations (will affect older Diaspora* installations).
96
+ # @!attribute [r] last_name
97
+ # @deprecated We decided to only use one name field, these should be removed
98
+ # in later iterations (will affect older Diaspora* installations).
89
99
  #
90
- # @see #full_name
91
- # @return [String] last name
92
- attr_reader :last_name
93
-
94
- # @deprecated As this is a simple property, consider move to WebFinger instead
95
- # of HCard. vCard has no comparable field for this information, but
96
- # Webfinger may declare arbitrary properties (will affect older Diaspora*
97
- # installations).
100
+ # @see #full_name
101
+ # @return [String] last name
102
+ property :last_name
103
+
104
+ # @!attribute [r] searchable
105
+ # @deprecated As this is a simple property, consider move to WebFinger instead
106
+ # of HCard. vCard has no comparable field for this information, but
107
+ # Webfinger may declare arbitrary properties (will affect older Diaspora*
108
+ # installations).
98
109
  #
99
- # flag if a user is searchable by name
100
- # @return [Boolean] searchable flag
101
- attr_reader :searchable
110
+ # flag if a user is searchable by name
111
+ # @return [Boolean] searchable flag
112
+ property :searchable
102
113
 
103
114
  # CSS selectors for finding all the hCard fields
104
115
  SELECTORS = {
@@ -128,7 +139,7 @@ module DiasporaFederation
128
139
  add_simple_property(content, :searchable, "searchable", @searchable)
129
140
 
130
141
  add_property(content, :key) do |html|
131
- html.pre(@pubkey.to_s, class: "key")
142
+ html.pre(@public_key.to_s, class: "key")
132
143
  end
133
144
 
134
145
  # TODO: remove me! ###################
@@ -145,33 +156,6 @@ module DiasporaFederation
145
156
  builder.doc.to_xhtml(indent: 2, indent_text: " ")
146
157
  end
147
158
 
148
- # Creates a new HCard instance from the given Hash containing profile data
149
- # @param [Hash] data account data
150
- # @return [HCard] HCard instance
151
- # @raise [InvalidData] if the account data Hash is invalid or incomplete
152
- def self.from_profile(data)
153
- raise InvalidData unless account_data_complete?(data)
154
-
155
- hc = allocate
156
- hc.instance_eval {
157
- @guid = data[:guid]
158
- @nickname = data[:nickname]
159
- @full_name = data[:full_name]
160
- @url = data[:url]
161
- @photo_large_url = data[:photo_large_url]
162
- @photo_medium_url = data[:photo_medium_url]
163
- @photo_small_url = data[:photo_small_url]
164
- @pubkey = data[:pubkey]
165
- @searchable = data[:searchable]
166
-
167
- # TODO: remove me! ###################
168
- @first_name = data[:first_name]
169
- @last_name = data[:last_name]
170
- #######################################
171
- }
172
- hc
173
- end
174
-
175
159
  # Creates a new HCard instance from the given HTML string.
176
160
  # @param html_string [String] HTML string
177
161
  # @return [HCard] HCard instance
@@ -179,24 +163,24 @@ module DiasporaFederation
179
163
  def self.from_html(html_string)
180
164
  doc = parse_html_and_validate(html_string)
181
165
 
182
- hc = allocate
183
- hc.instance_eval {
184
- @guid = content_from_doc(doc, :uid)
185
- @nickname = content_from_doc(doc, :nickname)
186
- @full_name = content_from_doc(doc, :fn)
187
- @url = element_from_doc(doc, :url)["href"]
188
- @photo_large_url = photo_from_doc(doc, :photo)
189
- @photo_medium_url = photo_from_doc(doc, :photo_medium)
190
- @photo_small_url = photo_from_doc(doc, :photo_small)
191
- @pubkey = content_from_doc(doc, :key) unless element_from_doc(doc, :key).nil?
192
- @searchable = content_from_doc(doc, :searchable) == "true"
166
+ data = {
167
+ guid: content_from_doc(doc, :uid),
168
+ nickname: content_from_doc(doc, :nickname),
169
+ full_name: content_from_doc(doc, :fn),
170
+ url: element_from_doc(doc, :url)["href"],
171
+ photo_large_url: photo_from_doc(doc, :photo),
172
+ photo_medium_url: photo_from_doc(doc, :photo_medium),
173
+ photo_small_url: photo_from_doc(doc, :photo_small),
174
+ searchable: (content_from_doc(doc, :searchable) == "true"),
193
175
 
194
176
  # TODO: change me! ###################
195
- @first_name = content_from_doc(doc, :given_name)
196
- @last_name = content_from_doc(doc, :family_name)
177
+ first_name: content_from_doc(doc, :given_name),
178
+ last_name: content_from_doc(doc, :family_name)
197
179
  #######################################
198
180
  }
199
- hc
181
+ # TODO: public key is new and can be missing
182
+ data[:public_key] = content_from_doc(doc, :key) unless element_from_doc(doc, :key).nil?
183
+ new(data)
200
184
  end
201
185
 
202
186
  private
@@ -271,19 +255,6 @@ module DiasporaFederation
271
255
  end
272
256
  end
273
257
 
274
- # Checks the given account data Hash for correct type and completeness.
275
- # @param [Hash] data account data
276
- # @return [Boolean] validation result
277
- def self.account_data_complete?(data)
278
- data.instance_of?(Hash) &&
279
- %i(
280
- guid nickname full_name url
281
- photo_large_url photo_medium_url photo_small_url
282
- pubkey searchable first_name last_name
283
- ).all? {|k| data.key? k }
284
- end
285
- private_class_method :account_data_complete?
286
-
287
258
  # Make sure some of the most important elements are present in the parsed
288
259
  # HTML document.
289
260
  # @param [LibXML::XML::Document] doc HTML document
@@ -303,17 +274,20 @@ module DiasporaFederation
303
274
  end
304
275
  private_class_method :parse_html_and_validate
305
276
 
306
- def element_from_doc(doc, selector)
277
+ def self.element_from_doc(doc, selector)
307
278
  doc.at_css(SELECTORS[selector])
308
279
  end
280
+ private_class_method :element_from_doc
309
281
 
310
- def content_from_doc(doc, content_selector)
282
+ def self.content_from_doc(doc, content_selector)
311
283
  element_from_doc(doc, content_selector).content
312
284
  end
285
+ private_class_method :content_from_doc
313
286
 
314
- def photo_from_doc(doc, photo_selector)
287
+ def self.photo_from_doc(doc, photo_selector)
315
288
  element_from_doc(doc, photo_selector)["src"]
316
289
  end
290
+ private_class_method :photo_from_doc
317
291
  end
318
292
  end
319
293
  end