yiffspace 0.0.7 → 0.0.9

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: 6df835265036ddab2c96c9eee4f74e2d486ff5edcf6e08ea4ee245fd4d4860c4
4
- data.tar.gz: 3f830fa81d6c083aff4f8b16d8f53a05d60ec2bee6cc7da16d97a5f9fb24a177
3
+ metadata.gz: 3cae6e6673d3c50b8899ec0c198d88af750ba9729804c8c6912ba8a14cf6712a
4
+ data.tar.gz: be9e9e433eca4720756d0a113b383159e4b4572b9bc4783f6eab6755c24de4f7
5
5
  SHA512:
6
- metadata.gz: a341d471f5e1aeb0d0226b7cd237927aa209f974d1b8a8c76642e7635629187714515e6051f8db78964c08dcffb90f6b52b913ae7f17e1baf4f52926e48361fc
7
- data.tar.gz: d6d84c18eb1b40da513fe8dd8fb79c1e2719d9ffa23e17a3132cedd03e336a5cfc08429d3a3ecab8606baf963aaa1d0bdb33d3207617ac6e4a59c389582c412c
6
+ metadata.gz: 6979ad72bc811ea8bc2c831e60122c2f4bd5fe75cca656866a5d607df51c2822f66d8a5d0436f1f984f401683deeb8605ae7821dfceba4bc929732b7d96274ac
7
+ data.tar.gz: f96a1cff3676ef954004f9006524760894e44fa134445c6359b30beb118c7f6326263fc529b79306cc80f7b708cb37af70e6af41e6db8b68ef66686831f52339
@@ -6,50 +6,22 @@ module YiffSpace
6
6
  include(Helper)
7
7
 
8
8
  def show
9
- state = generate_state!
10
- self.return_path = params[:path]
11
- redirect_to(auth_client_config.url(state: state), allow_other_host: true)
9
+ client.sign_in(redirect_uri: auth_client_config.redirect_uri, post_redirect_uri: params[:path] || "/")
12
10
  end
13
11
 
14
12
  def cb
15
- return render("yiffspace/error", locals: { message: "missing code in request" }, status: :bad_request) if params[:code].blank?
16
- return render("yiffspace/error", locals: { message: "missing state in request" }, status: :bad_request) if params[:state].blank?
17
- return render("yiffspace/error", locals: { message: "invalid state in request" }, status: :bad_request) if params[:state] != state
18
-
19
- reset_state!
20
- exchange = auth_client_config.exchange(params[:code])
21
- self.auth = exchange.auth
22
- self.user = exchange.user
23
- path = return_path
24
- action = auth_client_config.after_auth_action
25
- reset_return_path!
26
- if action.is_a?(Proc)
27
- instance_exec(*(action.arity.zero? ? [] : [path]), &action)
28
- return if performed?
29
- elsif action.is_a?(String)
30
- return redirect_to(action)
31
- end
32
-
33
- redirect_to(path || "/")
13
+ client.handle_sign_in_callback(url: request.original_url)
14
+ user = client.fetch_user_info
15
+ token = client.access_token_claims(resource: auth_client_config.resource)
16
+ self.user = UserInfo.new(id: user["identities"]["discord"]["userId"], user: user, discord: user["identities"]["discord"]["details"]["rawData"])
17
+ self.auth = AuthInfo.new(id: user["identities"]["discord"]["userId"], token: token, permissions: token["scope"].split, roles: user["roles"], client_id: auth_client_config.client_id)
34
18
  end
35
19
 
36
20
  def permissions; end
37
21
 
38
22
  def logout
39
- return redirect_back_or_to("/") if auth.blank? && user.blank?
40
-
41
- self.return_path = params[:path] # sanitization
42
- path = return_path
43
- action = auth_client_config.after_logout_action
44
- full_reset!
45
- if action.is_a?(Proc)
46
- action.call(*[self, path].slice(0, action.arity))
47
- return if performed?
48
- elsif action.is_a?(String)
49
- return redirect_to(action)
50
- end
51
-
52
- redirect_to(path || "/")
23
+ client.sign_out(post_logout_redirect_uri: request.base_url)
24
+ reset_user!
53
25
  end
54
26
 
55
27
  def debug
@@ -60,8 +32,16 @@ module YiffSpace
60
32
  params: params,
61
33
  session: session,
62
34
  client: auth_client_config.as_json.merge(client_secret: "[REDACTED]"),
35
+ user: client.fetch_user_info,
36
+ token: client.access_token_claims(resource: "https://gallery.furry.cool"),
63
37
  })
64
38
  end
39
+
40
+ private
41
+
42
+ def client
43
+ @client ||= auth_client_config.logto(self)
44
+ end
65
45
  end
66
46
  end
67
47
  end
@@ -1,5 +1,5 @@
1
1
  <h1 class="title">Permissions</h1>
2
- <% if auth? %>
2
+ <% if logged_in? %>
3
3
  <% if auth.permissions.any? %>
4
4
  <ul class="permissions-list">
5
5
  <% auth.permissions.each do |perm| %>
@@ -12,10 +12,6 @@ module YiffSpace
12
12
  define_method(attr) { |*, **| raise(NotImplementedError, "#{attr} is not present on anonymous auth") }
13
13
  end
14
14
 
15
- def entitlements
16
- []
17
- end
18
-
19
15
  def roles
20
16
  []
21
17
  end
@@ -50,7 +46,7 @@ module YiffSpace
50
46
  end
51
47
 
52
48
  def self.from_json(*)
53
- Anonymous.new
49
+ Anonymous.instance
54
50
  end
55
51
 
56
52
  def self.from_session(data)
@@ -3,21 +3,23 @@
3
3
  module YiffSpace
4
4
  module Auth
5
5
  class AuthInfo
6
- attr_reader(:id, :token, :entitlements, :roles, :permissions)
6
+ attr_reader(:id, :token, :roles, :permissions, :client_id)
7
7
 
8
8
  # @param id String
9
9
  # @param roles Array(String)
10
- # @param entitlements Array(String)
11
- # @param token OpenIDConnect::AccessToken
12
- def initialize(id:, entitlements:, roles:, token:)
10
+ # @param permissions Array(String)
11
+ # @param token LogtoClient::AccessTokenClaims
12
+ # @param client_id String
13
+ def initialize(id:, roles:, permissions:, token:, client_id:)
13
14
  raise(ArgumentError, "no id provided") if id.blank?
14
15
  raise(ArgumentError, "no token provided") if token.blank?
16
+ raise(ArgumentError, "no client id provided") if client_id.blank?
15
17
 
16
18
  @id = id
17
19
  @token = token
18
- @entitlements = Array(entitlements)
19
20
  @roles = Array(roles)
20
- @permissions = Permissions.new(@entitlements)
21
+ @permissions = Permissions.new(permissions, separator: YiffSpace::Auth.get_by_id(client_id).permissions_separator)
22
+ @client_id = client_id
21
23
  end
22
24
 
23
25
  def anonymous?
@@ -39,10 +41,11 @@ module YiffSpace
39
41
 
40
42
  def serializable_hash(*)
41
43
  {
42
- "id" => id,
43
- "token" => ::YiffSpace::Auth.serialize_token(token),
44
- "entitlements" => entitlements,
45
- "roles" => roles,
44
+ "id" => id,
45
+ "token" => token.as_json,
46
+ "roles" => roles,
47
+ "permissions" => permissions.values,
48
+ "client_id" => client_id,
46
49
  }
47
50
  end
48
51
 
@@ -57,10 +60,11 @@ module YiffSpace
57
60
  data = ::YiffSpace::Utils::OpenHash.from(data)
58
61
 
59
62
  new(
60
- id: data.id,
61
- token: ::YiffSpace::Auth.unserialize_token(data.token),
62
- entitlements: data.entitlements,
63
- roles: data.roles,
63
+ id: data.id,
64
+ token: data.token,
65
+ roles: data.roles,
66
+ permissions: data.permissions,
67
+ client_id: data.client_id,
64
68
  )
65
69
  end
66
70
 
@@ -1,58 +1,42 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require_relative("../core_ext/logto/named_session_storage")
4
+
3
5
  module YiffSpace
4
6
  module Auth
5
7
  class Client
6
- attr_accessor(:client_name, :client_id, :client_secret, :redirect_uri,
7
- :server_url, :scopes, :auth_session_key, :user_session_key,
8
- :token_session_key, :return_path_session_key, :state_session_key,
9
- :state_generator, :after_auth_action, :after_logout_action,
10
- :update_discord_images)
8
+ attr_accessor(:client_id, :client_secret, :scopes, :resource,
9
+ :redirect_uri, :server_url, :auth_session_key,
10
+ :user_session_key, :update_discord_images, :permissions_separator)
11
11
 
12
12
  attr_reader(:name)
13
13
 
14
14
  def initialize(name)
15
15
  @name = name.to_sym
16
- @server_url = "https://auth.yiff.space"
16
+ @scopes = %i[openid offline_access profile roles identities]
17
17
  @redirect_uri = "http://127.0.0.1:3000/auth/cb"
18
- @scopes = %i[openid discord offline_access entitlements]
18
+ @server_url = "https://auth.yiff.space"
19
19
  @auth_session_key = :"yiffspace_auth_#{name}"
20
20
  @user_session_key = :"yiffspace_user_#{name}"
21
- @token_session_key = :"yiffspace_token_#{name}"
22
- @return_path_session_key = :"yiffspace_return_path_#{name}"
23
- @state_session_key = :"yiffspace_state_#{name}"
24
- @state_generator = -> { SecureRandom.hex(48) }
25
21
  @update_discord_images = true
22
+ @permissions_separator = ":"
26
23
  end
27
24
 
28
- def openid_config
29
- @openid_config ||= OpenIDConnect::Discovery::Provider::Config.discover!("#{server_url}/application/o/#{client_name}/")
30
- end
31
-
32
- def oidc_client
33
- @oidc_client ||= OpenIDConnect::Client.new(
34
- identifier: client_id,
35
- secret: client_secret,
36
- redirect_uri: redirect_uri,
37
- authorization_endpoint: openid_config.authorization_endpoint,
38
- token_endpoint: openid_config.token_endpoint,
39
- userinfo_endpoint: openid_config.userinfo_endpoint,
25
+ def logto(controller)
26
+ LogtoClient.new(
27
+ config: LogtoClient::Config.new(
28
+ endpoint: server_url,
29
+ app_id: client_id,
30
+ app_secret: client_secret,
31
+ scopes: scopes,
32
+ resources: [resource].compact,
33
+ ),
34
+ # Allow the client to redirect to other hosts (i.e. your Logto tenant)
35
+ navigate: ->(uri) { controller.redirect_to(uri, allow_other_host: true) },
36
+ # Controller has access to the session object
37
+ storage: LogtoClient::NamedSessionStorage.new("yiffspace", controller.session, app_id: @name),
40
38
  )
41
39
  end
42
-
43
- def url(state: nil)
44
- oidc_client.authorization_uri(scope: scopes, state: state)
45
- end
46
-
47
- def exchange(code)
48
- oidc_client.authorization_code = code
49
- token = oidc_client.access_token!
50
- user = token.userinfo!
51
- id = user.raw_attributes["discord"]["id"]
52
- authinfo = AuthInfo.new(token: token, entitlements: user.raw_attributes["entitlements"], roles: user.raw_attributes["roles"], id: id)
53
- userinfo = UserInfo.new(user: user, id: id, discord: user.raw_attributes["discord"], client_id: oidc_client.identifier)
54
- Auth::ExchangeResponse.new(authinfo, userinfo)
55
- end
56
40
  end
57
41
  end
58
42
  end
@@ -38,7 +38,7 @@ module YiffSpace
38
38
  subclass.engine_name("yiffspace_auth_#{name}")
39
39
  # Inherit isolation settings that aren't copied from the parent class
40
40
  subclass.instance_variable_set(:@isolated, true)
41
- subclass.routes.default_scope = { module: "yiffspace/auth" }
41
+ subclass.routes.default_scope = { module: "yiff_space/auth" }
42
42
  subclass.routes.draw do
43
43
  constraints(SetClientName.new(name)) do
44
44
  get(:cb, controller: :root)
@@ -72,50 +72,21 @@ module YiffSpace
72
72
  session.delete(auth_client_config.user_session_key)
73
73
  end
74
74
 
75
- def state
76
- session[auth_client_config.state_session_key]
77
- end
78
-
79
- def state=(value)
80
- session[auth_client_config.state_session_key] = value
81
- end
82
-
83
- def reset_state!
84
- session.delete(auth_client_config.state_session_key)
85
- end
86
-
87
- def generate_state!
88
- generator = auth_client_config.state_generator
89
- self.state = generator.call(*(generator.arity.zero? ? [] : [self]))
90
- end
91
-
92
- def return_path
93
- session[auth_client_config.return_path_session_key]
94
- end
95
-
96
- def return_path=(value)
97
- return if value && (!value.start_with?("/") || value.start_with?("//"))
98
-
99
- session[auth_client_config.return_path_session_key] = value
100
- end
101
-
102
- def reset_return_path!
103
- session.delete(auth_client_config.return_path_session_key)
104
- end
105
-
106
75
  def full_reset!
107
- reset_state!
108
76
  reset_auth!
109
77
  reset_user!
110
- reset_return_path!
111
78
  end
112
79
 
113
80
  def require_auth(path)
114
- redirect_to(path) unless auth?
81
+ redirect_to(path) unless user?
82
+ end
83
+
84
+ def logged_in?
85
+ user?
115
86
  end
116
87
 
117
88
  def has_permission?(name)
118
- return false unless auth?
89
+ return false unless user?
119
90
 
120
91
  auth.permissions.has?(name)
121
92
  end
@@ -9,13 +9,14 @@ module YiffSpace
9
9
 
10
10
  include(Enumerable)
11
11
 
12
- def initialize(perms)
12
+ def initialize(perms, separator: ":")
13
13
  @values = perms
14
14
  @tree = {}
15
+ @separator = separator
15
16
 
16
17
  perms.each do |perm|
17
18
  current = @tree
18
- parts = perm.split(".")
19
+ parts = perm.split(separator)
19
20
 
20
21
  parts.each do |part|
21
22
  current[part] ||= {}
@@ -51,10 +52,10 @@ module YiffSpace
51
52
  end
52
53
 
53
54
  if @tree.key?(str)
54
- self.class.new_from_subtree(@tree[str])
55
+ self.class.new_from_subtree(@tree[str], @separator)
55
56
  else
56
57
  # return empty node instead of raising
57
- self.class.new([])
58
+ self.class.new([], separator: @separator)
58
59
  end
59
60
  end
60
61
 
@@ -62,10 +63,11 @@ module YiffSpace
62
63
  true
63
64
  end
64
65
 
65
- def self.new_from_subtree(tree)
66
+ def self.new_from_subtree(tree, separator)
66
67
  obj = allocate
67
68
  obj.instance_variable_set(:@tree, tree)
68
69
  obj.instance_variable_set(:@values, leaves_from_tree(tree))
70
+ obj.instance_variable_set(:@separator, separator)
69
71
  obj
70
72
  end
71
73
 
@@ -58,7 +58,7 @@ module YiffSpace
58
58
  end
59
59
 
60
60
  def self.from_json(*)
61
- Anonymous.new
61
+ Anonymous.instance
62
62
  end
63
63
 
64
64
  def self.from_session(data)
@@ -3,20 +3,18 @@
3
3
  module YiffSpace
4
4
  module Auth
5
5
  class UserInfo
6
- attr_reader(:id, :user, :discord, :client_id)
6
+ attr_reader(:id, :user, :discord)
7
7
 
8
8
  # @param id String
9
- # @param user OpenIDConnect::ResponseObject::UserInfo
9
+ # @param user LogtoCore::UserInfoResponse
10
10
  # @param discord Hash
11
- # @param client_id String
12
- def initialize(id:, user:, discord:, client_id:)
11
+ def initialize(id:, user:, discord:)
13
12
  raise(ArgumentError, "no id provided") if id.blank?
14
13
  raise(ArgumentError, "no user provided") if user.blank?
15
14
 
16
15
  @id = id
17
16
  @user = user
18
17
  @discord = DiscordInfo.from_json(discord)
19
- @client_id = client_id
20
18
  end
21
19
 
22
20
  def anonymous?
@@ -58,7 +56,7 @@ module YiffSpace
58
56
  {
59
57
  "id" => id,
60
58
  "discord" => discord.serializable_hash,
61
- "user" => ::YiffSpace::Auth.serialize_user(user, client_id: client_id),
59
+ "user" => user.as_json,
62
60
  }
63
61
  end
64
62
 
@@ -72,12 +70,10 @@ module YiffSpace
72
70
  data = JSON.parse(data) if data.is_a?(String)
73
71
  data = ::YiffSpace::Utils::OpenHash.from(data)
74
72
 
75
- user_data = ::YiffSpace::Utils::OpenHash.from(data.user)
76
73
  new(
77
- id: data.id,
78
- discord: data.discord,
79
- user: ::YiffSpace::Auth.unserialize_user(user_data),
80
- client_id: user_data.client_id,
74
+ id: data.id,
75
+ discord: data.discord,
76
+ user: data.user,
81
77
  )
82
78
  end
83
79
 
@@ -1,12 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require("openid_connect")
4
-
5
3
  module YiffSpace
6
4
  module Auth
7
- class SerializeError < StandardError; end
8
-
9
- ExchangeResponse = Struct.new(:auth, :user)
10
5
  CLIENT_NAME_ENV = "yiffspace.auth.client_name"
11
6
  DEFAULT_CLIENT_NAME = :default
12
7
 
@@ -23,50 +18,15 @@ module YiffSpace
23
18
  end
24
19
 
25
20
  def [](name)
26
- @clients[name.to_sym] or raise(KeyError, "unknown auth client: #{name.inspect}")
21
+ @clients[name.to_sym] || raise(KeyError, "unknown auth client: #{name.inspect}")
27
22
  end
28
23
 
29
24
  def default
30
25
  @clients[DEFAULT_CLIENT_NAME] || raise("no default client configured")
31
26
  end
32
27
 
33
- def find_by_client_id(client_id)
34
- @clients.values.find { |c| c.oidc_client.identifier == client_id }
35
- end
36
-
37
- def serialize_token(token)
38
- { attributes: token.raw_attributes.without("client"), client_id: token.client.identifier }
39
- end
40
-
41
- def unserialize_token(data)
42
- raise(SerializeError, "no token data provided") if data.blank?
43
- return data if data.is_a?(OpenIDConnect::AccessToken)
44
-
45
- data = JSON.parse(data) if data.is_a?(String)
46
- data = ::YiffSpace::Utils::OpenHash.from(data)
47
- raise(SerializeError, "no client id for token, refusing to reconstruct") if data.client_id.nil?
48
-
49
- client_config = find_by_client_id(data.client_id)
50
- raise(SerializeError, "unknown client_id #{data.client_id.inspect}") unless client_config
51
-
52
- OpenIDConnect::AccessToken.new(data.attributes.merge(client: client_config.oidc_client))
53
- end
54
-
55
- def serialize_user(user, client_id:)
56
- { attributes: user.raw_attributes, client_id: client_id }
57
- end
58
-
59
- def unserialize_user(data)
60
- raise(SerializeError, "no user data provided") if data.blank?
61
- return data if data.is_a?(OpenIDConnect::ResponseObject::UserInfo)
62
-
63
- data = JSON.parse(data) if data.is_a?(String)
64
- data = ::YiffSpace::Utils::OpenHash.from(data)
65
- raise(SerializeError, "no client id for user, refusing to reconstruct") if data.client_id.nil?
66
-
67
- find_by_client_id(data.client_id) or raise(SerializeError, "unknown client_id #{data.client_id.inspect}")
68
-
69
- OpenIDConnect::ResponseObject::UserInfo.new(data.attributes)
28
+ def get_by_id(id)
29
+ @clients.values.find { |c| c.client_id == id } || raise(ArgumentError, "unable to find client with id: #{id}")
70
30
  end
71
31
 
72
32
  def enable_debug_action?
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative("active_record/where_chain")
3
+ require_relative("active_record/all")
4
4
  require_relative("arel/all")
5
5
  require_relative("enumerable/all")
6
6
  require_relative("hash/all")
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative("../../extensions/logto/named_session_storage")
4
+
5
+ class LogtoClient
6
+ NamedSessionStorage = YiffSpace::Extensions::Logto::NamedSessionStorage
7
+ end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ require("logto/client")
4
+
5
+ module YiffSpace
6
+ module Extensions
7
+ module Logto
8
+ class NamedSessionStorage < LogtoClient::SessionStorage
9
+ def initialize(name, session, app_id: nil)
10
+ super(session, app_id: app_id)
11
+ @name = name
12
+ end
13
+
14
+ protected
15
+
16
+ def get_session_key(key)
17
+ "#{@name}_#{@app_id || 'default'}_#{key}"
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module YiffSpace
4
- VERSION = "0.0.7"
4
+ VERSION = "0.0.9"
5
5
  end
data/lib/yiffspace.rb CHANGED
@@ -21,4 +21,11 @@ loader.inflector.inflect({ "postgresql" => "PostgreSQL", "yiffspace" => "YiffSpa
21
21
  loader.ignore("#{__dir__}/yiffspace/core_ext")
22
22
  loader.ignore("#{__dir__}/yiffspace/include")
23
23
  loader.ignore("#{__dir__}/yiffspace/railtie.rb")
24
+ loader.ignore("#{__dir__}/yiffspace/auth/engine.rb")
24
25
  loader.setup
26
+
27
+ # Require the auth engine eagerly so it registers with Rails before the host app's
28
+ # active_support.initialize_per_engine_zeitwerk_loaders initializer runs. Without this,
29
+ # the engine is only loaded during route drawing (after Zeitwerk setup) and its
30
+ # app/controllers path is never added to the app's autoload roots.
31
+ require_relative("yiffspace/auth/engine") if defined?(Rails)
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: yiffspace
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.7
4
+ version: 0.0.9
5
5
  platform: ruby
6
6
  authors:
7
7
  - Donovan_DMC
8
8
  bindir: bin
9
9
  cert_chain: []
10
- date: 2026-06-03 00:00:00.000000000 Z
10
+ date: 2026-06-17 00:00:00.000000000 Z
11
11
  dependencies:
12
12
  - !ruby/object:Gem::Dependency
13
13
  name: abbrev
@@ -38,19 +38,19 @@ dependencies:
38
38
  - !ruby/object:Gem::Version
39
39
  version: '0.24'
40
40
  - !ruby/object:Gem::Dependency
41
- name: openid_connect
41
+ name: logto
42
42
  requirement: !ruby/object:Gem::Requirement
43
43
  requirements:
44
44
  - - ">="
45
45
  - !ruby/object:Gem::Version
46
- version: '2.3'
46
+ version: 0.2.0
47
47
  type: :runtime
48
48
  prerelease: false
49
49
  version_requirements: !ruby/object:Gem::Requirement
50
50
  requirements:
51
51
  - - ">="
52
52
  - !ruby/object:Gem::Version
53
- version: '2.3'
53
+ version: 0.2.0
54
54
  - !ruby/object:Gem::Dependency
55
55
  name: rails
56
56
  requirement: !ruby/object:Gem::Requirement
@@ -104,8 +104,8 @@ files:
104
104
  - LICENSE
105
105
  - README.md
106
106
  - Rakefile
107
- - app/assets/config/yiff_space_manifest.js
108
- - app/assets/stylesheets/yiff_space/application.css
107
+ - app/assets/config/yiffspace_manifest.js
108
+ - app/assets/stylesheets/yiffspace/application.css
109
109
  - app/controllers/yiff_space/application_controller.rb
110
110
  - app/helpers/yiff_space/application_helper.rb
111
111
  - app/helpers/yiff_space/auth_helper.rb
@@ -155,6 +155,7 @@ files:
155
155
  - lib/yiffspace/core_ext/enumerable/parallel.rb
156
156
  - lib/yiffspace/core_ext/hash/all.rb
157
157
  - lib/yiffspace/core_ext/hash/to_open_hash.rb
158
+ - lib/yiffspace/core_ext/logto/named_session_storage.rb
158
159
  - lib/yiffspace/core_ext/string/all.rb
159
160
  - lib/yiffspace/core_ext/string/sql.rb
160
161
  - lib/yiffspace/core_ext/string/to_b.rb
@@ -170,6 +171,7 @@ files:
170
171
  - lib/yiffspace/extensions/arel/visitors/postgresql/left_join_lateral.rb
171
172
  - lib/yiffspace/extensions/enumerable/parallel.rb
172
173
  - lib/yiffspace/extensions/hash/to_open_hash.rb
174
+ - lib/yiffspace/extensions/logto/named_session_storage.rb
173
175
  - lib/yiffspace/extensions/string/sql.rb
174
176
  - lib/yiffspace/extensions/string/to_b.rb
175
177
  - lib/yiffspace/extensions/string/truthy_falsy.rb