ostatus 0.0.7 → 0.0.8
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.
- data/lib/ostatus/activity.rb +14 -2
- data/lib/ostatus/author.rb +2 -0
- data/lib/ostatus/entry.rb +11 -2
- data/lib/ostatus/feed.rb +33 -0
- data/lib/ostatus/salmon.rb +227 -0
- data/lib/ostatus/thread.rb +45 -0
- data/lib/ostatus/version.rb +1 -1
- data/lib/ostatus.rb +2 -0
- data/ostatus.gemspec +0 -1
- data/spec/activity_spec.rb +3 -2
- data/spec/feed_spec.rb +7 -0
- data/test/example_feed.atom +34 -1
- data/test/example_page.html +4 -0
- metadata +10 -19
data/lib/ostatus/activity.rb
CHANGED
@@ -35,7 +35,13 @@ module OStatus
|
|
35
35
|
@entry[:object]
|
36
36
|
else
|
37
37
|
obj = @entry.activity_verb
|
38
|
-
|
38
|
+
if obj.nil?
|
39
|
+
nil
|
40
|
+
elsif obj.start_with?(SCHEMA_ROOT)
|
41
|
+
obj[SCHEMA_ROOT.size..-1].intern unless obj.nil?
|
42
|
+
else
|
43
|
+
obj
|
44
|
+
end
|
39
45
|
end
|
40
46
|
end
|
41
47
|
|
@@ -48,7 +54,13 @@ module OStatus
|
|
48
54
|
@entry[:object_type]
|
49
55
|
else
|
50
56
|
obj = @entry.activity_object_type
|
51
|
-
|
57
|
+
if obj.nil?
|
58
|
+
nil
|
59
|
+
elsif obj.start_with?(SCHEMA_ROOT)
|
60
|
+
obj[SCHEMA_ROOT.size..-1].intern unless obj.nil?
|
61
|
+
else
|
62
|
+
obj
|
63
|
+
end
|
52
64
|
end
|
53
65
|
end
|
54
66
|
|
data/lib/ostatus/author.rb
CHANGED
data/lib/ostatus/entry.rb
CHANGED
@@ -1,7 +1,9 @@
|
|
1
1
|
require_relative 'activity'
|
2
2
|
require_relative 'author'
|
3
|
+
require_relative 'thread'
|
3
4
|
|
4
5
|
module OStatus
|
6
|
+
THREAD_NS = 'http://purl.org/syndication/thread/1.0'
|
5
7
|
|
6
8
|
# Holds information about an individual entry in the Feed.
|
7
9
|
class Entry < Atom::Entry
|
@@ -9,10 +11,18 @@ module OStatus
|
|
9
11
|
|
10
12
|
add_extension_namespace :activity, ACTIVITY_NS
|
11
13
|
element 'activity:object-type'
|
12
|
-
element 'activity:object'
|
14
|
+
element 'activity:object', :class => OStatus::Author
|
13
15
|
element 'activity:verb'
|
14
16
|
element 'activity:target'
|
15
17
|
|
18
|
+
add_extension_namespace :thr, THREAD_NS
|
19
|
+
element 'thr:in-reply-to', :class => OStatus::Thread
|
20
|
+
|
21
|
+
# This is for backwards compatibility with some implementations of Activity
|
22
|
+
# Streams. It should not be used, and in fact is obscured as it is not a
|
23
|
+
# method in OStatus::Activity.
|
24
|
+
element 'activity:actor', :class => OStatus::Author
|
25
|
+
|
16
26
|
namespace Atom::NAMESPACE
|
17
27
|
element :title, :id, :summary
|
18
28
|
element :updated, :published, :class => DateTime, :content_only => true
|
@@ -35,7 +45,6 @@ module OStatus
|
|
35
45
|
self.activity_verb = OStatus::Activity::SCHEMA_ROOT + value.activity_verb.to_s
|
36
46
|
end
|
37
47
|
self.activity_target = value.activity_target if value.target
|
38
|
-
activity_object_type = "HEY"
|
39
48
|
end
|
40
49
|
|
41
50
|
def url
|
data/lib/ostatus/feed.rb
CHANGED
@@ -25,6 +25,11 @@ module OStatus
|
|
25
25
|
|
26
26
|
attr_reader :url
|
27
27
|
|
28
|
+
# Store in reverse order so that the -1 from .index "not found"
|
29
|
+
# will sort properly
|
30
|
+
MIME_ORDER = ['application/atom+xml', 'application/rss+xml',
|
31
|
+
'application/xml'].reverse
|
32
|
+
|
28
33
|
def initialize(str, url, access_token, options)
|
29
34
|
@str = str
|
30
35
|
@url = url
|
@@ -32,6 +37,34 @@ module OStatus
|
|
32
37
|
@options = options
|
33
38
|
|
34
39
|
if str
|
40
|
+
|
41
|
+
if str =~ /<html/
|
42
|
+
doc = LibXML::XML::HTMLParser.string(str).parse
|
43
|
+
links = doc.find(
|
44
|
+
"//*[contains(concat(' ',normalize-space(@rel),' '), 'alternate')]"
|
45
|
+
).map {|el|
|
46
|
+
{:type => el.attributes['type'].to_s,
|
47
|
+
:href => el.attributes['href'].to_s}
|
48
|
+
}.sort {|a, b|
|
49
|
+
MIME_ORDER.index(b[:type]) <=> MIME_ORDER.index(a[:type])
|
50
|
+
}
|
51
|
+
|
52
|
+
# Resolve relative links
|
53
|
+
link = URI::parse(links.first[:href]) rescue URI.new
|
54
|
+
|
55
|
+
unless link.host
|
56
|
+
link.host = URI::parse(@url).host rescue nil
|
57
|
+
end
|
58
|
+
|
59
|
+
unless link.absolute?
|
60
|
+
link.path = File::dirname(URI::parse(@url).path) \
|
61
|
+
+ '/' + link.path rescue nil
|
62
|
+
end
|
63
|
+
|
64
|
+
@url = link.to_s
|
65
|
+
@str = str = open(@url).read
|
66
|
+
end
|
67
|
+
|
35
68
|
super(XML::Reader.string(str))
|
36
69
|
else
|
37
70
|
super(options)
|
@@ -0,0 +1,227 @@
|
|
1
|
+
require 'xml'
|
2
|
+
require 'atom'
|
3
|
+
require 'digest/sha2'
|
4
|
+
require 'rsa'
|
5
|
+
|
6
|
+
module OStatus
|
7
|
+
class Salmon
|
8
|
+
attr_accessor :entry
|
9
|
+
|
10
|
+
# Create a Salmon instance for a particular OStatus::Entry
|
11
|
+
def initialize entry, signature = nil, plaintext = nil
|
12
|
+
@entry = entry
|
13
|
+
@signature = signature
|
14
|
+
@plaintext = plaintext
|
15
|
+
end
|
16
|
+
|
17
|
+
# Creates an entry for following a particular Author.
|
18
|
+
def Salmon.from_follow(user_author, followed_author)
|
19
|
+
entry = OStatus::Entry.new(
|
20
|
+
:author => user_author,
|
21
|
+
:title => "Now following #{followed_author.name}",
|
22
|
+
:content => Atom::Content::Html.new("Now following #{followed_author.name}")
|
23
|
+
)
|
24
|
+
|
25
|
+
entry.activity_verb = :follow
|
26
|
+
entry.activity_object = followed_author
|
27
|
+
|
28
|
+
OStatus::Salmon.new(entry)
|
29
|
+
end
|
30
|
+
|
31
|
+
# Creates an entry for unfollowing a particular Author.
|
32
|
+
def Salmon.from_unfollow(user_author, followed_author)
|
33
|
+
entry = OStatus::Entry.new(
|
34
|
+
:author => user_author,
|
35
|
+
:title => "Stopped following #{followed_author.name}",
|
36
|
+
:content => Atom::Content::Html.new("Stopped following #{followed_author.name}")
|
37
|
+
)
|
38
|
+
|
39
|
+
entry.activity_verb = "http://ostatus.org/schema/1.0/unfollow"
|
40
|
+
entry.activity_object = followed_author
|
41
|
+
|
42
|
+
OStatus::Salmon.new(entry)
|
43
|
+
end
|
44
|
+
|
45
|
+
# Will pull a OStatus::Entry from a magic envelope described by the xml.
|
46
|
+
def Salmon.from_xml source
|
47
|
+
if source.is_a?(String)
|
48
|
+
source = XML::Document.string(source,
|
49
|
+
:options => XML::Parser::Options::NOENT)
|
50
|
+
end
|
51
|
+
|
52
|
+
# Retrieve the envelope
|
53
|
+
envelope = source.find('/me:env',
|
54
|
+
'me:http://salmon-protocol.org/ns/magic-env').first
|
55
|
+
|
56
|
+
if envelope.nil?
|
57
|
+
return nil
|
58
|
+
end
|
59
|
+
|
60
|
+
data = envelope.find('me:data',
|
61
|
+
'me:http://salmon-protocol.org/ns/magic-env').first
|
62
|
+
if data.nil?
|
63
|
+
return nil
|
64
|
+
end
|
65
|
+
|
66
|
+
data_type = data.attributes["type"]
|
67
|
+
if data_type.nil?
|
68
|
+
data_type = 'application/atom+xml'
|
69
|
+
armored_data_type = ''
|
70
|
+
else
|
71
|
+
armored_data_type = Base64::urlsafe_encode64(data_type)
|
72
|
+
end
|
73
|
+
|
74
|
+
encoding = envelope.find('me:encoding',
|
75
|
+
'me:http://salmon-protocol.org/ns/magic-env').first
|
76
|
+
|
77
|
+
algorithm = envelope.find(
|
78
|
+
'me:alg',
|
79
|
+
'me:http://salmon-protocol.org/ns/magic-env').first
|
80
|
+
|
81
|
+
signature = source.find('me:sig',
|
82
|
+
'me:http://salmon-protocol.org/ns/magic-env').first
|
83
|
+
|
84
|
+
# Parse fields
|
85
|
+
|
86
|
+
if signature.nil?
|
87
|
+
# Well, if we cannot verify, we don't accept
|
88
|
+
return nil
|
89
|
+
else
|
90
|
+
# XXX: Handle key_id attribute
|
91
|
+
signature = signature.content
|
92
|
+
signature = Base64::urlsafe_decode64(signature)
|
93
|
+
end
|
94
|
+
|
95
|
+
if encoding.nil?
|
96
|
+
# When the encoding is omitted, use base64url
|
97
|
+
# Cite: Magic Envelope Draft Spec Section 3.3
|
98
|
+
armored_encoding = ''
|
99
|
+
encoding = 'base64url'
|
100
|
+
else
|
101
|
+
armored_encoding = Base64::urlsafe_encode64(encoding.content)
|
102
|
+
encoding = encoding.content.downcase
|
103
|
+
end
|
104
|
+
|
105
|
+
if algorithm.nil?
|
106
|
+
# When algorithm is omitted, use 'RSA-SHA256'
|
107
|
+
# Cite: Magic Envelope Draft Spec Section 3.3
|
108
|
+
armored_algorithm = ''
|
109
|
+
algorithm = 'rsa-sha256'
|
110
|
+
else
|
111
|
+
armored_algorithm = Base64::urlsafe_encode64(algorithm.content)
|
112
|
+
algorithm = algorithm.content.downcase
|
113
|
+
end
|
114
|
+
|
115
|
+
# Retrieve and decode data payload
|
116
|
+
|
117
|
+
data = data.content
|
118
|
+
armored_data = data
|
119
|
+
|
120
|
+
case encoding
|
121
|
+
when 'base64url'
|
122
|
+
data = Base64::urlsafe_decode64(data)
|
123
|
+
else
|
124
|
+
# Unsupported data encoding
|
125
|
+
return nil
|
126
|
+
end
|
127
|
+
|
128
|
+
# Signature plaintext
|
129
|
+
plaintext = "#{armored_data}.#{armored_data_type}.#{armored_encoding}.#{armored_algorithm}"
|
130
|
+
|
131
|
+
# Interpret data payload
|
132
|
+
payload = XML::Reader.string(data)
|
133
|
+
Salmon.new OStatus::Entry.new(payload), signature, plaintext
|
134
|
+
end
|
135
|
+
|
136
|
+
# Generate the xml for this Salmon notice and sign with the given private
|
137
|
+
# key.
|
138
|
+
def to_xml key
|
139
|
+
# Generate magic envelope
|
140
|
+
magic_envelope = XML::Document.new
|
141
|
+
|
142
|
+
magic_envelope.root = XML::Node.new 'env'
|
143
|
+
|
144
|
+
me_ns = XML::Namespace.new(magic_envelope.root,
|
145
|
+
'me', 'http://salmon-protocol.org/ns/magic-env')
|
146
|
+
|
147
|
+
magic_envelope.root.namespaces.namespace = me_ns
|
148
|
+
|
149
|
+
# Armored Data <me:data>
|
150
|
+
data = @entry.to_xml
|
151
|
+
@plaintext = data
|
152
|
+
data_armored = Base64::urlsafe_encode64(data)
|
153
|
+
elem = XML::Node.new 'data', data_armored, me_ns
|
154
|
+
elem.attributes['type'] = 'application/atom+xml'
|
155
|
+
data_type_armored = 'YXBwbGljYXRpb24vYXRvbSt4bWw='
|
156
|
+
magic_envelope.root << elem
|
157
|
+
|
158
|
+
# Encoding <me:encoding>
|
159
|
+
magic_envelope.root << XML::Node.new('encoding', 'base64url', me_ns)
|
160
|
+
encoding_armored = 'YmFzZTY0dXJs'
|
161
|
+
|
162
|
+
# Signing Algorithm <me:alg>
|
163
|
+
magic_envelope.root << XML::Node.new('alg', 'RSA-SHA256', me_ns)
|
164
|
+
algorithm_armored = 'UlNBLVNIQTI1Ng=='
|
165
|
+
|
166
|
+
# Signature <me:sig>
|
167
|
+
plaintext = "#{data_armored}.#{data_type_armored}.#{encoding_armored}.#{algorithm_armored}"
|
168
|
+
|
169
|
+
# Assign @signature to the signature generated from the plaintext
|
170
|
+
sign(plaintext, key)
|
171
|
+
|
172
|
+
signature_armored = Base64::urlsafe_encode64(@signature)
|
173
|
+
magic_envelope.root << XML::Node.new('sig', signature_armored, me_ns)
|
174
|
+
|
175
|
+
magic_envelope.to_s :indent => true, :encoding => XML::Encoding::UTF_8
|
176
|
+
end
|
177
|
+
|
178
|
+
# Return the EMSA string for this Salmon instance given the size of the
|
179
|
+
# public key modulus.
|
180
|
+
def signature modulus_byte_length
|
181
|
+
plaintext = Digest::SHA2.new(256).digest(@plaintext)
|
182
|
+
|
183
|
+
prefix = "\x30\x31\x30\x0d\x06\x09\x60\x86\x48\x01\x65\x03\x04\x02\x01\x05\x00\x04\x20"
|
184
|
+
padding_count = modulus_byte_length - prefix.bytes.count - plaintext.bytes.count - 3
|
185
|
+
|
186
|
+
padding = ""
|
187
|
+
padding_count.times do
|
188
|
+
padding = padding + "\xff"
|
189
|
+
end
|
190
|
+
|
191
|
+
"\x00\x01#{padding}\x00#{prefix}#{plaintext}"
|
192
|
+
end
|
193
|
+
|
194
|
+
def sign message, key
|
195
|
+
@plaintext = message
|
196
|
+
|
197
|
+
modulus_byte_count = key.private_key.modulus.size
|
198
|
+
|
199
|
+
@signature = signature(modulus_byte_count)
|
200
|
+
@signature = key.decrypt(@signature)
|
201
|
+
end
|
202
|
+
|
203
|
+
# Use RSA to verify the signature
|
204
|
+
# key - RSA::KeyPair with the public key to use
|
205
|
+
def verified? key
|
206
|
+
# RSA encryption is needed to compare the signatures
|
207
|
+
|
208
|
+
# Get signature to check
|
209
|
+
emsa = self.signature key.public_key.modulus.size
|
210
|
+
|
211
|
+
# Get signature in payload
|
212
|
+
emsa_signature = key.encrypt(@signature)
|
213
|
+
|
214
|
+
# RSA gem drops leading 0s since it does math upon an Integer
|
215
|
+
# As a workaround, I check for what I expect the second byte to be (\x01)
|
216
|
+
# This workaround will also handle seeing a \x00 first if the RSA gem is
|
217
|
+
# fixed.
|
218
|
+
if emsa_signature.getbyte(0) == 1
|
219
|
+
emsa_signature = "\x00#{emsa_signature}"
|
220
|
+
end
|
221
|
+
|
222
|
+
# Does the signature match?
|
223
|
+
# Return the result.
|
224
|
+
emsa_signature == emsa
|
225
|
+
end
|
226
|
+
end
|
227
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
require 'xml/libxml'
|
2
|
+
require 'atom/xml/parser.rb'
|
3
|
+
|
4
|
+
module OStatus
|
5
|
+
|
6
|
+
# This will parse the Thread Atom extension
|
7
|
+
class Thread
|
8
|
+
include Atom::Xml::Parseable
|
9
|
+
attribute :ref, :type, :source
|
10
|
+
uri_attribute :href
|
11
|
+
|
12
|
+
def initialize(o)
|
13
|
+
case o
|
14
|
+
when XML::Reader
|
15
|
+
if current_node_is?(o, 'in-reply-to')
|
16
|
+
parse(o, :once => true)
|
17
|
+
else
|
18
|
+
raise ArgumentError, "Thread created with node other than thr:in-reply-to: #{o.name}"
|
19
|
+
end
|
20
|
+
when Hash
|
21
|
+
[:href, :ref, :type, :source].each do |attr|
|
22
|
+
self.send("#{attr}=", o[attr])
|
23
|
+
end
|
24
|
+
else
|
25
|
+
raise ArgumentError, "Don't know how to handle #{o}"
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def length=(v)
|
30
|
+
@length = v.to_i
|
31
|
+
end
|
32
|
+
|
33
|
+
def to_s
|
34
|
+
self.href
|
35
|
+
end
|
36
|
+
|
37
|
+
def ==(o)
|
38
|
+
o.respond_to?(:href) && o.href == self.href
|
39
|
+
end
|
40
|
+
|
41
|
+
def inspect
|
42
|
+
"<OStatus::Thread href:'#{href}' type:'#{type}'>"
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
data/lib/ostatus/version.rb
CHANGED
data/lib/ostatus.rb
CHANGED
data/ostatus.gemspec
CHANGED
data/spec/activity_spec.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
require_relative '../lib/ostatus/feed.rb'
|
2
2
|
require_relative '../lib/ostatus/entry.rb'
|
3
3
|
require_relative '../lib/ostatus/activity.rb'
|
4
|
+
require_relative '../lib/ostatus/author.rb'
|
4
5
|
|
5
6
|
describe OStatus::Activity do
|
6
7
|
before(:each) do
|
@@ -12,8 +13,8 @@ describe OStatus::Activity do
|
|
12
13
|
end
|
13
14
|
|
14
15
|
describe "#object" do
|
15
|
-
it "should give
|
16
|
-
@activity.object.should eql(
|
16
|
+
it "should give an Author containing the content of the activity:object tag" do
|
17
|
+
@activity.object.class.should eql(OStatus::Author)
|
17
18
|
end
|
18
19
|
|
19
20
|
it "should give nil when no activity:object was given" do
|
data/spec/feed_spec.rb
CHANGED
@@ -6,6 +6,13 @@ describe OStatus::Feed do
|
|
6
6
|
@feed = OStatus::Feed.from_url('test/example_feed.atom')
|
7
7
|
end
|
8
8
|
|
9
|
+
describe "#initialize" do
|
10
|
+
it "should detect a feed URI in an HTML page" do
|
11
|
+
@feed = OStatus::Feed.from_url('test/example_page.html')
|
12
|
+
@feed.url.should == 'test/example_feed.atom'
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
9
16
|
describe "#atom" do
|
10
17
|
it "should return a String containing the atom information" do
|
11
18
|
@feed.atom.start_with?("<?xml").should eql(true)
|
data/test/example_feed.atom
CHANGED
@@ -71,7 +71,40 @@ bar</poco:note>
|
|
71
71
|
<link href="http://identi.ca/api/statuses/user_timeline/141464.atom" rel="self" type="application/atom+xml"/>
|
72
72
|
<entry>
|
73
73
|
<activity:object-type>http://activitystrea.ms/schema/1.0/note</activity:object-type>
|
74
|
-
<activity:object>
|
74
|
+
<activity:object>
|
75
|
+
<activity:object-type>http://activitystrea.ms/schema/1.0/person</activity:object-type>
|
76
|
+
<uri>http://identi.ca/user/141464</uri>
|
77
|
+
<name>greenmanspirit</name>
|
78
|
+
<email>foo@example.com</email>
|
79
|
+
<link rel="alternate" type="text/html" href="http://identi.ca/greenmanspirit"/>
|
80
|
+
<link rel="avatar" type="image/jpeg" media:width="480" media:height="480" href="http://avatar.identi.ca/141464-480-20100607212940.jpeg"/>
|
81
|
+
<link rel="avatar" type="image/jpeg" media:width="96" media:height="96" href="http://avatar.identi.ca/141464-96-20100607212940.jpeg"/>
|
82
|
+
<link rel="avatar" type="image/jpeg" media:width="48" media:height="48" href="http://avatar.identi.ca/141464-48-20100607212940.jpeg"/>
|
83
|
+
<link rel="avatar" type="image/jpeg" media:width="24" media:height="24" href="http://avatar.identi.ca/141464-24-20100607212940.jpeg"/>
|
84
|
+
<georss:point>0 0</georss:point>
|
85
|
+
<poco:preferredUsername>greenmanspirit</poco:preferredUsername>
|
86
|
+
<poco:displayName>Adam Hobaugh</poco:displayName>
|
87
|
+
<poco:id>foobar</poco:id>
|
88
|
+
<poco:name>barbaz</poco:name>
|
89
|
+
<poco:nickname>spaz</poco:nickname>
|
90
|
+
<poco:published>2012-02-21T02:15:14+00:00</poco:published>
|
91
|
+
<poco:updated>2013-02-21T02:15:14+00:00</poco:updated>
|
92
|
+
<poco:birthday>2014-02-21</poco:birthday>
|
93
|
+
<poco:anniversary>2015-02-21</poco:anniversary>
|
94
|
+
<poco:gender>male</poco:gender>
|
95
|
+
<poco:note>foo
|
96
|
+
bar</poco:note>
|
97
|
+
<poco:utcOffset>-08:00</poco:utcOffset>
|
98
|
+
<poco:connected>true</poco:connected>
|
99
|
+
<poco:urls>
|
100
|
+
<poco:type>homepage</poco:type>
|
101
|
+
<poco:value>http://adamhobaugh.com</poco:value>
|
102
|
+
<poco:primary>true</poco:primary>
|
103
|
+
</poco:urls>
|
104
|
+
|
105
|
+
<statusnet:profile_info local_id="141464"></statusnet:profile_info>
|
106
|
+
</activity:object>
|
107
|
+
|
75
108
|
<activity:target>Barbaz</activity:target>
|
76
109
|
<id>http://identi.ca/notice/64991641</id>
|
77
110
|
<title>staples come out of the head tomorrow, oh yeah</title>
|
metadata
CHANGED
@@ -5,8 +5,8 @@ version: !ruby/object:Gem::Version
|
|
5
5
|
segments:
|
6
6
|
- 0
|
7
7
|
- 0
|
8
|
-
-
|
9
|
-
version: 0.0.
|
8
|
+
- 8
|
9
|
+
version: 0.0.8
|
10
10
|
platform: ruby
|
11
11
|
authors:
|
12
12
|
- Hackers of the Severed Hand
|
@@ -14,11 +14,11 @@ autorequire:
|
|
14
14
|
bindir: bin
|
15
15
|
cert_chain: []
|
16
16
|
|
17
|
-
date: 2011-
|
17
|
+
date: 2011-05-20 00:00:00 -04:00
|
18
18
|
default_executable:
|
19
19
|
dependencies:
|
20
20
|
- !ruby/object:Gem::Dependency
|
21
|
-
name:
|
21
|
+
name: ratom
|
22
22
|
prerelease: false
|
23
23
|
requirement: &id001 !ruby/object:Gem::Requirement
|
24
24
|
none: false
|
@@ -30,23 +30,10 @@ dependencies:
|
|
30
30
|
version: "0"
|
31
31
|
type: :runtime
|
32
32
|
version_requirements: *id001
|
33
|
-
- !ruby/object:Gem::Dependency
|
34
|
-
name: ratom
|
35
|
-
prerelease: false
|
36
|
-
requirement: &id002 !ruby/object:Gem::Requirement
|
37
|
-
none: false
|
38
|
-
requirements:
|
39
|
-
- - ">="
|
40
|
-
- !ruby/object:Gem::Version
|
41
|
-
segments:
|
42
|
-
- 0
|
43
|
-
version: "0"
|
44
|
-
type: :runtime
|
45
|
-
version_requirements: *id002
|
46
33
|
- !ruby/object:Gem::Dependency
|
47
34
|
name: rspec
|
48
35
|
prerelease: false
|
49
|
-
requirement: &
|
36
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
50
37
|
none: false
|
51
38
|
requirements:
|
52
39
|
- - ">="
|
@@ -55,7 +42,7 @@ dependencies:
|
|
55
42
|
- 0
|
56
43
|
version: "0"
|
57
44
|
type: :development
|
58
|
-
version_requirements: *
|
45
|
+
version_requirements: *id002
|
59
46
|
description: This project is to be used to jumpstart OStatus related projects that implement the PubSubHubbub protocols by providing the common fundamentals of Atom parsing and OStatus object creation.
|
60
47
|
email:
|
61
48
|
- hotsh@xomb.org
|
@@ -76,6 +63,8 @@ files:
|
|
76
63
|
- lib/ostatus/entry.rb
|
77
64
|
- lib/ostatus/feed.rb
|
78
65
|
- lib/ostatus/portable_contacts.rb
|
66
|
+
- lib/ostatus/salmon.rb
|
67
|
+
- lib/ostatus/thread.rb
|
79
68
|
- lib/ostatus/version.rb
|
80
69
|
- ostatus.gemspec
|
81
70
|
- spec/activity_spec.rb
|
@@ -87,6 +76,7 @@ files:
|
|
87
76
|
- test/example_feed.atom
|
88
77
|
- test/example_feed_empty_author.atom
|
89
78
|
- test/example_feed_false_connected.atom
|
79
|
+
- test/example_page.html
|
90
80
|
has_rdoc: true
|
91
81
|
homepage: http://github.com/hotsh/ostatus
|
92
82
|
licenses: []
|
@@ -129,3 +119,4 @@ test_files:
|
|
129
119
|
- test/example_feed.atom
|
130
120
|
- test/example_feed_empty_author.atom
|
131
121
|
- test/example_feed_false_connected.atom
|
122
|
+
- test/example_page.html
|