blix-rest 0.7.2 → 0.8.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +85 -9
- data/lib/blix/rest/controller.rb +44 -4
- data/lib/blix/rest/route.rb +33 -0
- data/lib/blix/rest/session.rb +138 -0
- data/lib/blix/rest/version.rb +1 -1
- data/lib/blix/rest.rb +1 -1
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5db97b519f38052ee2b7272f3a25d6ec4d5e3ba71cae44bdcd83e25cdd6902f2
|
4
|
+
data.tar.gz: e7fb1c1da94eb622629a718bd81763d6874dc14028bed0ba8328b42cac5c2152
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: fb48999da4fffe47e1d52cb85319c7ed6473c756a55d6e87edef288a9a118f971c90d709ea73aaf566e1f927a7779056547a91d1cfae71b2cd1a157658c3d2a4
|
7
|
+
data.tar.gz: 93d06074a5b66da9099c1d1bee4fb23a00ac18f994809efb9fb28f0be7d6bf3a889fdad45a2fb349dbabeec6c816c77a34975a8cd7de70efbcce4cff2af1acb2
|
data/README.md
CHANGED
@@ -231,6 +231,7 @@ have access to a number of methods
|
|
231
231
|
method : the request method lowercase( 'get'/'post' ..)
|
232
232
|
req : the rack request
|
233
233
|
body : the request body as a string
|
234
|
+
path : the request path
|
234
235
|
query_params : a hash of parameters as passed in the url as parameters
|
235
236
|
path_params : a hash of parameters constructed from variable parts of the path
|
236
237
|
post_params : a hash of parameters passed in the body of the request
|
@@ -246,7 +247,7 @@ have access to a number of methods
|
|
246
247
|
render_erb : (template_name [,:layout=>name])
|
247
248
|
server_cache : get the server cache object
|
248
249
|
server_cache_get : retrieve/store value in cache
|
249
|
-
path_for : (path) give the
|
250
|
+
path_for : (path) give the external path for an internal path
|
250
251
|
url_for : (path) give the full url for an internal path
|
251
252
|
h : escape html string to avoid XSS
|
252
253
|
escape_javascript : escape a javascript string
|
@@ -291,22 +292,27 @@ is ok though.
|
|
291
292
|
|
292
293
|
the `before_route` hook can be used to modify the path or options of a route.
|
293
294
|
|
294
|
-
*NOTE* ! when manipulating the path you have to modify the string object in place.
|
295
|
-
|
296
295
|
the verb can not be modified
|
297
296
|
|
298
297
|
example:
|
299
298
|
|
300
299
|
class MyController < Blix::Rest::Controller
|
301
300
|
|
302
|
-
before_route do |
|
303
|
-
|
304
|
-
|
305
|
-
path.prepend('/app') unless path[0, 4] == '/app'
|
301
|
+
before_route do |route|
|
302
|
+
route.default_option(:level,:visitor)
|
303
|
+
route.prefix_path('/app')
|
306
304
|
end
|
307
305
|
...
|
308
306
|
end
|
309
307
|
|
308
|
+
the following methods are available on the route:
|
309
|
+
|
310
|
+
verb # readonly, the 'GET','POST' etc verb of the route
|
311
|
+
path # the path of the route
|
312
|
+
options # the options associated with the route eg :accept
|
313
|
+
path_prefix('/xx') # ensure the path has the given prefix
|
314
|
+
default_option(:xxx,'foo') # ensure that option has the given default value
|
315
|
+
|
310
316
|
### Sessions
|
311
317
|
|
312
318
|
the following methods are available in the controller for managing sessions.
|
@@ -321,11 +327,53 @@ this will generate a new session_id and setup the relevant headers
|
|
321
327
|
|
322
328
|
options can include:
|
323
329
|
|
324
|
-
:secure => true
|
325
|
-
:http = >true
|
330
|
+
:secure => true # secure cookies only
|
331
|
+
:http = >true # cookies for http only not javascript requests
|
326
332
|
:samesite =>:strict # use strict x-site policy
|
327
333
|
:samesite =>:lax # use lax x-site policy
|
328
334
|
|
335
|
+
For more complete session management:
|
336
|
+
|
337
|
+
class MyController < Blix::Rest::Controller
|
338
|
+
include Blix::Rest::Session
|
339
|
+
|
340
|
+
session_name :xxx # optional default'blix'
|
341
|
+
session_opts :http=>true # optional
|
342
|
+
session_manager: MyManager.new # optional , default Blix::Redis::Store
|
343
|
+
|
344
|
+
|
345
|
+
def myroutine
|
346
|
+
@xxx = session['xxx']
|
347
|
+
|
348
|
+
session['yyy'] = true
|
349
|
+
end
|
350
|
+
|
351
|
+
end
|
352
|
+
|
353
|
+
options can include:
|
354
|
+
|
355
|
+
:secure # false
|
356
|
+
:http # false
|
357
|
+
:samesite # lax
|
358
|
+
:path # '/'
|
359
|
+
:expire_secs # 30 mins
|
360
|
+
:cleanup_every_secs # 5 minutes
|
361
|
+
:max_age # nil
|
362
|
+
|
363
|
+
the following methods are available:
|
364
|
+
|
365
|
+
reset_session # gen new session id
|
366
|
+
session # session hash
|
367
|
+
csrf_token # the session csrf token
|
368
|
+
|
369
|
+
route options that affect sessions:
|
370
|
+
|
371
|
+
:nosession=>true # no session will be set/retrieved
|
372
|
+
:cache=>true # no session will be set/retrieved
|
373
|
+
:csrf=>true # request will be validated for calid csrf token.
|
374
|
+
# token must be in header X_CSRF_TOKEN field
|
375
|
+
|
376
|
+
session configuration is inherited from superclass controllers unless overridden.
|
329
377
|
|
330
378
|
## Cache
|
331
379
|
|
@@ -400,6 +448,31 @@ the cache is not used in development/testmode , only in production mode.
|
|
400
448
|
|
401
449
|
only cache pages with **HEADERS** and **CONTENT** that is not user specific.
|
402
450
|
|
451
|
+
## CORS
|
452
|
+
|
453
|
+
cross origin site requests
|
454
|
+
|
455
|
+
MyController < Blix::Rest::Controller
|
456
|
+
|
457
|
+
get '/info/crosssite' do
|
458
|
+
set_accept_cors
|
459
|
+
{:data=>'foo'}
|
460
|
+
end
|
461
|
+
|
462
|
+
options '/info/' crosssite' do
|
463
|
+
set_accept_cors, :headers=>'Content-Type',
|
464
|
+
end
|
465
|
+
|
466
|
+
end
|
467
|
+
|
468
|
+
within an `options` response the following parameters can be passes.
|
469
|
+
|
470
|
+
:origin=>'www.othersite.com' # specify specific allowed origin.
|
471
|
+
:methods => [:get] # allowed methods
|
472
|
+
:max_age => 86400 # maximum age this auth is valid
|
473
|
+
:headers => ['Content-Type','X-OTHER'] # allow additional headers
|
474
|
+
:credentials => true # allow requests with credentials
|
475
|
+
|
403
476
|
## Views
|
404
477
|
|
405
478
|
the location of your views defaults to `app/views` otherwise set it manually with:
|
@@ -488,6 +561,9 @@ NOTE : if you need to set up your database with users then you can use the follo
|
|
488
561
|
|
489
562
|
in features/support/world.rb .........
|
490
563
|
|
564
|
+
|
565
|
+
require 'blix/rest/cucumber'
|
566
|
+
|
491
567
|
class RestWorld
|
492
568
|
|
493
569
|
# add a hook to create the user in the database -
|
data/lib/blix/rest/controller.rb
CHANGED
@@ -94,6 +94,7 @@ module Blix::Rest
|
|
94
94
|
end
|
95
95
|
end
|
96
96
|
|
97
|
+
|
97
98
|
def form_hash
|
98
99
|
StringHash.new(req.POST)
|
99
100
|
end
|
@@ -166,6 +167,14 @@ module Blix::Rest
|
|
166
167
|
@_parameters
|
167
168
|
end
|
168
169
|
|
170
|
+
def route_params
|
171
|
+
@_parameters
|
172
|
+
end
|
173
|
+
|
174
|
+
def route_options
|
175
|
+
@_parameters
|
176
|
+
end
|
177
|
+
|
169
178
|
def response
|
170
179
|
@_response
|
171
180
|
end
|
@@ -232,6 +241,30 @@ module Blix::Rest
|
|
232
241
|
[login, password]
|
233
242
|
end
|
234
243
|
|
244
|
+
# set the cors headers
|
245
|
+
def set_accept_cors(opts={})
|
246
|
+
origin = opts[:origin] || env['HTTP_ORIGIN'] || '*'
|
247
|
+
origin = origin.to_s
|
248
|
+
if method=='options'
|
249
|
+
methods = [opts[:methods] || []].to_a.flatten
|
250
|
+
max_age = opts[:max_age] || 86400
|
251
|
+
headers = [opts[:headers] || []].to_a.flatten
|
252
|
+
credentials = opts.key?(:credentials) ? !!opts[:credentials] : true
|
253
|
+
methods = [:get] if methods.empty?
|
254
|
+
methods = methods.map{|m| m.to_s.upcase}
|
255
|
+
headers = ['Content-Type'] if headers.empty?
|
256
|
+
max_age = max_age.to_i
|
257
|
+
|
258
|
+
add_headers 'Access-Control-Allow-Origin' => origin,
|
259
|
+
'Access-Control-Allow-Methods'=>methods.join(', '),
|
260
|
+
'Access-Control-Allow-Headers'=>headers,
|
261
|
+
'Access-Control-Max-Age'=>max_age, #86400,
|
262
|
+
'Access-Control-Allow-Credentials'=>'true'
|
263
|
+
else
|
264
|
+
add_headers 'Access-Control-Allow-Origin' => origin
|
265
|
+
end
|
266
|
+
end
|
267
|
+
|
235
268
|
def set_status(value)
|
236
269
|
@_response.status = value.to_i
|
237
270
|
end
|
@@ -392,6 +425,9 @@ module Blix::Rest
|
|
392
425
|
response
|
393
426
|
end
|
394
427
|
|
428
|
+
def session_before(opts); end # empty session before hooh
|
429
|
+
def session_after; end # empty session after hook
|
430
|
+
|
395
431
|
#----------------------------------------------------------------------------------------------------------
|
396
432
|
|
397
433
|
def _setup(context, _verb, _path, _parameters)
|
@@ -524,16 +560,18 @@ module Blix::Rest
|
|
524
560
|
raise ServiceError, 'invalid format for this request' unless accept.index format
|
525
561
|
end
|
526
562
|
|
527
|
-
def _do_route_hook(
|
563
|
+
def _do_route_hook(route)
|
528
564
|
if @_route_hook
|
529
|
-
superclass._do_route_hook(
|
530
|
-
@_route_hook.call(
|
565
|
+
superclass._do_route_hook(route) if superclass.respond_to? :_do_route_hook
|
566
|
+
@_route_hook.call(route)
|
531
567
|
end
|
532
568
|
end
|
533
569
|
|
534
570
|
def route(verb, path, opts = {}, &blk)
|
571
|
+
path = '/' + path unless path[0] == '/'
|
535
572
|
path = String.new(path) # in case frozen.
|
536
|
-
|
573
|
+
route = Route.new(verb, path, opts)
|
574
|
+
_do_route_hook(route)
|
537
575
|
proc = lambda do |context|
|
538
576
|
unless opts[:force] && (opts[:accept] == :*)
|
539
577
|
check_format(opts[:accept], context.format)
|
@@ -541,6 +579,7 @@ module Blix::Rest
|
|
541
579
|
app = new
|
542
580
|
app._setup(context, verb, path, opts)
|
543
581
|
begin
|
582
|
+
app.session_before(opts)
|
544
583
|
app.before(opts)
|
545
584
|
app.__before
|
546
585
|
context.response = app.instance_eval( &blk )
|
@@ -549,6 +588,7 @@ module Blix::Rest
|
|
549
588
|
ensure
|
550
589
|
app.__after
|
551
590
|
app.after(opts, context.response)
|
591
|
+
app.session_after
|
552
592
|
context.response
|
553
593
|
end
|
554
594
|
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module Blix::Rest
|
2
|
+
|
3
|
+
# class used to represent a route and to allow manipulation of the
|
4
|
+
# options and path of the route before registrATION
|
5
|
+
|
6
|
+
class Route
|
7
|
+
|
8
|
+
attr_reader :verb, :path, :opts
|
9
|
+
alias_method :method, :verb
|
10
|
+
alias_method :options, :opts
|
11
|
+
|
12
|
+
def initialize(verb, path, opts)
|
13
|
+
@verb = verb.dup
|
14
|
+
@path = path
|
15
|
+
@opts = opts
|
16
|
+
end
|
17
|
+
|
18
|
+
def default_option(key, val)
|
19
|
+
opts[key.to_sym] = val unless opts.key?(key) || opts.key?(key.to_sym)
|
20
|
+
end
|
21
|
+
|
22
|
+
def path_prefix(prefix)
|
23
|
+
prefix = prefix.to_s
|
24
|
+
prefix = '/' + prefix unless prefix[0] == '/'
|
25
|
+
path.replace( prefix + path) unless path.start_with?(prefix)
|
26
|
+
end
|
27
|
+
|
28
|
+
def path=(val)
|
29
|
+
path.replace(val.to_s)
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,138 @@
|
|
1
|
+
module Blix::Rest
|
2
|
+
|
3
|
+
module Session
|
4
|
+
#----------------------------------------------------------------------------
|
5
|
+
#
|
6
|
+
# manage the session and authorization
|
7
|
+
#
|
8
|
+
#----------------------------------------------------------------------------
|
9
|
+
|
10
|
+
DAY = 24 * 60 * 60
|
11
|
+
MIN = 60
|
12
|
+
SESSION_NAME = 'blix'
|
13
|
+
|
14
|
+
SESSION_OPTS = {
|
15
|
+
#:secure=>true,
|
16
|
+
:http => false,
|
17
|
+
:samesite => :lax,
|
18
|
+
:path => Blix::Rest.full_path('/'),
|
19
|
+
:expire_secs => 30 * MIN, # 30 mins
|
20
|
+
:cleanup_every_secs => 5 * 60 # 5 minutes
|
21
|
+
#:max_age => nil # session cookie
|
22
|
+
}.freeze
|
23
|
+
|
24
|
+
|
25
|
+
def session_manager
|
26
|
+
self.class.get_session_manager
|
27
|
+
end
|
28
|
+
|
29
|
+
def session_name
|
30
|
+
self.class.get_session_name
|
31
|
+
end
|
32
|
+
|
33
|
+
def session_opts
|
34
|
+
self.class.get_session_opts
|
35
|
+
end
|
36
|
+
|
37
|
+
def session
|
38
|
+
@__session
|
39
|
+
end
|
40
|
+
|
41
|
+
def csrf_token
|
42
|
+
@__session['csrf'] ||= SecureRandom.hex(32)
|
43
|
+
end
|
44
|
+
|
45
|
+
def reset_session
|
46
|
+
raise 'login_session missing' unless @__session && @__session_id
|
47
|
+
session_manager.delete_session(@__session_id)
|
48
|
+
@__session_id = refresh_session_id(session_name, session_opts)
|
49
|
+
@__session['csrf'] = SecureRandom.hex(32)
|
50
|
+
session_manager.store_session(@__session_id, @__session)
|
51
|
+
end
|
52
|
+
|
53
|
+
# get a session id and use this to retrieve the session information - if any.
|
54
|
+
#
|
55
|
+
def session_before(opts)
|
56
|
+
@__session = {}
|
57
|
+
|
58
|
+
# do not set session on pages. that will be cached.
|
59
|
+
unless opts[:nosession] || opts[:cache]
|
60
|
+
@__session_id = get_session_id(session_name, session_opts)
|
61
|
+
@__session =
|
62
|
+
begin
|
63
|
+
session_manager.get_session(@__session_id)
|
64
|
+
rescue SessionExpiredError
|
65
|
+
@__session_id = refresh_session_id(session_name, session_opts)
|
66
|
+
session_manager.get_session(@__session_id)
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
if opts[:csrf]
|
71
|
+
if env["HTTP_X_CSRF_TOKEN"] != csrf_token
|
72
|
+
send_error("invalid csrf token")
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
end
|
77
|
+
|
78
|
+
# save the session hash before we go.
|
79
|
+
def session_after
|
80
|
+
session_manager.store_session(@__session_id, @__session) if @__session_id
|
81
|
+
end
|
82
|
+
|
83
|
+
private
|
84
|
+
|
85
|
+
def self.included(mod)
|
86
|
+
mod.extend Session::ClassMethods
|
87
|
+
end
|
88
|
+
|
89
|
+
module ClassMethods
|
90
|
+
|
91
|
+
def session_name(name)
|
92
|
+
@_sess_name = name.to_s
|
93
|
+
end
|
94
|
+
|
95
|
+
def session_opts(opts)
|
96
|
+
@_sess_custom_opts = opts
|
97
|
+
end
|
98
|
+
|
99
|
+
def session_manager(man)
|
100
|
+
raise ArgumentError, "incompatible session store" unless man.respond_to?(:get_session)
|
101
|
+
raise ArgumentError, "incompatible session store" unless man.respond_to?(:store_session)
|
102
|
+
raise ArgumentError, "incompatible session store" unless man.respond_to?(:delete_session)
|
103
|
+
@_sess_manager= man
|
104
|
+
end
|
105
|
+
|
106
|
+
def get_session_name
|
107
|
+
@_sess_name ||= begin
|
108
|
+
if superclass.respond_to?(:get_session_name)
|
109
|
+
superclass.get_session_name
|
110
|
+
else
|
111
|
+
SESSION_NAME
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
def get_session_opts
|
117
|
+
@_session_opts ||= begin
|
118
|
+
if superclass.respond_to?(:get_session_opts)
|
119
|
+
superclass.get_session_opts.merge(@_sess_custom_opts || {})
|
120
|
+
else
|
121
|
+
SESSION_OPTS.merge(@_sess_custom_opts || {})
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
def get_session_manager
|
127
|
+
@_sess_manager ||= begin
|
128
|
+
if superclass.respond_to?(:get_session_manager)
|
129
|
+
superclass.get_session_manager
|
130
|
+
else
|
131
|
+
Blix::RedisStore.new(get_session_opts)
|
132
|
+
end
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
end # ClassMethods
|
137
|
+
end # Session
|
138
|
+
end # Blix::Rest
|
data/lib/blix/rest/version.rb
CHANGED
data/lib/blix/rest.rb
CHANGED
@@ -150,7 +150,7 @@ require 'blix/rest/format_parser'
|
|
150
150
|
require 'blix/rest/request_mapper'
|
151
151
|
require 'blix/rest/cache'
|
152
152
|
require 'blix/rest/server'
|
153
|
-
|
153
|
+
require 'blix/rest/route'
|
154
154
|
require 'blix/rest/controller'
|
155
155
|
# require 'blix/rest/provider_controller'
|
156
156
|
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: blix-rest
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.8.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Clive Andrews
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2023-09-
|
11
|
+
date: 2023-09-24 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: httpclient
|
@@ -109,7 +109,9 @@ files:
|
|
109
109
|
- lib/blix/rest/request_mapper.rb
|
110
110
|
- lib/blix/rest/resource_cache.rb
|
111
111
|
- lib/blix/rest/response.rb
|
112
|
+
- lib/blix/rest/route.rb
|
112
113
|
- lib/blix/rest/server.rb
|
114
|
+
- lib/blix/rest/session.rb
|
113
115
|
- lib/blix/rest/string_hash.rb
|
114
116
|
- lib/blix/rest/version.rb
|
115
117
|
- lib/blix/utils.rb
|