yiffspace-auth 0.0.1 → 0.0.3

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: eaf8f70d591dd62b1fe71e4c6b0269b89178dbbfc96aa00d2f220dc0c051b625
4
- data.tar.gz: 60e9eb43743d443d4cced565c7891fd491344d5274317b72a2a599d9c5118cb0
3
+ metadata.gz: d19d9d8174528781d36a8abe31c4ac5a1571bef1ef9405cb9ba6397924bb6acc
4
+ data.tar.gz: 17545c629a6b9e975716d6e9c4dee590655157f497018fd58adb7464e2038bd3
5
5
  SHA512:
6
- metadata.gz: eca3a821613c9e57b8216ecc8a80608bd2068b31a2521d281183dbe1bd3dd2750111dfa20727912d6076ab08e1a53750b77d8ff0a111602792e791d3bd47fa96
7
- data.tar.gz: 3df50557690c89ffc87e32a94c30b9f3e664702a168fb441cb5a0aa3897928114f169a3da43b8f09bd4dca599906ae42a823d9a66a246e6336a93652584f5a3c
6
+ metadata.gz: db86285b83c9782a81dabe08dd176656f1d6bd6ad229934da632719dea0a435bf3d6b82d4989aba0690a140d992490d650b3cf429240367a500f65f8e8309e81
7
+ data.tar.gz: b1bff84f959da2b59b0ef5bf5f9fa593134b934f2ef895d7c6e2246c87c04910312f88d7ad1690d26804d5d0b8282769b87d2155a31f2a5a5d4a3861311bd568
@@ -1,12 +1,20 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require("active_support/concern")
4
+ require("securerandom")
4
5
 
5
6
  module YiffSpace
6
7
  module Auth
7
8
  module Helper
8
9
  extend(ActiveSupport::Concern)
9
10
 
11
+ # auth/user session values (raw Discord profile + OIDC token claims) can easily exceed a
12
+ # cookie's ~4KB limit, so the session cookie itself only holds an opaque pointer - the real
13
+ # payload lives in Rails.cache (already a hard dependency of this module, see
14
+ # #sync_auth_if_dirty! below), keyed off that pointer.
15
+ SESSION_CACHE_KEY = "yiffspace:auth:session:%s"
16
+ SESSION_CACHE_TTL = 30.days
17
+
10
18
  module ClassMethods
11
19
  def set_client_name(name) # rubocop:disable Naming/AccessorMethodName
12
20
  before_action do |controller|
@@ -27,7 +35,7 @@ module YiffSpace
27
35
  end
28
36
 
29
37
  def auth_raw
30
- session[auth_client_config.auth_session_key]
38
+ read_session_cache(auth_client_config.auth_session_key)
31
39
  end
32
40
 
33
41
  def auth
@@ -41,16 +49,16 @@ module YiffSpace
41
49
  end
42
50
 
43
51
  def auth=(value)
44
- value = nil if value.is_a?(AuthInfo::Anonymous)
45
- session[auth_client_config.auth_session_key] = value&.to_session
52
+ value = nil if value.is_a?(AuthInfo::Anonymous)
53
+ write_session_cache(auth_client_config.auth_session_key, value&.to_session)
46
54
  end
47
55
 
48
56
  def reset_auth!
49
- session.delete(auth_client_config.auth_session_key)
57
+ write_session_cache(auth_client_config.auth_session_key, nil)
50
58
  end
51
59
 
52
60
  def user_raw
53
- session[auth_client_config.user_session_key]
61
+ read_session_cache(auth_client_config.user_session_key)
54
62
  end
55
63
 
56
64
  def user
@@ -64,12 +72,12 @@ module YiffSpace
64
72
  end
65
73
 
66
74
  def user=(value)
67
- value = nil if value.is_a?(UserInfo::Anonymous)
68
- session[auth_client_config.user_session_key] = value&.to_session
75
+ value = nil if value.is_a?(UserInfo::Anonymous)
76
+ write_session_cache(auth_client_config.user_session_key, value&.to_session)
69
77
  end
70
78
 
71
79
  def reset_user!
72
- session.delete(auth_client_config.user_session_key)
80
+ write_session_cache(auth_client_config.user_session_key, nil)
73
81
  end
74
82
 
75
83
  def full_reset!
@@ -148,6 +156,32 @@ module YiffSpace
148
156
  request.env[CLIENT_NAME_ENV] = value.to_sym
149
157
  end
150
158
 
159
+ private
160
+
161
+ def read_session_cache(session_key)
162
+ token = session[session_key]
163
+ return nil if token.blank?
164
+
165
+ Rails.cache.read(format(SESSION_CACHE_KEY, token))
166
+ end
167
+
168
+ # A fresh token is minted on every write (rather than reusing/refreshing the existing one)
169
+ # so a stale token left over from a previous login can never be replayed to read whatever
170
+ # happens to be written at that cache key next.
171
+ def write_session_cache(session_key, value)
172
+ old_token = session[session_key]
173
+ Rails.cache.delete(format(SESSION_CACHE_KEY, old_token)) if old_token.present?
174
+
175
+ if value.nil?
176
+ session.delete(session_key)
177
+ return
178
+ end
179
+
180
+ token = SecureRandom.hex(32)
181
+ Rails.cache.write(format(SESSION_CACHE_KEY, token), value, expires_in: SESSION_CACHE_TTL)
182
+ session[session_key] = token
183
+ end
184
+
151
185
  module Scoped
152
186
  extend(ActiveSupport::Concern)
153
187
  include(Helper)
@@ -2,6 +2,6 @@
2
2
 
3
3
  module YiffSpace
4
4
  module Auth
5
- VERSION = "0.0.1"
5
+ VERSION = "0.0.3"
6
6
  end
7
7
  end
@@ -1,16 +1,50 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require("logto/client")
4
+ require("securerandom")
4
5
 
5
6
  module YiffSpace
6
7
  module Extensions
7
8
  module Logto
9
+ # LogtoClient::SessionStorage (our superclass) stores its values - PKCE verifier, nonce,
10
+ # state, and eventually the access/ID/refresh tokens themselves - directly in the Rails
11
+ # session, which is more than enough on its own to blow the ~4KB cookie limit. The gem's
12
+ # LogtoClient::RailsCacheStorage avoids the cookie but keys purely off app_id, with no
13
+ # per-browser scoping, so concurrent sign-ins from different users would stomp on each
14
+ # other's in-flight OAuth state. This keeps the per-browser scoping (still keyed off the
15
+ # session) but only stores a small opaque token there, with the real value in Rails.cache.
8
16
  class NamedSessionStorage < LogtoClient::SessionStorage
17
+ CACHE_KEY = "yiffspace:auth:logto_storage:%s"
18
+ CACHE_TTL = 30.days
19
+
9
20
  def initialize(name, session, app_id: nil)
10
21
  super(session, app_id: app_id)
11
22
  @name = name
12
23
  end
13
24
 
25
+ def get(key)
26
+ token = @session[get_session_key(key)]
27
+ return nil if token.blank?
28
+
29
+ Rails.cache.read(format(CACHE_KEY, token))
30
+ end
31
+
32
+ def set(key, value)
33
+ session_key = get_session_key(key)
34
+ old_token = @session[session_key]
35
+ Rails.cache.delete(format(CACHE_KEY, old_token)) if old_token.present?
36
+
37
+ token = SecureRandom.hex(32)
38
+ Rails.cache.write(format(CACHE_KEY, token), value, expires_in: CACHE_TTL)
39
+ @session[session_key] = token
40
+ end
41
+
42
+ def remove(key)
43
+ session_key = get_session_key(key)
44
+ token = @session.delete(session_key)
45
+ Rails.cache.delete(format(CACHE_KEY, token)) if token.present?
46
+ end
47
+
14
48
  protected
15
49
 
16
50
  def get_session_key(key)
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: yiffspace-auth
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.0.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Donovan_DMC