homura-runtime 0.3.3 → 0.3.4

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.
Files changed (79) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +7 -0
  3. data/lib/homura/runtime/version.rb +1 -1
  4. data/vendor/rack/auth/abstract/handler.rb +41 -0
  5. data/vendor/rack/auth/abstract/request.rb +51 -0
  6. data/vendor/rack/auth/basic.rb +58 -0
  7. data/vendor/rack/bad_request.rb +8 -0
  8. data/vendor/rack/body_proxy.rb +63 -0
  9. data/vendor/rack/builder.rb +315 -0
  10. data/vendor/rack/cascade.rb +67 -0
  11. data/vendor/rack/common_logger.rb +94 -0
  12. data/vendor/rack/conditional_get.rb +87 -0
  13. data/vendor/rack/config.rb +22 -0
  14. data/vendor/rack/constants.rb +68 -0
  15. data/vendor/rack/content_length.rb +34 -0
  16. data/vendor/rack/content_type.rb +33 -0
  17. data/vendor/rack/deflater.rb +159 -0
  18. data/vendor/rack/directory.rb +210 -0
  19. data/vendor/rack/etag.rb +71 -0
  20. data/vendor/rack/events.rb +172 -0
  21. data/vendor/rack/files.rb +224 -0
  22. data/vendor/rack/head.rb +25 -0
  23. data/vendor/rack/headers.rb +238 -0
  24. data/vendor/rack/lint.rb +1000 -0
  25. data/vendor/rack/lock.rb +29 -0
  26. data/vendor/rack/media_type.rb +42 -0
  27. data/vendor/rack/method_override.rb +56 -0
  28. data/vendor/rack/mime.rb +694 -0
  29. data/vendor/rack/mock.rb +3 -0
  30. data/vendor/rack/mock_request.rb +161 -0
  31. data/vendor/rack/mock_response.rb +147 -0
  32. data/vendor/rack/multipart/generator.rb +99 -0
  33. data/vendor/rack/multipart/parser.rb +586 -0
  34. data/vendor/rack/multipart/uploaded_file.rb +82 -0
  35. data/vendor/rack/multipart.rb +77 -0
  36. data/vendor/rack/null_logger.rb +48 -0
  37. data/vendor/rack/protection/authenticity_token.rb +256 -0
  38. data/vendor/rack/protection/base.rb +140 -0
  39. data/vendor/rack/protection/content_security_policy.rb +80 -0
  40. data/vendor/rack/protection/cookie_tossing.rb +77 -0
  41. data/vendor/rack/protection/escaped_params.rb +93 -0
  42. data/vendor/rack/protection/form_token.rb +25 -0
  43. data/vendor/rack/protection/frame_options.rb +39 -0
  44. data/vendor/rack/protection/http_origin.rb +43 -0
  45. data/vendor/rack/protection/ip_spoofing.rb +27 -0
  46. data/vendor/rack/protection/json_csrf.rb +60 -0
  47. data/vendor/rack/protection/path_traversal.rb +45 -0
  48. data/vendor/rack/protection/referrer_policy.rb +27 -0
  49. data/vendor/rack/protection/remote_referrer.rb +22 -0
  50. data/vendor/rack/protection/remote_token.rb +24 -0
  51. data/vendor/rack/protection/session_hijacking.rb +37 -0
  52. data/vendor/rack/protection/strict_transport.rb +41 -0
  53. data/vendor/rack/protection/version.rb +7 -0
  54. data/vendor/rack/protection/xss_header.rb +27 -0
  55. data/vendor/rack/protection.rb +58 -0
  56. data/vendor/rack/query_parser.rb +261 -0
  57. data/vendor/rack/recursive.rb +66 -0
  58. data/vendor/rack/reloader.rb +112 -0
  59. data/vendor/rack/request.rb +818 -0
  60. data/vendor/rack/response.rb +403 -0
  61. data/vendor/rack/rewindable_input.rb +116 -0
  62. data/vendor/rack/runtime.rb +35 -0
  63. data/vendor/rack/sendfile.rb +197 -0
  64. data/vendor/rack/session/abstract/id.rb +533 -0
  65. data/vendor/rack/session/constants.rb +13 -0
  66. data/vendor/rack/session/cookie.rb +292 -0
  67. data/vendor/rack/session/encryptor.rb +415 -0
  68. data/vendor/rack/session/pool.rb +76 -0
  69. data/vendor/rack/session/version.rb +10 -0
  70. data/vendor/rack/session.rb +12 -0
  71. data/vendor/rack/show_exceptions.rb +433 -0
  72. data/vendor/rack/show_status.rb +121 -0
  73. data/vendor/rack/static.rb +188 -0
  74. data/vendor/rack/tempfile_reaper.rb +44 -0
  75. data/vendor/rack/urlmap.rb +99 -0
  76. data/vendor/rack/utils.rb +631 -0
  77. data/vendor/rack/version.rb +17 -0
  78. data/vendor/rack.rb +66 -0
  79. metadata +76 -1
@@ -0,0 +1,533 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Released under the MIT License.
4
+ # Copyright, 2022-2023, by Samuel Williams.
5
+ # Copyright, 2022, by Jeremy Evans.
6
+
7
+ require 'time'
8
+ require 'securerandom'
9
+ # require 'digest/sha2'
10
+
11
+ require 'rack/constants'
12
+ require 'rack/request'
13
+ require 'rack/response'
14
+
15
+ require_relative '../constants'
16
+
17
+ module Rack
18
+
19
+ module Session
20
+
21
+ class SessionId
22
+ ID_VERSION = 2
23
+
24
+ attr_reader :public_id
25
+
26
+ def initialize(public_id)
27
+ @public_id = public_id
28
+ end
29
+
30
+ def private_id
31
+ "#{ID_VERSION}::#{hash_sid(public_id)}"
32
+ end
33
+
34
+ alias :cookie_value :public_id
35
+ alias :to_s :public_id
36
+
37
+ def empty?; false; end
38
+ def inspect; public_id.inspect; end
39
+
40
+ private
41
+
42
+ def hash_sid(sid)
43
+ Digest::SHA256.hexdigest(sid)
44
+ end
45
+ end
46
+
47
+ module Abstract
48
+ # SessionHash is responsible to lazily load the session from store.
49
+
50
+ class SessionHash
51
+ include Enumerable
52
+ attr_writer :id
53
+
54
+ Unspecified = Object.new
55
+
56
+ def self.find(req)
57
+ req.get_header RACK_SESSION
58
+ end
59
+
60
+ def self.set(req, session)
61
+ req.set_header RACK_SESSION, session
62
+ end
63
+
64
+ def self.set_options(req, options)
65
+ req.set_header RACK_SESSION_OPTIONS, options.dup
66
+ end
67
+
68
+ def initialize(store, req)
69
+ @store = store
70
+ @req = req
71
+ @loaded = false
72
+ end
73
+
74
+ def id
75
+ return @id if @loaded or instance_variable_defined?(:@id)
76
+ @id = @store.send(:extract_session_id, @req)
77
+ end
78
+
79
+ def options
80
+ @req.session_options
81
+ end
82
+
83
+ def each(&block)
84
+ load_for_read!
85
+ @data.each(&block)
86
+ end
87
+
88
+ def [](key)
89
+ load_for_read!
90
+ @data[key.to_s]
91
+ end
92
+
93
+ def dig(key, *keys)
94
+ load_for_read!
95
+ @data.dig(key.to_s, *keys)
96
+ end
97
+
98
+ def fetch(key, default = Unspecified, &block)
99
+ load_for_read!
100
+ if default == Unspecified
101
+ @data.fetch(key.to_s, &block)
102
+ else
103
+ @data.fetch(key.to_s, default, &block)
104
+ end
105
+ end
106
+
107
+ def has_key?(key)
108
+ load_for_read!
109
+ @data.has_key?(key.to_s)
110
+ end
111
+ alias :key? :has_key?
112
+ alias :include? :has_key?
113
+
114
+ def []=(key, value)
115
+ load_for_write!
116
+ @data[key.to_s] = value
117
+ end
118
+ alias :store :[]=
119
+
120
+ def clear
121
+ load_for_write!
122
+ @data.clear
123
+ end
124
+
125
+ def destroy
126
+ clear
127
+ @id = @store.send(:delete_session, @req, id, options)
128
+ end
129
+
130
+ def to_hash
131
+ load_for_read!
132
+ @data.dup
133
+ end
134
+
135
+ def update(hash)
136
+ load_for_write!
137
+ @data.update(stringify_keys(hash))
138
+ end
139
+ alias :merge! :update
140
+
141
+ def replace(hash)
142
+ load_for_write!
143
+ @data.replace(stringify_keys(hash))
144
+ end
145
+
146
+ def delete(key)
147
+ load_for_write!
148
+ @data.delete(key.to_s)
149
+ end
150
+
151
+ def inspect
152
+ if loaded?
153
+ @data.inspect
154
+ else
155
+ "#<#{self.class}:0x#{self.object_id.to_s(16)} not yet loaded>"
156
+ end
157
+ end
158
+
159
+ def exists?
160
+ return @exists if instance_variable_defined?(:@exists)
161
+ @data = {}
162
+ @exists = @store.send(:session_exists?, @req)
163
+ end
164
+
165
+ def loaded?
166
+ @loaded
167
+ end
168
+
169
+ def empty?
170
+ load_for_read!
171
+ @data.empty?
172
+ end
173
+
174
+ def keys
175
+ load_for_read!
176
+ @data.keys
177
+ end
178
+
179
+ def values
180
+ load_for_read!
181
+ @data.values
182
+ end
183
+
184
+ private
185
+
186
+ def load_for_read!
187
+ load! if !loaded? && exists?
188
+ end
189
+
190
+ def load_for_write!
191
+ load! unless loaded?
192
+ end
193
+
194
+ def load!
195
+ @id, session = @store.send(:load_session, @req)
196
+ @data = stringify_keys(session)
197
+ @loaded = true
198
+ end
199
+
200
+ def stringify_keys(other)
201
+ # Use transform_keys after dropping Ruby 2.4 support
202
+ hash = {}
203
+ other.to_hash.each do |key, value|
204
+ hash[key.to_s] = value
205
+ end
206
+ hash
207
+ end
208
+ end
209
+
210
+ # ID sets up a basic framework for implementing an id based sessioning
211
+ # service. Cookies sent to the client for maintaining sessions will only
212
+ # contain an id reference. Only #find_session, #write_session and
213
+ # #delete_session are required to be overwritten.
214
+ #
215
+ # All parameters are optional.
216
+ # * :key determines the name of the cookie, by default it is
217
+ # 'rack.session'
218
+ # * :path, :domain, :expire_after, :secure, :httponly, and :same_site set
219
+ # the related cookie options as by Rack::Response#set_cookie
220
+ # * :skip will not a set a cookie in the response nor update the session state
221
+ # * :defer will not set a cookie in the response but still update the session
222
+ # state if it is used with a backend
223
+ # * :renew (implementation dependent) will prompt the generation of a new
224
+ # session id, and migration of data to be referenced at the new id. If
225
+ # :defer is set, it will be overridden and the cookie will be set.
226
+ # * :sidbits sets the number of bits in length that a generated session
227
+ # id will be.
228
+ #
229
+ # These options can be set on a per request basis, at the location of
230
+ # <tt>env['rack.session.options']</tt>. Additionally the id of the
231
+ # session can be found within the options hash at the key :id. It is
232
+ # highly not recommended to change its value.
233
+ #
234
+ # Is Rack::Utils::Context compatible.
235
+ #
236
+ # Not included by default; you must require 'rack/session/abstract/id'
237
+ # to use.
238
+
239
+ class Persisted
240
+ DEFAULT_OPTIONS = {
241
+ key: RACK_SESSION,
242
+ path: '/',
243
+ domain: nil,
244
+ expire_after: nil,
245
+ secure: false,
246
+ httponly: true,
247
+ defer: false,
248
+ renew: false,
249
+ sidbits: 128,
250
+ cookie_only: true,
251
+ secure_random: ::SecureRandom
252
+ }.freeze
253
+
254
+ attr_reader :key, :default_options, :sid_secure, :same_site
255
+
256
+ def initialize(app, options = {})
257
+ @app = app
258
+ @default_options = self.class::DEFAULT_OPTIONS.merge(options)
259
+ @key = @default_options.delete(:key)
260
+ @cookie_only = @default_options.delete(:cookie_only)
261
+ @same_site = @default_options.delete(:same_site)
262
+ initialize_sid
263
+ end
264
+
265
+ def call(env)
266
+ context(env)
267
+ end
268
+
269
+ def context(env, app = @app)
270
+ req = make_request env
271
+ prepare_session(req)
272
+ status, headers, body = app.call(req.env)
273
+ res = Rack::Response::Raw.new status, headers
274
+ commit_session(req, res)
275
+ [status, headers, body]
276
+ end
277
+
278
+ private
279
+
280
+ def make_request(env)
281
+ Rack::Request.new env
282
+ end
283
+
284
+ def initialize_sid
285
+ @sidbits = @default_options[:sidbits]
286
+ @sid_secure = @default_options[:secure_random]
287
+ @sid_length = @sidbits / 4
288
+ end
289
+
290
+ # Generate a new session id using Ruby #rand. The size of the
291
+ # session id is controlled by the :sidbits option.
292
+ # Monkey patch this to use custom methods for session id generation.
293
+
294
+ def generate_sid(secure = @sid_secure)
295
+ if secure
296
+ secure.hex(@sid_length)
297
+ else
298
+ "%0#{@sid_length}x" % Kernel.rand(2**@sidbits - 1)
299
+ end
300
+ rescue NotImplementedError
301
+ generate_sid(false)
302
+ end
303
+
304
+ # Sets the lazy session at 'rack.session' and places options and session
305
+ # metadata into 'rack.session.options'.
306
+
307
+ def prepare_session(req)
308
+ session_was = req.get_header RACK_SESSION
309
+ session = session_class.new(self, req)
310
+ req.set_header RACK_SESSION, session
311
+ req.set_header RACK_SESSION_OPTIONS, @default_options.dup
312
+ session.merge! session_was if session_was
313
+ end
314
+
315
+ # Extracts the session id from provided cookies and passes it and the
316
+ # environment to #find_session.
317
+
318
+ def load_session(req)
319
+ sid = current_session_id(req)
320
+ sid, session = find_session(req, sid)
321
+ [sid, session || {}]
322
+ end
323
+
324
+ # Extract session id from request object.
325
+
326
+ def extract_session_id(request)
327
+ sid = request.cookies[@key]
328
+ sid ||= request.params[@key] unless @cookie_only
329
+ sid
330
+ end
331
+
332
+ # Returns the current session id from the SessionHash.
333
+
334
+ def current_session_id(req)
335
+ req.get_header(RACK_SESSION).id
336
+ end
337
+
338
+ # Check if the session exists or not.
339
+
340
+ def session_exists?(req)
341
+ value = current_session_id(req)
342
+ value && !value.empty?
343
+ end
344
+
345
+ # Session should be committed if it was loaded, any of specific options like :renew, :drop
346
+ # or :expire_after was given and the security permissions match. Skips if skip is given.
347
+
348
+ def commit_session?(req, session, options)
349
+ if options[:skip]
350
+ false
351
+ else
352
+ has_session = loaded_session?(session) || forced_session_update?(session, options)
353
+ has_session && security_matches?(req, options)
354
+ end
355
+ end
356
+
357
+ def loaded_session?(session)
358
+ !session.is_a?(session_class) || session.loaded?
359
+ end
360
+
361
+ def forced_session_update?(session, options)
362
+ force_options?(options) && session && !session.empty?
363
+ end
364
+
365
+ def force_options?(options)
366
+ options.values_at(:max_age, :renew, :drop, :defer, :expire_after).any?
367
+ end
368
+
369
+ def security_matches?(request, options)
370
+ return true unless options[:secure]
371
+ request.ssl?
372
+ end
373
+
374
+ # Acquires the session from the environment and the session id from
375
+ # the session options and passes them to #write_session. If successful
376
+ # and the :defer option is not true, a cookie will be added to the
377
+ # response with the session's id.
378
+
379
+ def commit_session(req, res)
380
+ session = req.get_header RACK_SESSION
381
+ options = session.options
382
+
383
+ if options[:drop] || options[:renew]
384
+ session_id = delete_session(req, session.id || generate_sid, options)
385
+ return unless session_id
386
+ end
387
+
388
+ return unless commit_session?(req, session, options)
389
+
390
+ session.send(:load!) unless loaded_session?(session)
391
+ session_id ||= session.id
392
+ session_data = session.to_hash.delete_if { |k, v| v.nil? }
393
+
394
+ if not data = write_session(req, session_id, session_data, options)
395
+ req.get_header(RACK_ERRORS).puts("Warning! #{self.class.name} failed to save session. Content dropped.")
396
+ elsif options[:defer] and not options[:renew]
397
+ req.get_header(RACK_ERRORS).puts("Deferring cookie for #{session_id}") if $VERBOSE
398
+ else
399
+ cookie = Hash.new
400
+ cookie[:value] = cookie_value(data)
401
+ cookie[:expires] = Time.now + options[:expire_after] if options[:expire_after]
402
+ cookie[:expires] = Time.now + options[:max_age] if options[:max_age]
403
+
404
+ if @same_site.respond_to? :call
405
+ cookie[:same_site] = @same_site.call(req, res)
406
+ else
407
+ cookie[:same_site] = @same_site
408
+ end
409
+ set_cookie(req, res, cookie.merge!(options))
410
+ end
411
+ end
412
+ public :commit_session
413
+
414
+ def cookie_value(data)
415
+ data
416
+ end
417
+
418
+ # Sets the cookie back to the client with session id. We skip the cookie
419
+ # setting if the value didn't change (sid is the same) or expires was given.
420
+
421
+ def set_cookie(request, response, cookie)
422
+ if request.cookies[@key] != cookie[:value] || cookie[:expires]
423
+ response.set_cookie(@key, cookie)
424
+ end
425
+ end
426
+
427
+ # Allow subclasses to prepare_session for different Session classes
428
+
429
+ def session_class
430
+ SessionHash
431
+ end
432
+
433
+ # All thread safety and session retrieval procedures should occur here.
434
+ # Should return [session_id, session].
435
+ # If nil is provided as the session id, generation of a new valid id
436
+ # should occur within.
437
+
438
+ def find_session(env, sid)
439
+ raise '#find_session not implemented.'
440
+ end
441
+
442
+ # All thread safety and session storage procedures should occur here.
443
+ # Must return the session id if the session was saved successfully, or
444
+ # false if the session could not be saved.
445
+
446
+ def write_session(req, sid, session, options)
447
+ raise '#write_session not implemented.'
448
+ end
449
+
450
+ # All thread safety and session destroy procedures should occur here.
451
+ # Should return a new session id or nil if options[:drop]
452
+
453
+ def delete_session(req, sid, options)
454
+ raise '#delete_session not implemented'
455
+ end
456
+ end
457
+
458
+ class PersistedSecure < Persisted
459
+ class SecureSessionHash < SessionHash
460
+ def [](key)
461
+ if key == "session_id"
462
+ load_for_read!
463
+ case id
464
+ when SessionId
465
+ id.public_id
466
+ else
467
+ id
468
+ end
469
+ else
470
+ super
471
+ end
472
+ end
473
+ end
474
+
475
+ def generate_sid(*)
476
+ public_id = super
477
+
478
+ SessionId.new(public_id)
479
+ end
480
+
481
+ def extract_session_id(*)
482
+ public_id = super
483
+ public_id && SessionId.new(public_id)
484
+ end
485
+
486
+ private
487
+
488
+ def session_class
489
+ SecureSessionHash
490
+ end
491
+
492
+ def cookie_value(data)
493
+ data.cookie_value
494
+ end
495
+ end
496
+
497
+ class ID < Persisted
498
+ def self.inherited(klass)
499
+ k = klass.ancestors.find { |kl| kl.respond_to?(:superclass) && kl.superclass == ID }
500
+ unless k.instance_variable_defined?(:"@_rack_warned")
501
+ warn "#{klass} is inheriting from #{ID}. Inheriting from #{ID} is deprecated, please inherit from #{Persisted} instead" if $VERBOSE
502
+ k.instance_variable_set(:"@_rack_warned", true)
503
+ end
504
+ super
505
+ end
506
+
507
+ # All thread safety and session retrieval procedures should occur here.
508
+ # Should return [session_id, session].
509
+ # If nil is provided as the session id, generation of a new valid id
510
+ # should occur within.
511
+
512
+ def find_session(req, sid)
513
+ get_session req.env, sid
514
+ end
515
+
516
+ # All thread safety and session storage procedures should occur here.
517
+ # Must return the session id if the session was saved successfully, or
518
+ # false if the session could not be saved.
519
+
520
+ def write_session(req, sid, session, options)
521
+ set_session req.env, sid, session, options
522
+ end
523
+
524
+ # All thread safety and session destroy procedures should occur here.
525
+ # Should return a new session id or nil if options[:drop]
526
+
527
+ def delete_session(req, sid, options)
528
+ destroy_session req.env, sid, options
529
+ end
530
+ end
531
+ end
532
+ end
533
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Released under the MIT License.
4
+ # Copyright, 2022-2023, by Samuel Williams.
5
+ # Copyright, 2022, by Jeremy Evans.
6
+
7
+ module Rack
8
+ module Session
9
+ RACK_SESSION = 'rack.session'
10
+ RACK_SESSION_OPTIONS = 'rack.session.options'
11
+ RACK_SESSION_UNPACKED_COOKIE_DATA = 'rack.session.unpacked_cookie_data'
12
+ end
13
+ end