lib/tynn/session.rb in tynn-1.4.0 vs lib/tynn/session.rb in tynn-2.0.0.alpha
- old
+ new
@@ -1,23 +1,25 @@
+# frozen_string_literal: true
+
class Tynn
- # Public: Adds simple cookie based session management. You can pass a secret
+ # Adds simple cookie based session management. You can pass a secret
# token to sign the cookie data, thus unauthorized means can't alter it.
#
- # Examples
- #
# require "tynn"
# require "tynn/session"
#
- # Tynn.plugin(Tynn::Session, secret: "__change_me__")
+ # Tynn.plugin(Tynn::Session, secret: "__change_me_not_secure__")
#
# Tynn.define do
- # root do
- # res.write(sprintf("hei %s", session[:username]))
- # end
+ # on("login") do
+ # post do
+ # # ...
#
- # on(:username) do |username|
- # session[:username] = username
+ # session[:user_id] = user.id
+ #
+ # res.redirect("/admin")
+ # end
# end
# end
#
# The following command generates a cryptographically secure secret ready
# to use:
@@ -26,31 +28,31 @@
#
# It's important to keep the token secret. Knowing the token allows an
# attacker to tamper the data. So, it's recommended to load the token
# from the environment.
#
- # Examples
- #
# Tynn.plugin(Tynn::Session, secret: ENV["SESSION_SECRET"])
#
- # Under the hood, Tynn::Session uses the +Rack::Session::Cookie+ middleware.
- # Thus, supports all the options available for this middleware:
+ # Under the hood, Tynn::Session uses the <tt>Rack::Session::Cookie</tt>
+ # middleware. Thus, supports all the options available for this middleware:
#
- # key - The name of the cookie. Defaults to <tt>"rack.session"</tt>.
+ # [key]
+ # The name of the cookie. Defaults to <tt>"rack.session"</tt>.
#
- # httponly - If +true+, sets the +HttpOnly+ flag. This mitigates the
- # risk of client side scripting accessing the cookie. Defaults
- # to +true+.
+ # [httponly]
+ # If <tt>true</tt>, sets the <tt>HttpOnly</tt> flag. This mitigates the
+ # risk of client side scripting accessing the cookie. Defaults to <tt>true</tt>.
#
- # secure - If +true+, sets the +Secure+ flag. This tells the browser
- # to only transmit the cookie over HTTPS. Defaults to `false`.
+ # [secure]
+ # If <tt>true</tt>, sets the <tt>Secure</tt> flag. This tells the browser
+ # to only transmit the cookie over HTTPS. Defaults to <tt>false</tt>.
#
- # expire_after - The lifespan of the cookie. If +nil+, the session cookie
- # is temporary and is no retained after the browser is
- # closed. Defaults to +nil+.
+ # [expire_after]
+ # The lifespan of the cookie. If <tt>nil</tt>, the session cookie is temporary
+ # and is no retained after the browser is closed. Defaults to <tt>nil</tt>.
#
- # Examples
+ # <tt></tt>
#
# Tynn.plugin(
# Tynn::Session,
# key: "app",
# secret: ENV["SESSION_SECRET"],
@@ -58,30 +60,62 @@
# httponly: true,
# secure: true
# )
#
module Session
- # Internal: Configures Rack::Session::Cookie middleware.
- def self.setup(app, options = {})
- if app.settings[:ssl]
- options = { secure: true }.merge(options)
+ SECRET_MIN_LENGTH = 30 # :nodoc:
+
+ def self.setup(app, options = {}) # :nodoc:
+ secret = options[:secret]
+
+ if secret.nil?
+ raise <<~MSG
+ No secret option provided to Tynn::Session.
+
+ Tynn::Session uses a secret token to sign the cookie data, thus
+ unauthorized means can't alter it. Please, add the secret option
+ to your code:
+
+ #{ app }.plugin(Tynn::Session, secret: "__a_long_random_secret__", ...)
+
+ If you're sharing your code publicly, make sure the secret key
+ is kept private. Knowing the secret allows an attacker to tamper
+ the data. You can use environment variables to store the secret:
+
+ #{ app }.plugin(Tynn::Session, secret: ENV.fetch("SESSION_SECRET"), ...)
+ MSG
end
- app.use(Rack::Session::Cookie, options)
+ if secret.length < SECRET_MIN_LENGTH
+ raise <<~MSG
+ The secret provided is shorter than the minimum length.
+
+ Make sure the secret is long and all random. You can generate a
+ secure secret key with:
+
+ $ ruby -r securerandom -e "puts SecureRandom.hex(64)"
+ MSG
+ end
+
+ app.use(Rack::Session::Cookie, {
+ coder: Rack::Session::Cookie::Base64::JSON.new,
+ hmac: OpenSSL::Digest::SHA256,
+ same_site: :Lax
+ }.merge(options))
end
module InstanceMethods
- # Public: Returns the session hash.
+ # Returns the session hash.
#
- # Examples
+ # session
+ # # => {}
#
- # session # => {}
- #
# session[:foo] = "foo"
- # session[:foo] # => "foo"
+ # session[:foo]
+ # # => "foo"
#
def session
- return req.session
+ req.session
end
end
end
end