blix-rest 0.7.2 → 0.8.2
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 +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
|