riddl 0.99.220 → 0.99.221
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/lib/ruby/riddl/utils/oauth2-helper.rb +1 -1
- data/lib/ruby/riddl/utils/oauth2-univie.rb +4 -4
- data/riddl.gemspec +1 -1
- metadata +1 -14
- data/lib/ruby/riddl/description.rb +0 -33
- data/lib/ruby/riddl/docoverlay.html +0 -255
- data/lib/ruby/riddl/docoverlay.rb +0 -14
- data/lib/ruby/riddl/downloadify.rb +0 -14
- data/lib/ruby/riddl/erbserve.rb +0 -24
- data/lib/ruby/riddl/fileserve.rb +0 -45
- data/lib/ruby/riddl/notifications_producer.rb +0 -328
- data/lib/ruby/riddl/oauth2-helper.rb +0 -135
- data/lib/ruby/riddl/oauth2-univie.rb +0 -167
- data/lib/ruby/riddl/properties.rb +0 -479
- data/lib/ruby/riddl/turtle.rb +0 -72
- data/lib/ruby/riddl/xmlserve.rb +0 -40
- data/lib/ruby/riddl/xsloverlay.rb +0 -21
data/lib/ruby/riddl/fileserve.rb
DELETED
@@ -1,45 +0,0 @@
|
|
1
|
-
require 'mime/types'
|
2
|
-
require 'charlock_holmes'
|
3
|
-
require 'digest/md5'
|
4
|
-
|
5
|
-
module Riddl
|
6
|
-
module Utils
|
7
|
-
class FileServe < Riddl::Implementation
|
8
|
-
def response
|
9
|
-
path = File.file?(@a[0]) ? @a[0] : "#{@a[0]}/#{@r[@match.length-1..-1].join('/')}".gsub(/\/+/,'/')
|
10
|
-
|
11
|
-
if File.directory?(path)
|
12
|
-
@status = 404
|
13
|
-
return []
|
14
|
-
end
|
15
|
-
if File.exists?(path)
|
16
|
-
mtime = File.mtime(path)
|
17
|
-
@headers << Riddl::Header.new("Last-Modified",mtime.httpdate)
|
18
|
-
@headers << Riddl::Header.new("ETag",Digest::MD5.hexdigest(mtime.httpdate))
|
19
|
-
htime = @env["HTTP_IF_MODIFIED_SINCE"].nil? ? Time.at(0) : Time.parse(@env["HTTP_IF_MODIFIED_SINCE"])
|
20
|
-
if htime == mtime
|
21
|
-
@headers << Riddl::Header.new("Connection","close")
|
22
|
-
@status = 304 # Not modified
|
23
|
-
return []
|
24
|
-
else
|
25
|
-
fmt = @a[1] || begin
|
26
|
-
mt = MIME::Types.type_for(path).first
|
27
|
-
if mt.nil?
|
28
|
-
'text/plain;charset=utf-8'
|
29
|
-
else
|
30
|
-
apx = ''
|
31
|
-
if mt.ascii?
|
32
|
-
tstr = File.read(path,CharlockHolmes::EncodingDetector::DEFAULT_BINARY_SCAN_LEN)
|
33
|
-
apx = ';charset=' + CharlockHolmes::EncodingDetector.detect(tstr)[:encoding]
|
34
|
-
end
|
35
|
-
mt.to_s + apx
|
36
|
-
end
|
37
|
-
end
|
38
|
-
return Riddl::Parameter::Complex.new('file',fmt,File.open(path,'r'))
|
39
|
-
end
|
40
|
-
end
|
41
|
-
@status = 404
|
42
|
-
end
|
43
|
-
end
|
44
|
-
end
|
45
|
-
end
|
@@ -1,328 +0,0 @@
|
|
1
|
-
module Riddl
|
2
|
-
module Utils
|
3
|
-
module Notifications
|
4
|
-
|
5
|
-
module Producer
|
6
|
-
|
7
|
-
def self::implementation(backend,handler=nil,details=:production)
|
8
|
-
unless handler.nil? || (handler.is_a? Riddl::Utils::Notifications::Producer::HandlerBase)
|
9
|
-
raise "handler not a subclass of HandlerBase"
|
10
|
-
end
|
11
|
-
Proc.new do
|
12
|
-
on resource "notifications" do
|
13
|
-
run Riddl::Utils::Notifications::Producer::Overview if get
|
14
|
-
on resource "topics" do
|
15
|
-
run Riddl::Utils::Notifications::Producer::Topics, backend if get
|
16
|
-
end
|
17
|
-
on resource "subscriptions" do
|
18
|
-
run Riddl::Utils::Notifications::Producer::Subscriptions, backend, details if get
|
19
|
-
run Riddl::Utils::Notifications::Producer::CreateSubscription, backend, handler if post 'subscribe'
|
20
|
-
on resource do
|
21
|
-
run Riddl::Utils::Notifications::Producer::Subscription, backend, details if get 'request'
|
22
|
-
run Riddl::Utils::Notifications::Producer::UpdateSubscription, backend, handler if put 'details'
|
23
|
-
run Riddl::Utils::Notifications::Producer::DeleteSubscription, backend, handler if delete 'delete'
|
24
|
-
on resource 'ws' do
|
25
|
-
run Riddl::Utils::Notifications::Producer::WS, backend, handler if websocket
|
26
|
-
end
|
27
|
-
end
|
28
|
-
end
|
29
|
-
end
|
30
|
-
end
|
31
|
-
end
|
32
|
-
|
33
|
-
class HandlerBase #{{{
|
34
|
-
def initialize(data)
|
35
|
-
@data = data
|
36
|
-
@key = nil
|
37
|
-
@topics = []
|
38
|
-
end
|
39
|
-
def key(k)
|
40
|
-
@key = k
|
41
|
-
self
|
42
|
-
end
|
43
|
-
def topics(t)
|
44
|
-
@topics = t
|
45
|
-
self
|
46
|
-
end
|
47
|
-
def ws_open(socket); end
|
48
|
-
def ws_close; end
|
49
|
-
def ws_message(socket,data); end
|
50
|
-
def create; end
|
51
|
-
def delete; end
|
52
|
-
def update; end
|
53
|
-
end #}}}
|
54
|
-
|
55
|
-
class Backend #{{{
|
56
|
-
attr_reader :topics
|
57
|
-
|
58
|
-
class Sub #{{{
|
59
|
-
def initialize(name)
|
60
|
-
@name = name
|
61
|
-
end
|
62
|
-
def modify(&block)
|
63
|
-
XML::Smart.modify(@name,"<subscription xmlns='http://riddl.org/ns/common-patterns/notifications-producer/1.0'/>") do |doc|
|
64
|
-
doc.register_namespace 'n', 'http://riddl.org/ns/common-patterns/notifications-producer/1.0'
|
65
|
-
block.call doc
|
66
|
-
end
|
67
|
-
end
|
68
|
-
def delete
|
69
|
-
FileUtils::rm_rf(File.dirname(@name))
|
70
|
-
end
|
71
|
-
def to_s
|
72
|
-
File.read(@name)
|
73
|
-
end
|
74
|
-
def read(&block)
|
75
|
-
XML::Smart.open_unprotected(@name) do |doc|
|
76
|
-
doc.register_namespace 'n', 'http://riddl.org/ns/common-patterns/notifications-producer/1.0'
|
77
|
-
block.call doc
|
78
|
-
end
|
79
|
-
end
|
80
|
-
end #}}}
|
81
|
-
|
82
|
-
class Subs #{{{
|
83
|
-
def initialize(target)
|
84
|
-
@target = target
|
85
|
-
end
|
86
|
-
|
87
|
-
def each(&block)
|
88
|
-
keys.each do |key|
|
89
|
-
f = @target + '/' + key + '/subscription.xml'
|
90
|
-
block.call Sub.new(f), key if File.exists? f
|
91
|
-
end
|
92
|
-
end
|
93
|
-
|
94
|
-
def include?(key)
|
95
|
-
f = @target + '/' + key + '/subscription.xml'
|
96
|
-
File.exists?(f)
|
97
|
-
end
|
98
|
-
|
99
|
-
def [](key)
|
100
|
-
f = @target + '/' + key + '/subscription.xml'
|
101
|
-
File.exists?(f) ? Sub.new(f) : nil
|
102
|
-
end
|
103
|
-
|
104
|
-
def create(&block)
|
105
|
-
key = nil
|
106
|
-
begin
|
107
|
-
continue = true
|
108
|
-
key = Digest::MD5.hexdigest(Kernel::rand().to_s)
|
109
|
-
Dir.mkdir(@target + '/' + key) rescue continue = false
|
110
|
-
end until continue
|
111
|
-
producer_secret = Digest::MD5.hexdigest(Kernel::rand().to_s)
|
112
|
-
consumer_secret = Digest::MD5.hexdigest(Kernel::rand().to_s)
|
113
|
-
File.open(@target + '/' + key + '/producer-secret','w') { |f| f.write producer_secret }
|
114
|
-
File.open(@target + '/' + key + '/consumer-secret','w') { |f| f.write consumer_secret }
|
115
|
-
XML::Smart::modify(@target + '/' + key + '/subscription.xml',"<subscription xmlns='http://riddl.org/ns/common-patterns/notifications-producer/1.0'/>") do |doc|
|
116
|
-
doc.register_namespace 'n', 'http://riddl.org/ns/common-patterns/notifications-producer/1.0'
|
117
|
-
block.call doc, key
|
118
|
-
end
|
119
|
-
[key, producer_secret, consumer_secret]
|
120
|
-
end
|
121
|
-
|
122
|
-
def keys
|
123
|
-
if File.directory?(@target)
|
124
|
-
Dir[@target + '/*'].map do |d|
|
125
|
-
File.directory?(d) ? File.basename(d) : nil
|
126
|
-
end.compact
|
127
|
-
else
|
128
|
-
[]
|
129
|
-
end
|
130
|
-
end
|
131
|
-
end #}}}
|
132
|
-
|
133
|
-
def initialize(topics,target)
|
134
|
-
@target = target.gsub(/^\/+/,'/')
|
135
|
-
|
136
|
-
FileUtils::mkdir_p(@target) unless File.exists?(@target)
|
137
|
-
|
138
|
-
raise "topics file not found" unless File.exists?(topics)
|
139
|
-
@topics = XML::Smart.open_unprotected(topics.gsub(/^\/+/,'/'))
|
140
|
-
@topics.register_namespace 'n', 'http://riddl.org/ns/common-patterns/notifications-producer/1.0'
|
141
|
-
|
142
|
-
subscriptions.each do |sub,key|
|
143
|
-
sub.read do |doc|
|
144
|
-
if doc.find('/*[@url]').empty?
|
145
|
-
sub.delete
|
146
|
-
end
|
147
|
-
end
|
148
|
-
end
|
149
|
-
end
|
150
|
-
|
151
|
-
def subscriptions
|
152
|
-
Subs.new(@target)
|
153
|
-
end
|
154
|
-
|
155
|
-
end #}}}
|
156
|
-
|
157
|
-
class Overview < Riddl::Implementation #{{{
|
158
|
-
def response
|
159
|
-
Riddl::Parameter::Complex.new("overview","text/xml") do
|
160
|
-
<<-END
|
161
|
-
<overview xmlns='http://riddl.org/ns/common-patterns/notifications-producer/1.0'>
|
162
|
-
<topics/>
|
163
|
-
<subscriptions/>
|
164
|
-
</overview>
|
165
|
-
END
|
166
|
-
end
|
167
|
-
|
168
|
-
end
|
169
|
-
end #}}}
|
170
|
-
|
171
|
-
class Topics < Riddl::Implementation #{{{
|
172
|
-
def response
|
173
|
-
backend = @a[0]
|
174
|
-
Riddl::Parameter::Complex.new("overview","text/xml") do
|
175
|
-
backend.topics.to_s
|
176
|
-
end
|
177
|
-
end
|
178
|
-
end #}}}
|
179
|
-
|
180
|
-
class Subscriptions < Riddl::Implementation #{{{
|
181
|
-
def response
|
182
|
-
backend = @a[0]
|
183
|
-
details = @a[1]
|
184
|
-
Riddl::Parameter::Complex.new("subscriptions","text/xml") do
|
185
|
-
ret = XML::Smart::string <<-END
|
186
|
-
<subscriptions details='#{details}' xmlns='http://riddl.org/ns/common-patterns/notifications-producer/1.0'/>
|
187
|
-
END
|
188
|
-
backend.subscriptions.each do |sub,key|
|
189
|
-
sub.read do |doc|
|
190
|
-
if doc.root.attributes['url']
|
191
|
-
ret.root.add('subscription', :id => key, :url => doc.root.attributes['url'])
|
192
|
-
else
|
193
|
-
ret.root.add('subscription', :id => key)
|
194
|
-
end
|
195
|
-
end
|
196
|
-
end
|
197
|
-
ret.to_s
|
198
|
-
end
|
199
|
-
end
|
200
|
-
end #}}}
|
201
|
-
|
202
|
-
class Subscription < Riddl::Implementation #{{{
|
203
|
-
def response
|
204
|
-
backend = @a[0]
|
205
|
-
if(backend.subscriptions.include?(@r.last))
|
206
|
-
Riddl::Parameter::Complex.new("subscription","text/xml") do
|
207
|
-
backend.subscriptions[@r.last].to_s
|
208
|
-
end
|
209
|
-
else
|
210
|
-
@status = 404
|
211
|
-
end
|
212
|
-
end
|
213
|
-
end #}}}
|
214
|
-
|
215
|
-
class CreateSubscription < Riddl::Implementation #{{{
|
216
|
-
def response
|
217
|
-
backend = @a[0]
|
218
|
-
handler = @a[1]
|
219
|
-
|
220
|
-
url = @p[0].name == 'url' ? @p.shift.value : nil
|
221
|
-
|
222
|
-
topics = []
|
223
|
-
key, consumer_secret, producer_secret = backend.subscriptions.create do |doc,key|
|
224
|
-
doc.root.attributes['url'] = url if url
|
225
|
-
while @p.length > 0
|
226
|
-
topic = @p.shift.value
|
227
|
-
base = @p.shift
|
228
|
-
type = base.name
|
229
|
-
items = base.value.split(',')
|
230
|
-
t = if topics.include?(topic)
|
231
|
-
doc.find("/n:subscription/n:topic[@id='#{topic}']").first
|
232
|
-
else
|
233
|
-
topics << topic
|
234
|
-
doc.root.add('topic', :id => topic)
|
235
|
-
end
|
236
|
-
items.each do |i|
|
237
|
-
t.add(type[0..-2], i)
|
238
|
-
end
|
239
|
-
end
|
240
|
-
end
|
241
|
-
|
242
|
-
handler.key(key).topics(topics).create unless handler.nil?
|
243
|
-
[
|
244
|
-
Riddl::Parameter::Simple.new('key',key),
|
245
|
-
Riddl::Parameter::Simple.new('producer-secret',producer_secret),
|
246
|
-
Riddl::Parameter::Simple.new('consumer-secret',consumer_secret)
|
247
|
-
]
|
248
|
-
end
|
249
|
-
end #}}}
|
250
|
-
|
251
|
-
class DeleteSubscription < Riddl::Implementation #{{{
|
252
|
-
def response
|
253
|
-
backend = @a[0]
|
254
|
-
handler = @a[1]
|
255
|
-
key = @r.last
|
256
|
-
|
257
|
-
backend.subscriptions[key].delete
|
258
|
-
handler.key(key).delete unless handler.nil?
|
259
|
-
return
|
260
|
-
end
|
261
|
-
end #}}}
|
262
|
-
|
263
|
-
class UpdateSubscription < Riddl::Implementation #{{{
|
264
|
-
def response
|
265
|
-
backend = @a[0]
|
266
|
-
handler = @a[1]
|
267
|
-
key = @r.last
|
268
|
-
|
269
|
-
url = @p[0].name == 'url' ? @p.shift.value : nil
|
270
|
-
|
271
|
-
# TODO check if message is valid (with producer secret)
|
272
|
-
unless backend.subscriptions[key]
|
273
|
-
@status = 404
|
274
|
-
return # subscription not found
|
275
|
-
end
|
276
|
-
|
277
|
-
topics = []
|
278
|
-
backend.subscriptions[key].modify do |doc|
|
279
|
-
if url.nil?
|
280
|
-
doc.find('/n:subscription/@url').delete_all!
|
281
|
-
else
|
282
|
-
doc.root.attributes['url'] = url
|
283
|
-
end
|
284
|
-
doc.root.children.delete_all!
|
285
|
-
while @p.length > 1
|
286
|
-
topic = @p.shift.value
|
287
|
-
base = @p.shift
|
288
|
-
type = base.name
|
289
|
-
items = base.value.split(',')
|
290
|
-
t = if topics.include?(topic)
|
291
|
-
doc.find("/n:subscription/n:topic[@id='#{topic}']").first
|
292
|
-
else
|
293
|
-
topics << topic
|
294
|
-
doc.root.add('topic', :id => topic)
|
295
|
-
end
|
296
|
-
items.each do |i|
|
297
|
-
t.add(type[0..-2], i)
|
298
|
-
end
|
299
|
-
end
|
300
|
-
end
|
301
|
-
|
302
|
-
handler.key(key).topics(topics).update unless handler.nil?
|
303
|
-
nil
|
304
|
-
end
|
305
|
-
end #}}}
|
306
|
-
|
307
|
-
class WS < Riddl::WebSocketImplementation #{{{
|
308
|
-
def onopen
|
309
|
-
@backend = @a[0]
|
310
|
-
@handler = @a[1]
|
311
|
-
@key = @r[-2]
|
312
|
-
@handler.key(@key).ws_open(self) unless @handler.nil?
|
313
|
-
end
|
314
|
-
|
315
|
-
def onmessage(data)
|
316
|
-
@handler.key(@key).ws_message(data) unless @handler.nil?
|
317
|
-
end
|
318
|
-
|
319
|
-
def onclose
|
320
|
-
@handler.key(@key).ws_close() unless @handler.nil?
|
321
|
-
end
|
322
|
-
end #}}}
|
323
|
-
|
324
|
-
end
|
325
|
-
|
326
|
-
end
|
327
|
-
end
|
328
|
-
end
|
@@ -1,135 +0,0 @@
|
|
1
|
-
require 'openssl'
|
2
|
-
require 'base64'
|
3
|
-
require 'securerandom'
|
4
|
-
require 'json'
|
5
|
-
|
6
|
-
module Riddl
|
7
|
-
module Utils
|
8
|
-
module OAuth2
|
9
|
-
|
10
|
-
module Helper
|
11
|
-
class Tokens #{{{
|
12
|
-
def initialize(tfile)
|
13
|
-
@tfile = tfile
|
14
|
-
@changed = changed
|
15
|
-
read
|
16
|
-
end
|
17
|
-
|
18
|
-
def [](name)
|
19
|
-
read if changed != @changed
|
20
|
-
@tokens[name]
|
21
|
-
end
|
22
|
-
|
23
|
-
def method_missing(name,*opts)
|
24
|
-
@tokens.send(name,*opts)
|
25
|
-
end
|
26
|
-
|
27
|
-
def []=(name,value)
|
28
|
-
@tokens[name] = value
|
29
|
-
write
|
30
|
-
nil
|
31
|
-
end
|
32
|
-
|
33
|
-
def changed
|
34
|
-
if File.exists?(@tfile)
|
35
|
-
File.stat(@tfile).mtime
|
36
|
-
else
|
37
|
-
@tokens = {}
|
38
|
-
write
|
39
|
-
end
|
40
|
-
end
|
41
|
-
private :changed
|
42
|
-
|
43
|
-
def write
|
44
|
-
EM.defer {
|
45
|
-
File.write(@tfile, JSON::pretty_generate(@tokens)) rescue {}
|
46
|
-
}
|
47
|
-
@changed = changed
|
48
|
-
end
|
49
|
-
private :write
|
50
|
-
|
51
|
-
def read
|
52
|
-
@tokens = JSON::parse(File.read(@tfile)) rescue {}
|
53
|
-
end
|
54
|
-
private :read
|
55
|
-
|
56
|
-
def delete(token)
|
57
|
-
deleted = @tokens.delete(token)
|
58
|
-
write
|
59
|
-
deleted
|
60
|
-
end
|
61
|
-
|
62
|
-
def delete_by_value(user_id)
|
63
|
-
deleted = @tokens.delete_if { |_, v| v == user_id }
|
64
|
-
write
|
65
|
-
deleted
|
66
|
-
end
|
67
|
-
end #}}}
|
68
|
-
|
69
|
-
def self::header #{{{
|
70
|
-
{
|
71
|
-
:alg => 'HS256',
|
72
|
-
:typ => 'JWT'
|
73
|
-
}.to_json
|
74
|
-
end #}}}
|
75
|
-
|
76
|
-
def self::nonce
|
77
|
-
SecureRandom::hex(32)
|
78
|
-
end
|
79
|
-
|
80
|
-
def self::sign(secret, what) #{{{
|
81
|
-
Base64::urlsafe_encode64 OpenSSL::HMAC.digest(OpenSSL::Digest.new('sha256'), secret, what)
|
82
|
-
end #}}}
|
83
|
-
|
84
|
-
def self::generate_access_token(client_id, secret, dur=3600)# {{{
|
85
|
-
h = Base64::urlsafe_encode64 header
|
86
|
-
p = Base64::urlsafe_encode64( {
|
87
|
-
:iss => client_id,
|
88
|
-
:sub => nonce,
|
89
|
-
:aud => client_id,
|
90
|
-
:exp => Time.now.to_i + dur
|
91
|
-
}.to_json)
|
92
|
-
s = sign(secret, "#{h}.#{p}")
|
93
|
-
"#{h}.#{p}.#{s}"
|
94
|
-
end# }}}
|
95
|
-
def self::generate_refresh_token(client_id, secret, dur=7776000) # {{{
|
96
|
-
token = Base64::urlsafe_encode64({
|
97
|
-
:iss => client_id,
|
98
|
-
:sub => nonce,
|
99
|
-
:exp => Time.now.to_i + dur
|
100
|
-
}.to_json)
|
101
|
-
"#{token}.#{sign(secret,token)}"
|
102
|
-
end# }}}
|
103
|
-
def self::generate_optimistic_token(client_id, secret, adur=3600, rdur=7776000) #{{{
|
104
|
-
t = generate_access_token(client_id, secret, adur)
|
105
|
-
r = generate_refresh_token(client_id, secret, rdur)
|
106
|
-
[t, r]
|
107
|
-
end #}}}
|
108
|
-
|
109
|
-
def self::decrypt_with_shared_secret(data, secret) #{{{
|
110
|
-
# extract initialization vector from encrypted data for further shenanigans
|
111
|
-
iv, encr = data[0...16], data[16..-1]
|
112
|
-
|
113
|
-
decipher = OpenSSL::Cipher::Cipher.new 'aes-256-cbc'
|
114
|
-
decipher.decrypt
|
115
|
-
|
116
|
-
decipher.key = Digest::SHA256.hexdigest secret
|
117
|
-
decipher.iv = iv
|
118
|
-
|
119
|
-
decipher.update(encr) + decipher.final rescue nil
|
120
|
-
end #}}}
|
121
|
-
def self::encrypt_with_shared_secret(data, secret) #{{{
|
122
|
-
cipher = OpenSSL::Cipher::Cipher.new 'aes-256-cbc'
|
123
|
-
cipher.encrypt
|
124
|
-
|
125
|
-
key = Digest::SHA256.hexdigest secret
|
126
|
-
iv = cipher.random_iv
|
127
|
-
cipher.key = key
|
128
|
-
cipher.iv = iv
|
129
|
-
|
130
|
-
Base64::urlsafe_encode64(iv + cipher.update(data) + cipher.final) rescue nil
|
131
|
-
end #}}}
|
132
|
-
end
|
133
|
-
end
|
134
|
-
end
|
135
|
-
end
|