class SimpleWorkflow::Middleware
Rack middleware to detect and store detours and manage returns from detours.
Public Class Methods
new(app)
click to toggle source
# File lib/simple_workflow/middleware.rb, line 10 def initialize(app) @app = app @simple_workflow_encryptor = nil end
Public Instance Methods
call(env)
click to toggle source
# File lib/simple_workflow/middleware.rb, line 15 def call(env) store_detour_from_params(env) status, headers, body = @app.call(env) remove_old_detours(env) [status, headers, body] end
Private Instance Methods
encryptor(env)
click to toggle source
# File lib/simple_workflow/middleware.rb, line 95 def encryptor(env) return @simple_workflow_encryptor if @simple_workflow_encryptor @simple_workflow_encryptor = cookie_jar(env).instance_variable_get(:@encryptor) return @simple_workflow_encryptor if @simple_workflow_encryptor Rails.logger.warn 'simple_workflow: Could not get encryptor from the cookie jar' secret_key_base = Rails.application.config.secret_key_base || Rails.application.config.secret_token || SecureRandom.hex(64) key_generator = ActiveSupport::KeyGenerator.new(secret_key_base, iterations: 1000) key_generator = ActiveSupport::CachingKeyGenerator.new(key_generator) secret = key_generator.generate_key('encrypted cookie') sign_secret = key_generator.generate_key('signed encrypted cookie') @simple_workflow_encryptor = ActiveSupport::MessageEncryptor.new(secret, sign_secret) end
params(env)
click to toggle source
# File lib/simple_workflow/middleware.rb, line 32 def params(env) request(env).params end
remove_discarded_flashes(session)
click to toggle source
# File lib/simple_workflow/middleware.rb, line 75 def remove_discarded_flashes(session) return unless (old_flashes = session[:flash] && session[:flash]['discard']) Rails.logger.warn <<~MSG simple_workflow: found discarded flash entries: #{old_flashes}. Deleting them. MSG session[:flash]['flashes'] = session[:flash]['flashes'].except(*old_flashes) Rails.logger.warn "simple_workflow: session: #{session.to_hash}" end
remove_old_detours(env)
click to toggle source
# File lib/simple_workflow/middleware.rb, line 44 def remove_old_detours(env) return unless session(env).instance_variable_get(:@by).is_a?(ActionDispatch::Session::CookieStore) session_size = workflow_size = nil session = session(env) cookie_jar = cookie_jar(env) encryptor = encryptor(env) loop do ser_val = serialize_session(cookie_jar, session.to_hash) session_size = encryptor.encrypt_and_sign(ser_val).size wf_ser_val = serialize_session(cookie_jar, session[:detours]) workflow_size = encryptor.encrypt_and_sign(wf_ser_val).size break unless workflow_size >= 2048 || (session_size >= 3072 && session[:detours] && !session[:detours].empty?) Rails.logger.warn("Workflow too large (#{workflow_size}/#{session_size}). Dropping oldest detour.") session[:detours].shift reset_workflow(session) if session[:detours].empty? end Rails.logger.debug { <<~MSG } session: #{session_size} bytes, workflow(#{session[:detours].try(:size) || 0}): #{workflow_size} bytes MSG return unless session_size > 4096 Rails.logger.warn <<~MSG simple_workflow: session exceeds cookie size limit: #{session_size} bytes. Workflow empty! Not My Fault! MSG Rails.logger.warn "simple_workflow: session: #{session.to_hash}" remove_discarded_flashes(session) end
request(env)
click to toggle source
# File lib/simple_workflow/middleware.rb, line 24 def request(env) ActionDispatch::Request.new(env) end
serialize_session(cookie_jar, session)
click to toggle source
# File lib/simple_workflow/middleware.rb, line 86 def serialize_session(cookie_jar, session) cookie_jar.send(:serializer).send(:dump, session) end
session(env)
click to toggle source
# File lib/simple_workflow/middleware.rb, line 40 def session(env) env['rack.session'] end
store_detour_from_params(env)
click to toggle source
# File lib/simple_workflow/middleware.rb, line 111 def store_detour_from_params(env) store_detour_in_session(session(env), params(env)[:detour]) if params(env)[:detour] return unless params(env)[:return_from_detour] && session(env)[:detours] params_hash = params(env).to_h.reject { |k, _v| %i[detour return_from_detour].include? k.to_sym } pop_detour(session(env), params_hash) end