diaspora_federation 0.0.13 → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +15 -32
- data/lib/diaspora_federation.rb +9 -31
- data/lib/diaspora_federation/discovery/h_card.rb +8 -15
- data/lib/diaspora_federation/discovery/host_meta.rb +2 -4
- data/lib/diaspora_federation/discovery/web_finger.rb +11 -11
- data/lib/diaspora_federation/discovery/xrd_document.rb +4 -8
- data/lib/diaspora_federation/entities.rb +2 -0
- data/lib/diaspora_federation/entities/account_deletion.rb +5 -0
- data/lib/diaspora_federation/entities/comment.rb +3 -6
- data/lib/diaspora_federation/entities/contact.rb +5 -0
- data/lib/diaspora_federation/entities/conversation.rb +10 -1
- data/lib/diaspora_federation/entities/message.rb +29 -4
- data/lib/diaspora_federation/entities/participation.rb +24 -0
- data/lib/diaspora_federation/entities/poll_participation.rb +3 -6
- data/lib/diaspora_federation/entities/profile.rb +5 -0
- data/lib/diaspora_federation/entities/related_entity.rb +33 -0
- data/lib/diaspora_federation/entities/relayable.rb +55 -40
- data/lib/diaspora_federation/entities/relayable_retraction.rb +21 -12
- data/lib/diaspora_federation/entities/request.rb +6 -2
- data/lib/diaspora_federation/entities/reshare.rb +5 -0
- data/lib/diaspora_federation/entities/retraction.rb +37 -0
- data/lib/diaspora_federation/entities/signed_retraction.rb +16 -5
- data/lib/diaspora_federation/entities/status_message.rb +11 -0
- data/lib/diaspora_federation/entity.rb +73 -30
- data/lib/diaspora_federation/federation/fetcher.rb +11 -1
- data/lib/diaspora_federation/federation/receiver.rb +10 -0
- data/lib/diaspora_federation/federation/receiver/abstract_receiver.rb +18 -4
- data/lib/diaspora_federation/federation/receiver/exceptions.rb +4 -0
- data/lib/diaspora_federation/federation/receiver/public.rb +10 -0
- data/lib/diaspora_federation/federation/sender.rb +1 -1
- data/lib/diaspora_federation/http_client.rb +1 -2
- data/lib/diaspora_federation/logging.rb +6 -0
- data/lib/diaspora_federation/properties_dsl.rb +4 -2
- data/lib/diaspora_federation/salmon/encrypted_magic_envelope.rb +2 -2
- data/lib/diaspora_federation/salmon/encrypted_slap.rb +3 -5
- data/lib/diaspora_federation/salmon/exceptions.rb +1 -1
- data/lib/diaspora_federation/salmon/magic_envelope.rb +16 -17
- data/lib/diaspora_federation/salmon/slap.rb +1 -2
- data/lib/diaspora_federation/salmon/xml_payload.rb +1 -2
- data/lib/diaspora_federation/validators.rb +2 -0
- data/lib/diaspora_federation/validators/conversation_validator.rb +2 -0
- data/lib/diaspora_federation/validators/message_validator.rb +2 -2
- data/lib/diaspora_federation/validators/participation_validator.rb +3 -2
- data/lib/diaspora_federation/validators/poll_validator.rb +1 -0
- data/lib/diaspora_federation/validators/related_entity_validator.rb +12 -0
- data/lib/diaspora_federation/validators/relayable_retraction_validator.rb +1 -1
- data/lib/diaspora_federation/validators/relayable_validator.rb +1 -0
- data/lib/diaspora_federation/validators/retraction_validator.rb +1 -1
- data/lib/diaspora_federation/validators/rules/diaspora_id.rb +8 -11
- data/lib/diaspora_federation/validators/rules/diaspora_id_count.rb +1 -1
- data/lib/diaspora_federation/validators/signed_retraction_validator.rb +1 -1
- data/lib/diaspora_federation/validators/status_message_validator.rb +2 -0
- data/lib/diaspora_federation/validators/web_finger_validator.rb +2 -2
- data/lib/diaspora_federation/version.rb +1 -1
- metadata +9 -7
@@ -58,7 +58,7 @@ module DiasporaFederation
|
|
58
58
|
# @param [Hash] data entity data
|
59
59
|
# @return [Hash] hash with resolved aliases
|
60
60
|
def resolv_aliases(data)
|
61
|
-
|
61
|
+
data.map {|name, value|
|
62
62
|
if class_prop_aliases.has_key? name
|
63
63
|
prop_name = class_prop_aliases[name]
|
64
64
|
raise InvalidData, "only use '#{name}' OR '#{prop_name}'" if data.has_key? prop_name
|
@@ -66,7 +66,7 @@ module DiasporaFederation
|
|
66
66
|
else
|
67
67
|
[name, value]
|
68
68
|
end
|
69
|
-
}
|
69
|
+
}.to_h
|
70
70
|
end
|
71
71
|
|
72
72
|
# @return [Symbol] alias for the xml-generation/parsing
|
@@ -144,7 +144,9 @@ module DiasporaFederation
|
|
144
144
|
# @param [Symbol] alias_name alias name
|
145
145
|
def define_alias(name, alias_name)
|
146
146
|
class_prop_aliases[alias_name] = name
|
147
|
+
# rubocop:disable Style/Alias
|
147
148
|
instance_eval { alias_method alias_name, name }
|
149
|
+
# rubocop:enable Style/Alias
|
148
150
|
end
|
149
151
|
|
150
152
|
# Raised, if the name is of an unexpected type
|
@@ -36,7 +36,7 @@ module DiasporaFederation
|
|
36
36
|
key = AES.generate_key_and_iv
|
37
37
|
encrypted_env = AES.encrypt(magic_env.to_xml, key[:key], key[:iv])
|
38
38
|
|
39
|
-
encoded_key =
|
39
|
+
encoded_key = key.map {|k, v| [k, Base64.strict_encode64(v)] }.to_h
|
40
40
|
encrypted_key = Base64.strict_encode64(pubkey.public_encrypt(JSON.generate(encoded_key)))
|
41
41
|
|
42
42
|
JSON.generate(aes_key: encrypted_key, encrypted_magic_envelope: encrypted_env)
|
@@ -51,7 +51,7 @@ module DiasporaFederation
|
|
51
51
|
encrypted_json = JSON.parse(encrypted_env)
|
52
52
|
|
53
53
|
encoded_key = JSON.parse(privkey.private_decrypt(Base64.decode64(encrypted_json["aes_key"])))
|
54
|
-
key =
|
54
|
+
key = encoded_key.map {|k, v| [k, Base64.decode64(v)] }.to_h
|
55
55
|
|
56
56
|
xml = AES.decrypt(encrypted_json["encrypted_magic_envelope"], key["key"], key["iv"])
|
57
57
|
Nokogiri::XML::Document.parse(xml).root
|
@@ -140,7 +140,7 @@ module DiasporaFederation
|
|
140
140
|
# @param [String] data base64 encoded, encrypted header data
|
141
141
|
# @param [OpenSSL::PKey::RSA] privkey private key for decryption
|
142
142
|
# @return [Hash] { iv: "...", aes_key: "...", author_id: "..." }
|
143
|
-
def self.header_data(data, privkey)
|
143
|
+
private_class_method def self.header_data(data, privkey)
|
144
144
|
header_elem = decrypt_header(data, privkey)
|
145
145
|
raise InvalidHeader unless header_elem.name == "decrypted_header"
|
146
146
|
|
@@ -150,20 +150,18 @@ module DiasporaFederation
|
|
150
150
|
|
151
151
|
{iv: iv, aes_key: key, author_id: author_id}
|
152
152
|
end
|
153
|
-
private_class_method :header_data
|
154
153
|
|
155
154
|
# decrypts the xml header
|
156
155
|
# @param [String] data base64 encoded, encrypted header data
|
157
156
|
# @param [OpenSSL::PKey::RSA] privkey private key for decryption
|
158
157
|
# @return [Nokogiri::XML::Element] header xml document
|
159
|
-
def self.decrypt_header(data, privkey)
|
158
|
+
private_class_method def self.decrypt_header(data, privkey)
|
160
159
|
cipher_header = JSON.parse(Base64.decode64(data))
|
161
160
|
key = JSON.parse(privkey.private_decrypt(Base64.decode64(cipher_header["aes_key"])))
|
162
161
|
|
163
162
|
xml = AES.decrypt(cipher_header["ciphertext"], Base64.decode64(key["key"]), Base64.decode64(key["iv"]))
|
164
163
|
Nokogiri::XML::Document.parse(xml).root
|
165
164
|
end
|
166
|
-
private_class_method :decrypt_header
|
167
165
|
|
168
166
|
# encrypt the header xml with an AES cipher and encrypt the cipher params
|
169
167
|
# with the recipients public_key
|
@@ -201,7 +199,7 @@ module DiasporaFederation
|
|
201
199
|
# @param [Hash] hash { key: "...", iv: "..." }
|
202
200
|
# @return [Hash] encoded hash: { key: "...", iv: "..." }
|
203
201
|
def strict_base64_encode(hash)
|
204
|
-
|
202
|
+
hash.map {|k, v| [k, Base64.strict_encode64(v)] }.to_h
|
205
203
|
end
|
206
204
|
end
|
207
205
|
end
|
@@ -15,7 +15,7 @@ module DiasporaFederation
|
|
15
15
|
class MissingHeader < RuntimeError
|
16
16
|
end
|
17
17
|
|
18
|
-
# Raised if the decrypted header has an unexpected XML structure
|
18
|
+
# Raised, if the decrypted header has an unexpected XML structure
|
19
19
|
# @deprecated
|
20
20
|
class InvalidHeader < RuntimeError
|
21
21
|
end
|
@@ -19,8 +19,10 @@ module DiasporaFederation
|
|
19
19
|
# When parsing the XML of an incoming Magic Envelope {MagicEnvelope.unenvelop}
|
20
20
|
# is used.
|
21
21
|
#
|
22
|
-
# @see
|
22
|
+
# @see https://cdn.rawgit.com/salmon-protocol/salmon-protocol/master/draft-panzer-magicsig-01.html
|
23
23
|
class MagicEnvelope
|
24
|
+
include Logging
|
25
|
+
|
24
26
|
# encoding used for the payload data
|
25
27
|
ENCODING = "base64url".freeze
|
26
28
|
|
@@ -123,6 +125,8 @@ module DiasporaFederation
|
|
123
125
|
|
124
126
|
data = read_and_decrypt_data(magic_env, cipher_params)
|
125
127
|
|
128
|
+
logger.debug "unenvelop message from #{sender}:\n#{data}"
|
129
|
+
|
126
130
|
new(XmlPayload.unpack(Nokogiri::XML::Document.parse(data).root), sender)
|
127
131
|
end
|
128
132
|
|
@@ -131,7 +135,9 @@ module DiasporaFederation
|
|
131
135
|
# the payload data as string
|
132
136
|
# @return [String] payload data
|
133
137
|
def payload_data
|
134
|
-
@payload_data ||= XmlPayload.pack(@payload).to_xml.strip
|
138
|
+
@payload_data ||= XmlPayload.pack(@payload).to_xml.strip.tap do |data|
|
139
|
+
logger.debug "send payload:\n#{data}"
|
140
|
+
end
|
135
141
|
end
|
136
142
|
|
137
143
|
def key_id
|
@@ -159,74 +165,67 @@ module DiasporaFederation
|
|
159
165
|
end
|
160
166
|
|
161
167
|
# @param [Nokogiri::XML::Element] env magic envelope XML
|
162
|
-
def self.envelope_valid?(env)
|
168
|
+
private_class_method def self.envelope_valid?(env)
|
163
169
|
(env.instance_of?(Nokogiri::XML::Element) &&
|
164
170
|
env.name == "env" &&
|
165
171
|
!env.at_xpath("me:data").content.empty? &&
|
166
172
|
!env.at_xpath("me:sig").content.empty?)
|
167
173
|
end
|
168
|
-
private_class_method :envelope_valid?
|
169
174
|
|
170
175
|
# @param [Nokogiri::XML::Element] env magic envelope XML
|
171
176
|
# @param [String] sender diaspora-ID of the sender or nil
|
172
177
|
# @return [Boolean]
|
173
|
-
def self.signature_valid?(env, sender)
|
178
|
+
private_class_method def self.signature_valid?(env, sender)
|
174
179
|
subject = sig_subject([Base64.urlsafe_decode64(env.at_xpath("me:data").content),
|
175
180
|
env.at_xpath("me:data")["type"],
|
176
181
|
env.at_xpath("me:encoding").content,
|
177
182
|
env.at_xpath("me:alg").content])
|
178
183
|
|
179
|
-
sender_key = DiasporaFederation.callbacks.trigger(:
|
184
|
+
sender_key = DiasporaFederation.callbacks.trigger(:fetch_public_key, sender)
|
180
185
|
raise SenderKeyNotFound unless sender_key
|
181
186
|
|
182
187
|
sig = Base64.urlsafe_decode64(env.at_xpath("me:sig").content)
|
183
188
|
sender_key.verify(DIGEST, sig, subject)
|
184
189
|
end
|
185
|
-
private_class_method :signature_valid?
|
186
190
|
|
187
191
|
# reads the +key_id+ from the magic envelope
|
188
192
|
# @param [Nokogiri::XML::Element] env magic envelope XML
|
189
193
|
# @return [String] diaspora-ID of the sender
|
190
|
-
def self.sender(env)
|
194
|
+
private_class_method def self.sender(env)
|
191
195
|
key_id = env.at_xpath("me:sig")["key_id"]
|
192
196
|
raise InvalidEnvelope, "no key_id" unless key_id # TODO: move to `envelope_valid?`
|
193
197
|
Base64.urlsafe_decode64(key_id)
|
194
198
|
end
|
195
|
-
private_class_method :sender
|
196
199
|
|
197
200
|
# constructs the signature subject.
|
198
201
|
# the given array should consist of the data, data_type (mimetype), encoding
|
199
202
|
# and the algorithm
|
200
203
|
# @param [Array<String>] data_arr
|
201
204
|
# @return [String] signature subject
|
202
|
-
def self.sig_subject(data_arr)
|
205
|
+
private_class_method def self.sig_subject(data_arr)
|
203
206
|
data_arr.map {|i| Base64.urlsafe_encode64(i) }.join(".")
|
204
207
|
end
|
205
|
-
private_class_method :sig_subject
|
206
208
|
|
207
209
|
# @param [Nokogiri::XML::Element] magic_env magic envelope XML
|
208
210
|
# @return [Boolean]
|
209
|
-
def self.encoding_valid?(magic_env)
|
211
|
+
private_class_method def self.encoding_valid?(magic_env)
|
210
212
|
magic_env.at_xpath("me:encoding").content == ENCODING
|
211
213
|
end
|
212
|
-
private_class_method :encoding_valid?
|
213
214
|
|
214
215
|
# @param [Nokogiri::XML::Element] magic_env magic envelope XML
|
215
216
|
# @return [Boolean]
|
216
|
-
def self.algorithm_valid?(magic_env)
|
217
|
+
private_class_method def self.algorithm_valid?(magic_env)
|
217
218
|
magic_env.at_xpath("me:alg").content == ALGORITHM
|
218
219
|
end
|
219
|
-
private_class_method :algorithm_valid?
|
220
220
|
|
221
221
|
# @param [Nokogiri::XML::Element] magic_env magic envelope XML
|
222
222
|
# @param [Hash] cipher_params hash containing the key and iv
|
223
223
|
# @return [String] data
|
224
|
-
def self.read_and_decrypt_data(magic_env, cipher_params)
|
224
|
+
private_class_method def self.read_and_decrypt_data(magic_env, cipher_params)
|
225
225
|
data = Base64.urlsafe_decode64(magic_env.at_xpath("me:data").content)
|
226
226
|
data = AES.decrypt(data, cipher_params[:key], cipher_params[:iv]) unless cipher_params.nil?
|
227
227
|
data
|
228
228
|
end
|
229
|
-
private_class_method :read_and_decrypt_data
|
230
229
|
end
|
231
230
|
end
|
232
231
|
end
|
@@ -86,12 +86,11 @@ module DiasporaFederation
|
|
86
86
|
# Parses the magic envelop from the document.
|
87
87
|
#
|
88
88
|
# @param [Nokogiri::XML::Document] doc Salmon XML Document
|
89
|
-
def self.magic_env_from_doc(doc)
|
89
|
+
private_class_method def self.magic_env_from_doc(doc)
|
90
90
|
doc.at_xpath("d:diaspora/me:env", Slap::NS).tap do |env|
|
91
91
|
raise MissingMagicEnvelope if env.nil?
|
92
92
|
end
|
93
93
|
end
|
94
|
-
private_class_method :magic_env_from_doc
|
95
94
|
end
|
96
95
|
end
|
97
96
|
end
|
@@ -51,11 +51,10 @@ module DiasporaFederation
|
|
51
51
|
end
|
52
52
|
|
53
53
|
# @param [Nokogiri::XML::Element] element
|
54
|
-
def self.xml_wrapped?(element)
|
54
|
+
private_class_method def self.xml_wrapped?(element)
|
55
55
|
(element.name == "XML" && !element.at_xpath("post").nil? &&
|
56
56
|
!element.at_xpath("post").children.empty?)
|
57
57
|
end
|
58
|
-
private_class_method :xml_wrapped?
|
59
58
|
end
|
60
59
|
end
|
61
60
|
end
|
@@ -4,8 +4,9 @@ module DiasporaFederation
|
|
4
4
|
class ParticipationValidator < Validation::Validator
|
5
5
|
include Validation
|
6
6
|
|
7
|
-
|
8
|
-
|
7
|
+
rule :author, %i(not_empty diaspora_id)
|
8
|
+
rule :guid, :guid
|
9
|
+
rule :parent_guid, :guid
|
9
10
|
rule :parent_type, [:not_empty, regular_expression: {regex: /\APost\z/}]
|
10
11
|
end
|
11
12
|
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
module DiasporaFederation
|
2
|
+
module Validators
|
3
|
+
# This validates a {Entities::RelatedEntity}
|
4
|
+
class RelatedEntityValidator < Validation::Validator
|
5
|
+
include Validation
|
6
|
+
|
7
|
+
rule :author, %i(not_empty diaspora_id)
|
8
|
+
rule :local, :boolean
|
9
|
+
rule :public, :boolean
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
@@ -2,23 +2,20 @@ module Validation
|
|
2
2
|
module Rule
|
3
3
|
# Diaspora ID validation rule
|
4
4
|
#
|
5
|
-
#
|
6
|
-
# which was adapted from https://github.com/emmanuel/aequitas/blob/master/lib/aequitas/rule/format/email_address.rb
|
5
|
+
# A simple rule to validate the base structure of diaspora IDs.
|
7
6
|
class DiasporaId
|
8
7
|
# The Regex for a valid diaspora ID
|
9
8
|
DIASPORA_ID = begin
|
10
9
|
letter = "a-zA-Z"
|
11
10
|
digit = "0-9"
|
11
|
+
hexadecimal = "[a-fA-F#{digit}]"
|
12
12
|
username = "[#{letter}#{digit}\\-\\_\\.]+"
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
dcontent = "(?:#{dtext}|#{quoted_pair})"
|
20
|
-
domain_literal = "\\[#{dcontent}+\\]"
|
21
|
-
domain = "(?:#{dot_atom}|#{domain_literal})"
|
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}\\]"
|
17
|
+
ip_addr = "(?:#{ipv4}|#{ipv6})"
|
18
|
+
domain = "(?:#{hostname}|#{ip_addr})"
|
22
19
|
port = "(:[#{digit}]+)?"
|
23
20
|
addr_spec = "(#{username}\\@#{domain}#{port})?"
|
24
21
|
|
@@ -12,8 +12,8 @@ module DiasporaFederation
|
|
12
12
|
rule :alias_url, URI: %i(host path)
|
13
13
|
rule :hcard_url, [:not_nil, URI: %i(host path)]
|
14
14
|
rule :seed_url, %i(not_nil URI)
|
15
|
-
rule :profile_url,
|
16
|
-
rule :atom_url,
|
15
|
+
rule :profile_url, URI: %i(host path)
|
16
|
+
rule :atom_url, URI: %i(host path)
|
17
17
|
rule :salmon_url, URI: %i(host path)
|
18
18
|
end
|
19
19
|
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.0
|
4
|
+
version: 0.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Benjamin Neff
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-
|
11
|
+
date: 2016-06-26 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: nokogiri
|
@@ -19,7 +19,7 @@ dependencies:
|
|
19
19
|
version: '1.6'
|
20
20
|
- - ">="
|
21
21
|
- !ruby/object:Gem::Version
|
22
|
-
version: 1.6.
|
22
|
+
version: 1.6.8
|
23
23
|
type: :runtime
|
24
24
|
prerelease: false
|
25
25
|
version_requirements: !ruby/object:Gem::Requirement
|
@@ -29,7 +29,7 @@ dependencies:
|
|
29
29
|
version: '1.6'
|
30
30
|
- - ">="
|
31
31
|
- !ruby/object:Gem::Version
|
32
|
-
version: 1.6.
|
32
|
+
version: 1.6.8
|
33
33
|
- !ruby/object:Gem::Dependency
|
34
34
|
name: faraday
|
35
35
|
requirement: !ruby/object:Gem::Requirement
|
@@ -122,6 +122,7 @@ files:
|
|
122
122
|
- lib/diaspora_federation/entities/poll_participation.rb
|
123
123
|
- lib/diaspora_federation/entities/post.rb
|
124
124
|
- lib/diaspora_federation/entities/profile.rb
|
125
|
+
- lib/diaspora_federation/entities/related_entity.rb
|
125
126
|
- lib/diaspora_federation/entities/relayable.rb
|
126
127
|
- lib/diaspora_federation/entities/relayable_retraction.rb
|
127
128
|
- lib/diaspora_federation/entities/request.rb
|
@@ -166,6 +167,7 @@ files:
|
|
166
167
|
- lib/diaspora_federation/validators/poll_participation_validator.rb
|
167
168
|
- lib/diaspora_federation/validators/poll_validator.rb
|
168
169
|
- lib/diaspora_federation/validators/profile_validator.rb
|
170
|
+
- lib/diaspora_federation/validators/related_entity_validator.rb
|
169
171
|
- lib/diaspora_federation/validators/relayable_retraction_validator.rb
|
170
172
|
- lib/diaspora_federation/validators/relayable_validator.rb
|
171
173
|
- lib/diaspora_federation/validators/request_validator.rb
|
@@ -186,7 +188,7 @@ files:
|
|
186
188
|
- lib/tasks/build.rake
|
187
189
|
- lib/tasks/diaspora_federation_tasks.rake
|
188
190
|
- lib/tasks/tests.rake
|
189
|
-
homepage: https://github.com/
|
191
|
+
homepage: https://github.com/diaspora/diaspora_federation
|
190
192
|
licenses:
|
191
193
|
- AGPL 3.0 - http://www.gnu.org/licenses/agpl-3.0.html
|
192
194
|
metadata: {}
|
@@ -198,7 +200,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
198
200
|
requirements:
|
199
201
|
- - "~>"
|
200
202
|
- !ruby/object:Gem::Version
|
201
|
-
version: '2.
|
203
|
+
version: '2.1'
|
202
204
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
203
205
|
requirements:
|
204
206
|
- - ">="
|
@@ -206,7 +208,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
206
208
|
version: '0'
|
207
209
|
requirements: []
|
208
210
|
rubyforge_project:
|
209
|
-
rubygems_version: 2.4.
|
211
|
+
rubygems_version: 2.4.8
|
210
212
|
signing_key:
|
211
213
|
specification_version: 4
|
212
214
|
summary: diaspora* federation library
|