brevio-session 0.1

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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: c515c318b1b9d9dcc8f157a9fd507511d2462d43ddb62de9f439ce55e21c5da3
4
+ data.tar.gz: d104172c65410bf4e52d8087a2e8bcb30220cf1ef18d75d7d3f0a5eeaba2cb7d
5
+ SHA512:
6
+ metadata.gz: 5cfcdc09b39e5162e49d1ae0f386dfa59a5e5c62a6a80c7e763d5b67fd029bea0b422efba229caf6c525e1e9011f4d84bdf48ada003d92b5918c7a00da80b244
7
+ data.tar.gz: f2deb2e307e1bdcf2f91744bffd969ef5a48dd34638079b22693ca6ba0ac38cdbe342a7ecd525b12b666faff15338ec682add782738693f1ddf0ad0e69288e2e
data/.gitignore ADDED
@@ -0,0 +1,2 @@
1
+ .byebug_history
2
+ *.gem
data/.rubocop.yml ADDED
@@ -0,0 +1,56 @@
1
+ AllCops:
2
+ NewCops: enable
3
+ TargetRubyVersion: 3.2
4
+
5
+ Layout/EmptyLineAfterGuardClause:
6
+ Enabled: false
7
+
8
+ Layout/FirstHashElementIndentation:
9
+ EnforcedStyle: consistent
10
+
11
+ Layout/HashAlignment:
12
+ EnforcedHashRocketStyle: table
13
+
14
+ Layout/LineLength:
15
+ Max: 100
16
+
17
+ Layout/MultilineMethodCallIndentation:
18
+ EnforcedStyle: indented_relative_to_receiver
19
+
20
+ Metrics/BlockLength:
21
+ Exclude:
22
+ - "*.gemspec"
23
+
24
+ Naming/AccessorMethodName:
25
+ Exclude:
26
+ - test/**/*
27
+
28
+ Metrics/AbcSize:
29
+ Exclude:
30
+ - test/**/stubs/**/*
31
+
32
+ Metrics/ClassLength:
33
+ Exclude:
34
+ - test/**/stubs/**/*
35
+
36
+ Metrics/MethodLength:
37
+ Exclude:
38
+ - test/**/*
39
+
40
+ Style/Alias:
41
+ Exclude:
42
+ - test/**/*
43
+
44
+ Style/ClassAndModuleChildren:
45
+ Enabled: false
46
+
47
+ Style/ClassVars:
48
+ Exclude:
49
+ - test/**/*
50
+
51
+ Style/Documentation:
52
+ Enabled: false
53
+
54
+ Style/ModuleFunction:
55
+ Enabled: true
56
+ EnforcedStyle: extend_self
data/.ruby-version ADDED
@@ -0,0 +1 @@
1
+ 3.2.0
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ # frozen_string_literal: true
2
+
3
+ source 'https://rubygems.org'
4
+ gemspec
data/Gemfile.lock ADDED
@@ -0,0 +1,102 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ brevio-session (0.1)
5
+ actionpack (~> 7.0.3)
6
+ redis (~> 5.0)
7
+ zeitwerk (~> 2.6.7)
8
+
9
+ GEM
10
+ remote: https://rubygems.org/
11
+ specs:
12
+ actionpack (7.0.4)
13
+ actionview (= 7.0.4)
14
+ activesupport (= 7.0.4)
15
+ rack (~> 2.0, >= 2.2.0)
16
+ rack-test (>= 0.6.3)
17
+ rails-dom-testing (~> 2.0)
18
+ rails-html-sanitizer (~> 1.0, >= 1.2.0)
19
+ actionview (7.0.4)
20
+ activesupport (= 7.0.4)
21
+ builder (~> 3.1)
22
+ erubi (~> 1.4)
23
+ rails-dom-testing (~> 2.0)
24
+ rails-html-sanitizer (~> 1.1, >= 1.2.0)
25
+ activesupport (7.0.4)
26
+ concurrent-ruby (~> 1.0, >= 1.0.2)
27
+ i18n (>= 1.6, < 2)
28
+ minitest (>= 5.1)
29
+ tzinfo (~> 2.0)
30
+ ast (2.4.2)
31
+ builder (3.2.4)
32
+ concurrent-ruby (1.1.10)
33
+ connection_pool (2.4.0)
34
+ crass (1.0.6)
35
+ debug (1.5.0)
36
+ irb (>= 1.3.6)
37
+ reline (>= 0.2.7)
38
+ erubi (1.11.0)
39
+ i18n (1.12.0)
40
+ concurrent-ruby (~> 1.0)
41
+ io-console (0.6.0)
42
+ irb (1.6.1)
43
+ reline (>= 0.3.0)
44
+ json (2.6.2)
45
+ loofah (2.19.0)
46
+ crass (~> 1.0.2)
47
+ nokogiri (>= 1.5.9)
48
+ mini_portile2 (2.8.1)
49
+ minitest (5.16.3)
50
+ nokogiri (1.13.9)
51
+ mini_portile2 (~> 2.8.0)
52
+ racc (~> 1.4)
53
+ parallel (1.22.1)
54
+ parser (3.1.2.1)
55
+ ast (~> 2.4.1)
56
+ racc (1.6.1)
57
+ rack (2.2.4)
58
+ rack-test (2.0.2)
59
+ rack (>= 1.3)
60
+ rails-dom-testing (2.0.3)
61
+ activesupport (>= 4.2.0)
62
+ nokogiri (>= 1.6)
63
+ rails-html-sanitizer (1.4.3)
64
+ loofah (~> 2.3)
65
+ rainbow (3.1.1)
66
+ redis (5.0.6)
67
+ redis-client (>= 0.9.0)
68
+ redis-client (0.14.1)
69
+ connection_pool
70
+ regexp_parser (2.5.0)
71
+ reline (0.3.2)
72
+ io-console (~> 0.5)
73
+ rexml (3.2.5)
74
+ rubocop (1.36.0)
75
+ json (~> 2.3)
76
+ parallel (~> 1.10)
77
+ parser (>= 3.1.2.1)
78
+ rainbow (>= 2.2.2, < 4.0)
79
+ regexp_parser (>= 1.8, < 3.0)
80
+ rexml (>= 3.2.5, < 4.0)
81
+ rubocop-ast (>= 1.20.1, < 2.0)
82
+ ruby-progressbar (~> 1.7)
83
+ unicode-display_width (>= 1.4.0, < 3.0)
84
+ rubocop-ast (1.21.0)
85
+ parser (>= 3.1.1.0)
86
+ ruby-progressbar (1.11.0)
87
+ tzinfo (2.0.5)
88
+ concurrent-ruby (~> 1.0)
89
+ unicode-display_width (2.2.0)
90
+ zeitwerk (2.6.7)
91
+
92
+ PLATFORMS
93
+ arm64-darwin-21
94
+
95
+ DEPENDENCIES
96
+ brevio-session!
97
+ bundler (~> 2.1)
98
+ debug (~> 1.5.0, <= 1.6.0)
99
+ rubocop (~> 1.35)
100
+
101
+ BUNDLED WITH
102
+ 2.3.22
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2018 Nicolay Hvidsten
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,82 @@
1
+ # Brevio Session
2
+
3
+ This gem is a thin wrapper around the Brevio HTTP session, which is created by the [Brevio ID](https://github.com/team-brevio/id) service, and stored in Redis. The HTTP session is shared by all customer-facing Brevio services, enabling single sign-on.
4
+
5
+ The session is shared by storing the encrypted Redis key in an agreed-upon cookie (`BREVIO_ID_COOKIE`). The passphrase used for the encryption is also agreed-upon between services (`BREVIO_ID_SECRET_KEY`).
6
+
7
+ The gem provides three utility functions, used in the application controllers:
8
+
9
+ - `fetch_brevio_session`: Loads the Brevio session from Redis and returns a `HashWithIndifferentAccess` wrapper around it.
10
+ - `fetch_brevio_session!`: Same as above, but raises an error if the session isn't present.
11
+ - `brevio_logged_in?`: Returns a boolean flag indicating whether there exists a current Brevio session.
12
+
13
+ ## Installation
14
+
15
+ ```ruby
16
+ # Gemfile
17
+ gem 'brevio-session'
18
+
19
+ # config/initializers/brevio_session.rb
20
+ Brevio::Session::Config.configure do |config|
21
+ config.debug = ENV.fetch('BREVIO_SESSION_DEBUG', false) # Logs additional information for session retrieval
22
+ config.production = Rails.env.production?
23
+ config.redis = Brevio::Redis::Client.new(ENV.fetch('BREVIO_ID_REDIS_URL'))
24
+ config.secret_key = ENV.fetch('BREVIO_ID_SECRET_KEY')
25
+ config.session_cookie = ENV.fetch('BREVIO_ID_COOKIE')
26
+ config.session_expire = Integer(ENV.fetch('BREVIO_ID_EXPIRE')).minutes
27
+ end
28
+ ```
29
+
30
+ ## Usage
31
+
32
+ To gain access to the utility functions mentioned above, you need to include the `Brevio::Session` module in
33
+ any Rails controller. The module is a [Rails Concern](https://api.rubyonrails.org/v7.0.4/classes/ActiveSupport/Concern.html) which ensures it is being included in the correct context.
34
+
35
+ ```ruby
36
+ class ApiController
37
+ include Brevio::Session
38
+
39
+ def action
40
+ brevio_session = fetch_brevio_session
41
+ puts brevio_session
42
+ # => { user_id: 1, audit_company_id: 1, user_stamp: '2022-01-0107:39:58.281894000' }
43
+ end
44
+ end
45
+ ```
46
+
47
+ The session itself contains the following information (subject to change in Brevio ID):
48
+
49
+ - `user_id`: The primary key for the user in the Brevio ID database.
50
+ - `audit_company_id`: The primary key for the audit company in the Brevio ID database.
51
+ - `user_stamp`: Timestamp indicating when the user was last updated in Brevio ID.
52
+
53
+ ## Testing
54
+
55
+ Since we want to test features with logged-in users, we need to be able to emulate a shared Brevio session.
56
+
57
+ First off, we need to mock the Redis session, which is done by calling the `Brevio::Session::Testing.setup!` function.
58
+
59
+ ```ruby
60
+ Brevio::Session::Testing.setup!(logger: Rails.logger)
61
+ # => '--- 👨‍🔬 Setting up Brevio Session gem for testing 👨‍🔬 ---'
62
+ ```
63
+
64
+ We can then simulate a logged-in user by calling the `Brevio::Session::Testing.brevio_login` function.
65
+
66
+ ```ruby
67
+ class TestCase < ActionDispatch::IntegrationTest
68
+ include Brevio::Session::Testing
69
+
70
+ let(:user) { create(:user) }
71
+
72
+ test 'is logged in' do
73
+ brevio_login(user)
74
+ get(dashboard_path(user))
75
+ assert_response(:ok)
76
+ end
77
+ end
78
+ ```
79
+
80
+ ## License
81
+
82
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ Gem::Specification.new do |spec|
4
+ spec.name = 'brevio-session'
5
+ spec.version = '0.1'
6
+ spec.authors = ['Brevio AS']
7
+ spec.email = ['support@brevio.com']
8
+ spec.files = `git ls-files -z`.split("\0")
9
+
10
+ spec.homepage = 'https://github.com/team-brevio/brevio-session'
11
+ spec.summary = 'Brevio session wrapper'
12
+ spec.required_ruby_version = '3.2'
13
+ spec.description = 'Wrapper around HTTP session set by Brevio ID'
14
+ spec.license = 'MIT'
15
+
16
+ spec.add_development_dependency 'bundler', '~> 2.1'
17
+ spec.add_development_dependency 'debug', '~> 1.5.0', '<= 1.6.0'
18
+ spec.add_development_dependency 'rubocop', '~> 1.35'
19
+ spec.add_dependency 'actionpack', '~> 7.0.3'
20
+ spec.add_dependency 'redis', '~> 5.0'
21
+ spec.add_dependency 'zeitwerk', '~> 2.6.7'
22
+ spec.metadata['rubygems_mfa_required'] = 'true'
23
+ end
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Brevio::Session::Config
4
+ extend self
5
+
6
+ attr_accessor :config
7
+
8
+ def configure
9
+ self.config ||= Configuration.new
10
+ yield(config)
11
+ end
12
+
13
+ class Configuration
14
+ attr_accessor(
15
+ :debug,
16
+ :encryption_key,
17
+ :logger,
18
+ :production,
19
+ :redis,
20
+ :session_cookie,
21
+ :session_expire
22
+ )
23
+ alias debug? debug
24
+ alias production? production
25
+ end
26
+
27
+ module Redis
28
+ module Prefixes
29
+ AUDIT_COMPANY = 'brevio-id:audit-company'
30
+ SESSION = 'brevio-id:session'
31
+ USER = 'brevio-id:user'
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,39 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Brevio::Session
4
+ module Cookies::Parse
5
+ extend self
6
+
7
+ def perform!(cookie)
8
+ raise NilSession if cookie.nil?
9
+ data, iv, auth_tag = cookie.split('--').map { |value| Base64.decode64(value) }
10
+ cipher = OpenSSL::Cipher.new(CIPHER)
11
+ secret = OpenSSL::PKCS5.pbkdf2_hmac_sha1(brevio_config.encryption_key,
12
+ SALT, 1000, cipher.key_len)
13
+
14
+ cipher.decrypt
15
+ cipher.key = secret
16
+ cipher.iv = iv
17
+ cipher.auth_tag = auth_tag
18
+ cipher.auth_data = ''
19
+
20
+ cookie_payload = cipher.update(data)
21
+ cookie_payload << cipher.final
22
+ cookie_payload = JSON.parse(cookie_payload)
23
+ key = JSON.parse(Base64.decode64(cookie_payload['_rails']['message']))
24
+
25
+ "#{Config::Redis::Prefixes::SESSION}:#{key}"
26
+ end
27
+
28
+ private
29
+
30
+ # https://github.com/team-brevio/brevio-id-gem/blob/master/lib/brevio_id/session/cookie_jar.rb#L79
31
+ CIPHER = 'aes-256-gcm'
32
+ # https://github.com/team-brevio/brevio-id-gem/blob/master/lib/brevio_id/session/cookie_jar.rb#L84
33
+ SALT = 'authenticated encrypted cookie'
34
+
35
+ def brevio_config
36
+ Config.config
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Brevio::Session
4
+ module Redis
5
+ extend self
6
+
7
+ def get(key)
8
+ brevio_config.redis.get(key)
9
+ end
10
+
11
+ def expire(key, exp)
12
+ brevio_config.redis.expire(key, exp)
13
+ end
14
+
15
+ private
16
+
17
+ def brevio_config
18
+ Config.config
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,62 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Brevio::Session
4
+ # Module used to enable testing for controllers using the Brevio session.
5
+ # Mocks a login to a shared redis, with keys generated by the Brevio::Session::CookieJar.
6
+ #
7
+ module Testing
8
+ # Simulates a user with a shared Brevio session. We can specify which *brevio_id* the
9
+ # mocked ID service should return (as well as a custom last updated_at timestamp).
10
+ #
11
+ # The user needs to have the following methods defined: #brevio_id, #audit_company
12
+ #
13
+ def brevio_login(user, updated_at: Time.current.yesterday)
14
+ redis_key = SecureRandom.hex(6)
15
+
16
+ session_hash = { user_id: user.brevio_id,
17
+ audit_company_id: user.audit_company.brevio_id,
18
+ user_stamp: updated_at }
19
+
20
+ Testing.config.logger.info "setting Brevio session to #{session_hash}"
21
+
22
+ Testing.config.gem_config.redis.set(
23
+ redis_key,
24
+ session_hash
25
+ )
26
+ set_cookie(redis_key)
27
+ end
28
+
29
+ def brevio_logout
30
+ cookies[Testing.config.gem_config.session_cookie] = nil
31
+ end
32
+
33
+ # rubocop:disable Naming/AccessorMethodName (set makes sense here)
34
+ def set_cookie(value)
35
+ cookies[Testing.config.gem_config.session_cookie] = value
36
+ end
37
+ # rubocop:enable Naming/AccessorMethodName
38
+
39
+ extend self
40
+
41
+ attr_accessor :sessions, :config
42
+
43
+ def setup!(logger:)
44
+ self.config = Config.new
45
+ config.logger = logger
46
+ config.gem_config = Brevio::Session::Config.config
47
+ config.logger.info '--- 👨‍🔬 Setting up Brevio Session gem for testing 👨‍🔬 ---'
48
+
49
+ # Ensures we return a mocked value of the session, rather than something which depends on
50
+ # the cryptographically signed value.
51
+ #
52
+ Brevio::Session::Cookies::Parse.send(:define_method, :perform!) do |cookie|
53
+ raise NilSession if cookie.nil?
54
+ cookie
55
+ end
56
+ end
57
+
58
+ class Config
59
+ attr_accessor :logger, :gem_config
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,98 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'active_support/concern'
4
+
5
+ module Brevio::Session
6
+ extend ActiveSupport::Concern
7
+
8
+ # By including this module into a Rails controller you will have access to the convenience methods
9
+ # fetch_brevio_session(!) and brevio_logged_in? which acts as a wrapper around the decrypting of
10
+ # predefined session cookies and sessions stored in Redis.
11
+ #
12
+ # We also require access to instance attributes like #request and the cookie jar, which are only
13
+ # available in the context of a controller.
14
+ #
15
+ included do
16
+ raise 'Included Brevio::Session outside of controller' unless self <= ActionController::Base
17
+ end
18
+
19
+ # Fetches the Brevio session from Redis, based on the encrypted key stored in the client's cookie.
20
+ # Returns *nil* if there's no session present.
21
+ #
22
+ def fetch_brevio_session
23
+ brevio_session, redis_key = fetch_session
24
+ return nil if brevio_session.nil?
25
+ if brevio_config.debug?
26
+ brevio_config.logger.info "[brevio-session] Found session #{brevio_session.inspect}"
27
+ end
28
+ refresh_session(redis_key) unless params.transform_keys(&:underscore)[:no_session].present?
29
+ brevio_session
30
+ rescue RuntimeError => e
31
+ brevio_config.logger.error "[brevio-session] #{e.message}"
32
+ nil
33
+ end
34
+
35
+ # Calls the above function, but raises an exception if the session isn't present.
36
+ def fetch_brevio_session!
37
+ brevio_session, redis_key = fetch_session
38
+ raise NilSession, 'Brevio session was nil' if brevio_session.nil?
39
+ refresh_session(redis_key) unless params.transform_keys(&:underscore)[:no_session].present?
40
+ brevio_session
41
+ end
42
+
43
+ # Returns a boolean flag indicating whether the current client has a Brevio session cookie set,
44
+ # and whether this cookie contains a user ID.
45
+ #
46
+ def brevio_logged_in?
47
+ fetch_session&.dig(:user_id).present?
48
+ end
49
+
50
+ private
51
+
52
+ def brevio_config
53
+ Config.config
54
+ end
55
+
56
+ def fetch_session
57
+ brevio_config.logger.info '[brevio-session] Fetching Brevio session'
58
+ cookie = request.cookie_jar[brevio_config.session_cookie]
59
+ redis_key = Cookies::Parse.perform!(cookie)
60
+ brevio_session = Redis.get(redis_key)
61
+ raise NilSession if brevio_session.nil?
62
+ [brevio_session.with_indifferent_access, redis_key]
63
+ rescue RuntimeError => e
64
+ brevio_config.logger.error "[brevio-session] --- 💣 Couldn't fetch Brevio session 💣 ---"
65
+ brevio_config.logger.error "[brevio-session] #{e.message}"
66
+ nil
67
+ end
68
+
69
+ # Refreshes the Brevio session cookie, avoding its expiry. This is helpful to
70
+ # ensure the user stays logged in through interacting with the application.
71
+ #
72
+ def refresh_session(redis_key)
73
+ brevio_config.logger.info '[brevio-session] Refreshing Brevio session' if brevio_config.debug?
74
+ cookies[brevio_config.session_cookie] = {
75
+ value: request.cookie_jar[brevio_config.session_cookie],
76
+ domain: :all,
77
+ expires: brevio_config.session_expire,
78
+ httponly: true,
79
+ secure: true
80
+ }
81
+ Redis.expire(redis_key, brevio_config.session_expire)
82
+ rescue RuntimeError => e
83
+ brevio_config.logger.error "[brevio-session] --- 💣 Couldn't refresh Brevio session 💣 ---"
84
+ brevio_config.logger.error "[brevio-session] #{e.message}"
85
+ end
86
+
87
+ class << self
88
+ # Function used to fetch the current audit company session for a given Brevio ID.
89
+ # This session contains information about an audit company shared by any number of
90
+ # users. If the audit company has been updated in ID (e.g. changed logo or name), the
91
+ # database record of the local service (e.g. Confirm/Sign) will fetch the updates if
92
+ # the timestamp in this session is greater than their own local timestamps.
93
+ #
94
+ def audit_company_updated_at(brevio_id)
95
+ Config.config.redis.get("#{Config::Redis::Prefixes::AUDIT_COMPANY}:#{brevio_id}")
96
+ end
97
+ end
98
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ # This file exists so we can do require 'brevio-session'
4
+ # See:
5
+ # https://github.com/rest-client/rest-client/blob/master/lib/rest_client.rb
6
+ require "#{File.dirname(__FILE__)}/brevio_session"
7
+
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'zeitwerk'
4
+
5
+ # Silences warnings for auto-defined constants, e.g. "Brevio" in this case due to having a "Brevio" folder
6
+ Zeitwerk::Loader.for_gem(warn_on_extra_files: false)
7
+
8
+ loader = Zeitwerk::Loader.for_gem
9
+ loader.ignore("#{__dir__}/brevio-session.rb")
10
+ loader.setup # ready!
11
+
12
+ require 'action_dispatch'
13
+
14
+ module Brevio::Session
15
+ class NilSession < StandardError; end
16
+ end
@@ -0,0 +1,38 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'test_helper'
4
+
5
+ class BrevioSessionIntegrationTest < Minitest::Test
6
+ include Rack::Test::Methods
7
+ include Brevio::Session::Testing
8
+
9
+ def brevio_redis
10
+ Brevio::Session::Config.config.redis
11
+ end
12
+
13
+ def user
14
+ UserStub.new(brevio_id: 1)
15
+ end
16
+
17
+ def test_sets_brevio_session_in_redis
18
+ session = brevio_login(user)
19
+ get '/', nil, cookie: "brevio_session=#{session}"
20
+ assert last_response.ok?
21
+ assert current_session.cookie_jar['brevio_session']
22
+ assert_equal user.brevio_id, brevio_redis.get("brevio-id:session:#{session}")[:user_id]
23
+ json_body = JSON.parse(last_response.body)
24
+ assert_equal user.brevio_id, json_body['user_id']
25
+ end
26
+
27
+ def test_user_stamp
28
+ time = Time.current
29
+ session = brevio_login(user, updated_at: time)
30
+ get '/', nil, cookie: "brevio_session=#{session}"
31
+ assert last_response.ok?
32
+ json_body = JSON.parse(last_response.body)
33
+ # ceil ceils the subsecond to a default decimal (0) by default. We don't really care about
34
+ # microsecond precision here during the JSON parsing/dumping
35
+ assert_equal time.ceil, Time.parse(json_body['user_stamp']).ceil
36
+ end
37
+
38
+ end
@@ -0,0 +1,39 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Brevio ID stores its session using redis-session-store, which stores all values as JSON.
4
+ # The returned value is a JSON string, which needs to be parsed by the redis client. The native
5
+ # Redis.get would simply return the JSON string, so we need to wrap it.
6
+ #
7
+ # The services consuming the Brevio::Session (e.g. Confirm/Sign) already assume the values
8
+ # in Redis are all JSON (see domain/brevio/redis/client.rb).
9
+ #
10
+ #
11
+ class RedisJSONWrapper
12
+ def set(key, value)
13
+ redis.set(key, value.to_json)
14
+ end
15
+
16
+ def get(key)
17
+ raw = redis.get(key)
18
+ return nil if raw.nil?
19
+
20
+ value = JSON.parse(raw)
21
+ return value if value.empty?
22
+
23
+ value.with_indifferent_access
24
+ end
25
+
26
+ def del(keys)
27
+ redis.del(keys)
28
+ end
29
+
30
+ def expire(key, expiry)
31
+ redis.expire(key, expiry)
32
+ end
33
+
34
+ private
35
+
36
+ def redis
37
+ @redis ||= ::Redis.new
38
+ end
39
+ end
data/test/stubs.rb ADDED
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ class UserStub
4
+ attr_accessor :brevio_id, :audit_company
5
+
6
+ def initialize(attrs)
7
+ @brevio_id = attrs[:brevio_id]
8
+ @audit_company = AuditCompanyStub.new(brevio_id: @brevio_id + 1)
9
+ end
10
+ end
11
+
12
+ class AuditCompanyStub
13
+ attr_accessor :brevio_id
14
+
15
+ def initialize(attrs)
16
+ @brevio_id = attrs[:brevio_id]
17
+ end
18
+ end
data/test/test_app.rb ADDED
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Based on https://github.com/rails/rails/blob/6-0-stable/guides/bug_report_templates/action_controller_master.rb
4
+
5
+ require 'action_controller/railtie'
6
+ require 'rack/test'
7
+ require 'brevio-session'
8
+
9
+ class TestApp < Rails::Application
10
+ config.root = __dir__
11
+ config.hosts << 'example.org'
12
+ config.session_store :cookie_store, key: 'brevio_session'
13
+ secrets.secret_key_base = 'secret_key_base'
14
+
15
+ config.logger = Logger.new($stdout)
16
+ config.log_level = :info
17
+ Rails.logger = config.logger
18
+
19
+ routes.draw do
20
+ get '/' => 'test#index'
21
+ end
22
+ end
23
+
24
+ class TestController < ActionController::Base
25
+ include Brevio::Session
26
+ include Rails.application.routes.url_helpers
27
+
28
+ def logger
29
+ Rails.logger
30
+ end
31
+
32
+ def index
33
+ brevio_session = fetch_brevio_session
34
+ render json: brevio_session.to_json
35
+ end
36
+ end
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'minitest/autorun'
4
+ require 'rack/test'
5
+
6
+ require 'debug'
7
+ require 'fakeredis'
8
+ require 'priscilla'
9
+ require 'brevio-session'
10
+ require 'brevio_session/testing'
11
+
12
+ require 'redis_json_wrapper'
13
+ require 'stubs'
14
+ require 'test_app'
15
+
16
+ Brevio::Session::Config.configure do |config|
17
+ config.debug = true
18
+ config.production = false
19
+ config.redis = RedisJSONWrapper.new
20
+ config.secret_key = 'secret_key_base'
21
+ config.session_cookie = 'brevio_session'
22
+ config.session_expire = 45.minutes
23
+ end
24
+
25
+ Brevio::Session::Testing.setup!(logger: Rails.logger)
26
+
27
+ module Minitest
28
+ class Test
29
+ include Rack::Test::Methods
30
+ include TestApp.routes.url_helpers
31
+
32
+ def app
33
+ TestApp
34
+ end
35
+ end
36
+ end
metadata ADDED
@@ -0,0 +1,154 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: brevio-session
3
+ version: !ruby/object:Gem::Version
4
+ version: '0.1'
5
+ platform: ruby
6
+ authors:
7
+ - Brevio AS
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2023-04-18 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '2.1'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '2.1'
27
+ - !ruby/object:Gem::Dependency
28
+ name: debug
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: 1.5.0
34
+ - - "<="
35
+ - !ruby/object:Gem::Version
36
+ version: 1.6.0
37
+ type: :development
38
+ prerelease: false
39
+ version_requirements: !ruby/object:Gem::Requirement
40
+ requirements:
41
+ - - "~>"
42
+ - !ruby/object:Gem::Version
43
+ version: 1.5.0
44
+ - - "<="
45
+ - !ruby/object:Gem::Version
46
+ version: 1.6.0
47
+ - !ruby/object:Gem::Dependency
48
+ name: rubocop
49
+ requirement: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - "~>"
52
+ - !ruby/object:Gem::Version
53
+ version: '1.35'
54
+ type: :development
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - "~>"
59
+ - !ruby/object:Gem::Version
60
+ version: '1.35'
61
+ - !ruby/object:Gem::Dependency
62
+ name: actionpack
63
+ requirement: !ruby/object:Gem::Requirement
64
+ requirements:
65
+ - - "~>"
66
+ - !ruby/object:Gem::Version
67
+ version: 7.0.3
68
+ type: :runtime
69
+ prerelease: false
70
+ version_requirements: !ruby/object:Gem::Requirement
71
+ requirements:
72
+ - - "~>"
73
+ - !ruby/object:Gem::Version
74
+ version: 7.0.3
75
+ - !ruby/object:Gem::Dependency
76
+ name: redis
77
+ requirement: !ruby/object:Gem::Requirement
78
+ requirements:
79
+ - - "~>"
80
+ - !ruby/object:Gem::Version
81
+ version: '5.0'
82
+ type: :runtime
83
+ prerelease: false
84
+ version_requirements: !ruby/object:Gem::Requirement
85
+ requirements:
86
+ - - "~>"
87
+ - !ruby/object:Gem::Version
88
+ version: '5.0'
89
+ - !ruby/object:Gem::Dependency
90
+ name: zeitwerk
91
+ requirement: !ruby/object:Gem::Requirement
92
+ requirements:
93
+ - - "~>"
94
+ - !ruby/object:Gem::Version
95
+ version: 2.6.7
96
+ type: :runtime
97
+ prerelease: false
98
+ version_requirements: !ruby/object:Gem::Requirement
99
+ requirements:
100
+ - - "~>"
101
+ - !ruby/object:Gem::Version
102
+ version: 2.6.7
103
+ description: Wrapper around HTTP session set by Brevio ID
104
+ email:
105
+ - support@brevio.com
106
+ executables: []
107
+ extensions: []
108
+ extra_rdoc_files: []
109
+ files:
110
+ - ".gitignore"
111
+ - ".rubocop.yml"
112
+ - ".ruby-version"
113
+ - Gemfile
114
+ - Gemfile.lock
115
+ - LICENSE.txt
116
+ - README.md
117
+ - brevio-session.gemspec
118
+ - lib/brevio-session.rb
119
+ - lib/brevio/session.rb
120
+ - lib/brevio/session/config.rb
121
+ - lib/brevio/session/cookies/parse.rb
122
+ - lib/brevio/session/redis.rb
123
+ - lib/brevio/session/testing.rb
124
+ - lib/brevio_session.rb
125
+ - test/brevio_session_integration_test.rb
126
+ - test/redis_json_wrapper.rb
127
+ - test/stubs.rb
128
+ - test/test_app.rb
129
+ - test/test_helper.rb
130
+ homepage: https://github.com/team-brevio/brevio-session
131
+ licenses:
132
+ - MIT
133
+ metadata:
134
+ rubygems_mfa_required: 'true'
135
+ post_install_message:
136
+ rdoc_options: []
137
+ require_paths:
138
+ - lib
139
+ required_ruby_version: !ruby/object:Gem::Requirement
140
+ requirements:
141
+ - - '='
142
+ - !ruby/object:Gem::Version
143
+ version: '3.2'
144
+ required_rubygems_version: !ruby/object:Gem::Requirement
145
+ requirements:
146
+ - - ">="
147
+ - !ruby/object:Gem::Version
148
+ version: '0'
149
+ requirements: []
150
+ rubygems_version: 3.4.1
151
+ signing_key:
152
+ specification_version: 4
153
+ summary: Brevio session wrapper
154
+ test_files: []