# frozen_string_literal: true require 'active_support/concern' module Brevio::Session module WithSessionLogin extend ActiveSupport::Concern # By including this module into a Rails controller you will have access to the convenience methods # fetch_brevio_session(!) and brevio_logged_in? which acts as a wrapper around the decrypting of # predefined session cookies and sessions stored in Redis. # # We also require access to instance attributes like #request and the cookie jar, which are only # available in the context of a controller. # included do unless self <= ActionController::Base || instance_methods.include?(:session) raise 'Included Brevio::Session outside of controller' end end # Fetches the Brevio session from Redis, based on the encrypted key stored in the client's cookie. # Returns *nil* if there's no session present. # def fetch_brevio_session brevio_session, redis_key = fetch_session return nil if brevio_session.nil? if brevio_config.debug? brevio_config.logger.info "[brevio-session] Found session #{brevio_session.inspect}" end refresh_session(redis_key) unless params.transform_keys(&:underscore)[:no_session].present? brevio_session rescue RuntimeError => e brevio_config.logger.error "[brevio-session] #{e.message}" nil end # Calls the above function, but raises an exception if the session isn't present. def fetch_brevio_session! brevio_session, redis_key = fetch_session raise NilSession if brevio_session.nil? refresh_session(redis_key) unless params.transform_keys(&:underscore)[:no_session].present? brevio_session end # Returns a boolean flag indicating whether the current client has a Brevio session cookie set, # and whether this cookie contains a user ID. # def brevio_logged_in? brevio_session, = fetch_session brevio_session&.dig(:user_id).present? end private def brevio_config Config.config end def fetch_session brevio_config.logger.info '[brevio-session] Fetching Brevio session' cookie = request.cookie_jar[brevio_config.session_cookie] redis_key = Cookies::Parse.perform!(cookie) brevio_session = Redis.get(redis_key) raise NilSession if brevio_session.nil? [brevio_session.with_indifferent_access, redis_key] rescue RuntimeError => e brevio_config.logger.error "[brevio-session] --- 💣 Couldn't fetch Brevio session 💣 ---" brevio_config.logger.error "[brevio-session] #{e.message}" nil end # Refreshes the Brevio session cookie, avoding its expiry. This is helpful to # ensure the user stays logged in through interacting with the application. # def refresh_session(redis_key) brevio_config.logger.info '[brevio-session] Refreshing Brevio session' if brevio_config.debug? cookies[brevio_config.session_cookie] = { value: request.cookie_jar[brevio_config.session_cookie], domain: :all, expires: brevio_config.session_expire, httponly: true, secure: true } Redis.expire(redis_key, brevio_config.session_expire) rescue RuntimeError => e brevio_config.logger.error "[brevio-session] --- 💣 Couldn't refresh Brevio session 💣 ---" brevio_config.logger.error "[brevio-session] #{e.message}" end end end