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.
@@ -1,167 +0,0 @@
1
- require File.expand_path(File.dirname(__FILE__) + '/oauth2-helper')
2
-
3
- module Riddl
4
- module Utils
5
- module OAuth2
6
-
7
- module UnivieBearer
8
- def self::implementation(client_id, client_secret, access_tokens)
9
- Proc.new do
10
- run CheckAuth, client_id, client_secret, access_tokens if get
11
- end
12
- end
13
-
14
- class CheckAuth < Riddl::Implementation
15
- def response
16
- client_id = @a[0]
17
- client_secret = @a[1]
18
- access_tokens = @a[2]
19
- if @h['AUTHORIZATION']
20
- token = @h['AUTHORIZATION'].sub(/^Bearer /, '')
21
-
22
- data, _, signature = token.rpartition '.'
23
- expected_sign = Riddl::Utils::OAuth2::Helper::sign(client_id + ':' + client_secret, data)
24
-
25
- if !access_tokens.key? token
26
- @status = 403
27
- return Riddl::Parameter::Complex.new('data', 'application/json', {
28
- :error => 'Unknown token'
29
- }.to_json)
30
- elsif signature != expected_sign
31
- @status = 403
32
- return Riddl::Parameter::Complex.new('data', 'application/json', {
33
- :error => 'Invalid token, you bad boy'
34
- }.to_json)
35
- end
36
-
37
- header_claims, payload_claims = data.split('.').map { |v| Base64::urlsafe_decode64 v }
38
- payload_claims = JSON::parse payload_claims
39
-
40
- if header_claims != Riddl::Utils::OAuth2::Helper::header
41
- @status = 401
42
- return Riddl::Parameter::Complex.new('data', 'application/json', {
43
- :error => 'Invalid header claims'
44
- }.to_json)
45
- elsif payload_claims['exp'] <= Time.now.to_i
46
- @status = 403
47
- return Riddl::Parameter::Complex.new('data', 'application/json', {
48
- :error => 'Expired token'
49
- }.to_json)
50
- elsif !payload_claims['aud'].split(',').map(&:strip).include? client_id
51
- # XXX: ein token für mehrere clients gültig? lookup?
52
- @status = 403
53
- return Riddl::Parameter::Complex.new('data', 'application/json', {
54
- :error => 'Token is not valid for this application'
55
- }.to_json)
56
- end
57
-
58
- @headers << Riddl::Header.new('AUTHORIZATION_BEARER', access_tokens[token])
59
- end
60
-
61
- @p
62
- end
63
- end
64
- end
65
-
66
- module UnivieApp
67
- def self::implementation(client_id, client_secret, access_tokens, refresh_tokens)
68
- Proc.new do
69
- on resource 'verify' do
70
- run VerifyIdentity, access_tokens, refresh_tokens, client_id, client_secret if post 'verify_in'
71
- end
72
- on resource 'token' do
73
- run RefreshToken, access_tokens, refresh_tokens, client_id, client_secret if post 'refresh_token_in'
74
- end
75
- on resource 'revoke' do
76
- run RevokeTokenFlow, access_tokens, refresh_tokens if get 'revoke_token_in'
77
- run RevokeUserFlow, access_tokens, refresh_tokens if get 'revoke_user_in'
78
- end
79
- end
80
- end
81
-
82
- class VerifyIdentity < Riddl::Implementation
83
- def response
84
- code = Base64::urlsafe_decode64 @p[0].value
85
- access_tokens = @a[0]
86
- refresh_tokens = @a[1]
87
- client_id = @a[2]
88
- client_secret = @a[3]
89
-
90
- client_pass = "#{client_id}:#{client_secret}"
91
- user_id, decrypted = Riddl::Utils::OAuth2::Helper::decrypt_with_shared_secret(code, client_pass).split(':', 2)
92
- token, refresh_token = Riddl::Utils::OAuth2::Helper::generate_optimistic_token(client_id, client_pass)
93
- access_tokens[token] = user_id
94
- refresh_tokens[refresh_token] = token
95
-
96
- json_response = {
97
- :access_token => token,
98
- :refresh_token => refresh_token,
99
- :code => Base64.urlsafe_encode64(decrypted)
100
- }.to_json
101
-
102
- Riddl::Parameter::Complex.new('data', 'application/json', json_response)
103
- end
104
- end
105
-
106
- class RevokeTokenFlow < Riddl::Implementation
107
- def response
108
- token = @p[0].value
109
- access_tokens = @a[0]
110
- refresh_tokens = @a[1]
111
-
112
- access_tokens.delete(token)
113
- refresh_tokens.delete_by_value(token)
114
- end
115
- end
116
-
117
- class RevokeUserFlow < Riddl::Implementation
118
- def response
119
- user_id = @p[0].value
120
- access_tokens = @a[0]
121
- refresh_tokens = @a[1]
122
-
123
- token = access_tokens.delete_by_value user_id
124
- refresh_tokens.delete_by_value token
125
- end
126
- end
127
-
128
- class RefreshToken < Riddl::Implementation
129
- def response
130
- refresh_token = @p[1].value
131
- access_tokens = @a[0]
132
- refresh_tokens = @a[1]
133
- client_id = @a[2]
134
- client_secret = @a[3]
135
-
136
- token, _ = refresh_token.split '.'
137
- token_data = JSON::parse(Base64::urlsafe_decode64 token)
138
-
139
- if token_data['iss'] != client_id
140
- @status = 401
141
- return Riddl::Parameter::Complex.new('data', 'application/json', {
142
- :error => 'Token must be refreshed by issuer.'
143
- }.to_json)
144
- elsif refresh_tokens[refresh_token].nil? || token_data['exp'] <= Time.now.to_i
145
- @status = 403
146
- puts "i dont know #{refresh_token}", "#{refresh_tokens[refresh_token]}"
147
- return Riddl::Parameter::Complex.new('data', 'application/json', {
148
- :error => 'Invalid refresh token.'
149
- }.to_json)
150
- end
151
-
152
- old_token = refresh_tokens[refresh_token]
153
- user = access_tokens.delete old_token
154
-
155
- token = Riddl::Utils::OAuth2::Helper::generate_access_token(client_id, client_id + ':' + client_secret)
156
-
157
- refresh_tokens[refresh_token] = token
158
- access_tokens[token] = user
159
-
160
- Riddl::Parameter::Complex.new('data', 'application/json', { :token => token }.to_json)
161
- end
162
- end
163
- end
164
-
165
- end
166
- end
167
- end
@@ -1,479 +0,0 @@
1
- module Riddl
2
- module Utils
3
- module Properties
4
-
5
- VERSION_MAJOR = 1
6
- VERSION_MINOR = 0
7
- PROPERTIES_SCHEMA_XSL_RNG = "#{File.dirname(__FILE__)}/../ns/common-patterns/properties/#{VERSION_MAJOR}.#{VERSION_MINOR}/properties.schema.xsl"
8
-
9
- def self::implementation(backend,handler=nil,details=:production)
10
- unless handler.nil? || (handler.is_a? Riddl::Utils::Properties::HandlerBase)
11
- raise "handler not a subclass of HandlerBase"
12
- end
13
- Proc.new do
14
- run Riddl::Utils::Properties::All, backend, handler if get '*'
15
- run Riddl::Utils::Properties::Query, backend, handler if get 'query'
16
- on resource 'schema' do
17
- run Riddl::Utils::Properties::Schema, backend if get
18
- on resource 'rng' do
19
- run Riddl::Utils::Properties::RngSchema, backend if get
20
- end
21
- end
22
- on resource 'values' do
23
- run Riddl::Utils::Properties::Properties, backend, handler if get
24
- run Riddl::Utils::Properties::AddProperty, backend, handler if post 'property'
25
- run Riddl::Utils::Properties::AddProperties, backend, handler if put 'properties'
26
- on resource do
27
- run Riddl::Utils::Properties::GetContent, backend, handler if get
28
- run Riddl::Utils::Properties::DelContent, backend, handler if delete
29
- run Riddl::Utils::Properties::AddContent, backend, handler if post 'addcontent'
30
- run Riddl::Utils::Properties::UpdContent, backend, handler if put 'updcontent'
31
- on resource do
32
- run Riddl::Utils::Properties::GetContent, backend, handler if get
33
- run Riddl::Utils::Properties::DelContent, backend, handler if delete
34
- run Riddl::Utils::Properties::UpdContent, backend, handler if put 'updcontent'
35
- on resource do
36
- run Riddl::Utils::Properties::GetContent, backend, handler if get
37
- end
38
- end
39
- end
40
- end
41
- end
42
- end
43
-
44
- # Overloadable and Backends
45
- class HandlerBase #{{{
46
- def initialize(data)
47
- @data = data
48
- @property = nil
49
- end
50
- def property(p)
51
- @property = p
52
- self
53
- end
54
- def create; end
55
- def read; end
56
- def update; end
57
- def delete; end
58
- end #}}}
59
-
60
- class Backend #{{{
61
- attr_reader :schema, :data, :rng
62
-
63
- def initialize(schema,target,init=nil)
64
- @target = target.gsub(/^\/+/,'/')
65
- @schemas = {}
66
- @rngs = {}
67
-
68
- if schema.is_a? Hash
69
- schema.each { |k,v| add_schema k, v }
70
- elsif schema.is_a? String
71
- add_schema 'default', schema
72
- end
73
- raise "no schemas provided" if @schemas.length == 0
74
- @schema = @schemas.first[1]
75
- @rng = @rngs.first[1]
76
-
77
- FileUtils::mkdir_p(File::dirname(@target)) unless File.exists?(@target)
78
- FileUtils::cp init, @target if init and not File.exists?(@target)
79
-
80
- raise "properties file not found" unless File.exists?(@target)
81
- @data = XML::Smart.open_unprotected(@target)
82
- @data.register_namespace 'p', 'http://riddl.org/ns/common-patterns/properties/1.0'
83
- @mutex = Mutex.new
84
- end
85
-
86
- def activate_schema(name)
87
- if @schemas[name]
88
- @schema = @schemas[name]
89
- @rng = @rngs[name]
90
- true
91
- else
92
- false
93
- end
94
- end
95
-
96
- def add_schema(key,name)
97
- raise "schema file not found" unless File.exists?(name)
98
- @schemas[key] = XML::Smart.open_unprotected(name.gsub(/^\/+/,'/'))
99
- @schemas[key].register_namespace 'p', 'http://riddl.org/ns/common-patterns/properties/1.0'
100
- if !File::exists?(Riddl::Utils::Properties::PROPERTIES_SCHEMA_XSL_RNG)
101
- raise "properties schema transformation file not found"
102
- end
103
- @rngs[key] = @schemas[key].transform_with(XML::Smart.open_unprotected(Riddl::Utils::Properties::PROPERTIES_SCHEMA_XSL_RNG))
104
- end
105
- private :add_schema
106
-
107
- def modifiable?(property)
108
- @schema.find("boolean(/p:properties/p:#{property}[@modifiable='true'])") || schema.find("boolean(/p:properties/p:optional/p:#{property}[@modifiable='true'])")
109
- end
110
- def valid_state?(property,current,new)
111
- @schema.find("boolean(/p:properties/p:#{property}/p:#{current}/p:#{new}[@putable='true'])") || schema.find("boolean(/p:properties/p:optional/p:#{property}/p:#{current}/p:#{new}[@putable='true'])")
112
- end
113
- def is_state?(property)
114
- @schema.find("boolean(/p:properties/p:#{property}[@type='state'])") || schema.find("boolean(/p:properties/p:optional/p:#{property}[@type='state'])")
115
- end
116
- def init_state?(property,new)
117
- @schema.find("boolean(/p:properties/p:#{property}/p:#{new}[position()=1])") || schema.find("boolean(/p:properties/p:optional/p:#{property}/p:#{new}[position()=1])")
118
- end
119
- def property_type(property)
120
- exis = @schema.find("/p:properties/*[name()='#{property}']|/p:properties/p:optional/*[name()='#{property}']")
121
- exis.any? ? exis.first.attributes['type'].to_sym : nil
122
- end
123
-
124
- def modify(&block)
125
- tdoc = @data.root.to_doc
126
- tdoc.register_namespace 'p', 'http://riddl.org/ns/common-patterns/properties/1.0'
127
- @mutex.synchronize do
128
- block.call tdoc
129
- if tdoc.validate_against(@rng){|err| puts err.message }
130
- block.call @data
131
- @data.save_as(@target)
132
- true
133
- else
134
- false
135
- end
136
- end
137
- end
138
- end #}}}
139
-
140
- # Just reading
141
- class All < Riddl::Implementation #{{{
142
- def response
143
- backend = @a[0]
144
- handler = @a[1]
145
- EM.defer{handler.read} unless handler.nil?
146
- return Riddl::Parameter::Complex.new("document","text/xml",backend.data.to_s)
147
- end
148
- end #}}}
149
-
150
- class Properties < Riddl::Implementation #{{{
151
- def response
152
- backend = @a[0]
153
- handler = @a[1]
154
- EM.defer{handler.read} unless handler.nil?
155
-
156
- ret = XML::Smart.string("<properties xmlns=\"http://riddl.org/ns/common-patterns/properties/1.0\"/>")
157
- backend.schema.find("/p:properties/*[name()!='optional']|/p:properties/p:optional/*").each do |r|
158
- ret.root.add("property",r.qname.to_s)
159
- end
160
- return Riddl::Parameter::Complex.new("keys","text/xml",ret.to_s)
161
- end
162
- end #}}}
163
-
164
- class Query < Riddl::Implementation #{{{
165
- def response
166
- backend = @a[0]
167
- handler = @a[1]
168
- EM.defer{handler.read} unless handler.nil?
169
- query = (@p[0].value.to_s.strip.empty? ? '*' : @p[0].value)
170
-
171
- begin
172
- e = backend.data.find(query)
173
- rescue => e
174
- prop = XML::Smart::string("<not-existing xmlns=\"http://riddl.org/ns/common-patterns/properties/1.0\"/>").to_s
175
- return Riddl::Parameter::Complex.new("value","text/xml",prop.to_s)
176
- end
177
- if e.class == XML::Smart::Dom::NodeSet
178
- if e.any?
179
- prop = XML::Smart::string("<value xmlns=\"http://riddl.org/ns/common-patterns/properties/1.0\"/>")
180
- prop.root.add(e)
181
- else
182
- prop = XML::Smart::string("<not-existing xmlns=\"http://riddl.org/ns/common-patterns/properties/1.0\"/>").to_s
183
- end
184
- return Riddl::Parameter::Complex.new("value","text/xml",prop.to_s)
185
- else
186
- return Riddl::Parameter::Simple.new("value",e.to_s)
187
- end
188
- end
189
- end #}}}
190
-
191
- class RngSchema < Riddl::Implementation #{{{
192
- def response
193
- backend = @a[0]
194
- Riddl::Parameter::Complex.new("document-schema","text/xml",backend.rng.to_s)
195
- end
196
- end #}}}
197
-
198
- class Schema < Riddl::Implementation #{{{
199
- def response
200
- backend = @a[0]
201
- return Riddl::Parameter::Complex.new("document-schema","text/xml",backend.schema.to_s)
202
- end
203
- end #}}}
204
-
205
- class GetContent < Riddl::Implementation #{{{
206
- def response
207
- backend = @a[0]
208
- handler = @a[1]
209
-
210
- EM.defer{handler.property(@r[1]).read} unless handler.nil?
211
-
212
- if ret = extract_values(backend,@r[1],Riddl::Protocols::Utils::unescape(@r[2..-1].join('/')))
213
- ret
214
- else
215
- @status = 404
216
- end
217
- end
218
-
219
- def extract_values(backend,property,minor=nil)
220
- case backend.property_type(property)
221
- when :complex
222
- res = backend.data.find("/p:properties/*[name()=\"#{property}\"]#{minor == '' ? '' : "/p:#{minor}"}")
223
- if res.any?
224
- prop = XML::Smart::string("<value xmlns=\"http://riddl.org/ns/common-patterns/properties/1.0\"/>")
225
- if res.length == 1
226
- prop.root.add(res.first.children)
227
- else
228
- prop.root.add(res)
229
- end
230
- return Riddl::Parameter::Complex.new("value","text/xml",prop.to_s)
231
- else
232
- prop = XML::Smart::string("<not-existing xmlns=\"http://riddl.org/ns/common-patterns/properties/1.0\"/>")
233
- end
234
- when :simple, :state
235
- res = backend.data.find("string(/p:properties/*[name()=\"#{property}\"]#{minor})")
236
- return Riddl::Parameter::Simple.new("value",res.to_s)
237
- when :arbitrary
238
- res = backend.data.find("/p:properties/*[name()=\"#{property}\"]")
239
- if res.any?
240
- c = res.first.children
241
- if c.length == 1 && c.first.class == XML::Smart::Dom::Element
242
- return Riddl::Parameter::Complex.new("content","text/xml",c.first.dump)
243
- else
244
- return Riddl::Parameter::Complex.new("content","text/plain",c.first.to_s)
245
- end
246
- else
247
- prop = XML::Smart::string("<not-existing xmlns=\"http://riddl.org/ns/common-patterns/properties/1.0\"/>")
248
- return Riddl::Parameter::Complex.new("content","text/xml",prop.to_s)
249
- end
250
- end
251
- nil
252
- end
253
- private :extract_values
254
-
255
- end #}}}
256
-
257
- # Modifiable
258
- class AddProperty < Riddl::Implementation #{{{
259
- def response
260
- backend = @a[0]
261
- handler = @a[1]
262
-
263
- property = @p[0].value
264
- ct = @p[1]
265
- value = ct.name == 'value' ? ct.value : nil
266
- content = ct.name == 'content' ? ct.value : nil
267
-
268
- unless backend.modifiable?(property)
269
- @status = 500
270
- return # change properties.schema
271
- end
272
-
273
- path = "/p:properties/*[name()=\"#{property}\"]"
274
- nodes = backend.data.find(path)
275
- if nodes.any?
276
- @status = 404
277
- return # this property does not exist
278
- end
279
-
280
- if backend.is_state?(property)
281
- unless backend.init_state?(property,value)
282
- @status = 404
283
- return # not a valid state from here on
284
- end
285
- end
286
-
287
- newstuff = value.nil? ? XML::Smart.string(content).root.children : value
288
- backend.modify do |doc|
289
- ele = doc.root.add property
290
- if value.nil?
291
- ele.add newstuff
292
- else
293
- ele.text = newstuff
294
- end
295
- end || begin
296
- @status = 400
297
- return # bad request
298
- end
299
-
300
- EM.defer{handler.property(property).create} unless handler.nil?
301
- return
302
- end
303
- end #}}}
304
-
305
- class AddProperties < Riddl::Implementation #{{{
306
- def response
307
- backend = @a[0]
308
- handler = @a[1]
309
-
310
- 0.upto(@p.length/2-1) do |i|
311
- property = @p[i*2].value
312
- ct = @p[i*2+1]
313
- value = ct.name == 'value' ? ct.value : nil
314
- content = ct.name == 'content' ? ct.value : nil
315
-
316
- unless backend.modifiable?(property)
317
- @status = 500
318
- return # change properties.schema
319
- end
320
-
321
- path = "/p:properties/*[name()=\"#{property}\"]"
322
- nodes = backend.data.find(path)
323
- if nodes.empty?
324
- @status = 404
325
- return # this property does not exist
326
- end
327
-
328
- if backend.is_state?(property)
329
- unless backend.valid_state?(property,nodes.first.to_s,value)
330
- @status = 404
331
- return # not a valid state from here on
332
- end
333
- end
334
-
335
- newstuff = value.nil? ? XML::Smart.string(content).root.children : value
336
- backend.modify do |doc|
337
- nodes = doc.find(path)
338
- nods = nodes.map{|ele| ele.children.delete_all!; ele}
339
- nods.each do |ele|
340
- if value.nil?
341
- ele.add newstuff
342
- else
343
- ele.text = newstuff
344
- end
345
- end
346
- end || begin
347
- @status = 400
348
- return # bad request
349
- end
350
-
351
- end
352
- EM.defer do
353
- 0.upto(@p.length/2-1) do |i|
354
- property = @p[i*2].value
355
- handler.property(property).create
356
- end
357
- end unless handler.nil?
358
- return
359
- end
360
- end #}}}
361
-
362
- class AddContent < Riddl::Implementation #{{{
363
- def response
364
- backend = @a[0]
365
- handler = @a[1]
366
-
367
- property = @r[1]
368
- value = @p.detect{|p| p.name == 'value'}.value
369
-
370
- unless backend.modifiable?(property)
371
- @status = 500
372
- return # change properties.schema
373
- end
374
-
375
- path = "/p:properties/p:#{property}"
376
- node = backend.data.find(path)
377
- if node.empty?
378
- @status = 404
379
- return # this property does not exist
380
- end
381
-
382
- newstuff = XML::Smart.string(value)
383
- backend.modify do |doc|
384
- node = doc.find(path)
385
- node.first.add newstuff.root
386
- end || begin
387
- @status = 400
388
- return # bad request
389
- end
390
-
391
- EM.defer{handler.property(property).create} unless handler.nil?
392
- end
393
- end #}}}
394
-
395
- class DelContent < Riddl::Implementation #{{{
396
- def response
397
- backend = @a[0]
398
- handler = @a[1]
399
-
400
- property = @r[1]
401
- minor = Riddl::Protocols::Utils::unescape(@r[2])
402
-
403
- unless backend.modifiable?(property)
404
- @status = 500
405
- return # change properties.schema
406
- end
407
-
408
- path = "/p:properties/*[name()=\"#{property}\"]#{minor.nil? ? '' : "/p:#{minor}"}"
409
- nodes = backend.data.find(path)
410
- if nodes.empty?
411
- @status = 404
412
- return # this property does not exist
413
- end
414
-
415
- backend.modify do |doc|
416
- doc.find(path).delete_all!
417
- end || begin
418
- @status = 400
419
- return # bad request
420
- end
421
-
422
- EM.defer{handler.property(property).delete} unless handler.nil?
423
- return
424
- end
425
- end #}}}
426
-
427
- class UpdContent < Riddl::Implementation #{{{
428
- def response
429
- backend = @a[0]
430
- handler = @a[1]
431
-
432
- property = @r[1]
433
- value = @p.detect{|p| p.name == 'value'}; value = value.nil? ? value : value.value
434
- content = @p.detect{|p| p.name == 'content'}; content = content.nil? ? content : content.value
435
- minor = @r[2]
436
-
437
- unless backend.modifiable?(property)
438
- @status = 500
439
- return # change properties.schema
440
- end
441
-
442
- path = "/p:properties/*[name()=\"#{property}\"]#{minor.nil? ? '' : "/p:#{minor}"}"
443
- nodes = backend.data.find(path)
444
- if nodes.empty?
445
- @status = 404
446
- return # this property does not exist
447
- end
448
-
449
- if backend.is_state?(property)
450
- unless backend.valid_state?(property,nodes.first.to_s,value)
451
- @status = 404
452
- return # not a valid state from here on
453
- end
454
- end
455
-
456
- newstuff = value.nil? ? XML::Smart.string(content).root.children : value
457
- backend.modify do |doc|
458
- nodes = doc.root.find(path)
459
- nods = nodes.map{|ele| ele.children.delete_all!; ele}
460
- nods.each do |ele|
461
- if value.nil?
462
- ele.add newstuff
463
- else
464
- ele.text = newstuff
465
- end
466
- end
467
- end || begin
468
- @status = 400
469
- return # bad request
470
- end
471
-
472
- EM.defer{handler.property(property).update} unless handler.nil?
473
- return
474
- end
475
- end #}}}
476
-
477
- end
478
- end
479
- end