yiffspace 0.0.25 → 0.1.0

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.
Files changed (41) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +11 -0
  3. data/lib/yiffspace/configuration.rb +0 -25
  4. data/lib/yiffspace/{railtie.rb → engine.rb} +9 -7
  5. data/lib/yiffspace/extensions/active_record/where_chain.rb +5 -5
  6. data/lib/yiffspace/version.rb +1 -1
  7. data/lib/yiffspace.rb +5 -6
  8. metadata +2 -49
  9. data/app/helpers/yiff_space/auth_helper.rb +0 -6
  10. data/engines/auth/app/controllers/yiff_space/auth/application_controller.rb +0 -11
  11. data/engines/auth/app/controllers/yiff_space/auth/root_controller.rb +0 -49
  12. data/engines/auth/app/controllers/yiff_space/auth/webhook_controller.rb +0 -73
  13. data/engines/auth/app/views/yiff_space/auth/root/permissions.html.erb +0 -14
  14. data/engines/auth/config/routes.rb +0 -12
  15. data/lib/tasks/yiffspace_tasks.rake +0 -41
  16. data/lib/yiffspace/auth/api_user.rb +0 -43
  17. data/lib/yiffspace/auth/auth_info/anonymous.rb +0 -60
  18. data/lib/yiffspace/auth/auth_info.rb +0 -78
  19. data/lib/yiffspace/auth/client.rb +0 -56
  20. data/lib/yiffspace/auth/discord_info.rb +0 -65
  21. data/lib/yiffspace/auth/engine.rb +0 -58
  22. data/lib/yiffspace/auth/helper.rb +0 -174
  23. data/lib/yiffspace/auth/permissions.rb +0 -87
  24. data/lib/yiffspace/auth/set_client_name.rb +0 -15
  25. data/lib/yiffspace/auth/user_info/anonymous.rb +0 -72
  26. data/lib/yiffspace/auth/user_info.rb +0 -87
  27. data/lib/yiffspace/auth.rb +0 -44
  28. data/lib/yiffspace/core_ext/action_dispatch/set_auth_client/scoped.rb +0 -13
  29. data/lib/yiffspace/core_ext/action_dispatch/set_auth_client.rb +0 -13
  30. data/lib/yiffspace/core_ext/logto/named_session_storage.rb +0 -7
  31. data/lib/yiffspace/extensions/action_dispatch/set_auth_client/scoped.rb +0 -15
  32. data/lib/yiffspace/extensions/action_dispatch/set_auth_client.rb +0 -13
  33. data/lib/yiffspace/extensions/logto/named_session_storage.rb +0 -22
  34. data/lib/yiffspace/logto_management_client.rb +0 -136
  35. data/lib/yiffspace/serializers/anonymous_auth_info_serializer.rb +0 -23
  36. data/lib/yiffspace/serializers/anonymous_user_info_serializer.rb +0 -23
  37. data/lib/yiffspace/serializers/auth_info_serializer.rb +0 -23
  38. data/lib/yiffspace/serializers/discord_info_serializer.rb +0 -23
  39. data/lib/yiffspace/serializers/permissions_serializer.rb +0 -23
  40. data/lib/yiffspace/serializers/user_info_serializer.rb +0 -23
  41. data/lib/yiffspace/utils/user_deduper.rb +0 -66
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: d25c09cc2215ae215fedbcac2a2f7df9cb90bcffe077b9ce65e19cc7a87cdcc2
4
- data.tar.gz: d1e559638ed2c624a88df12fb99c95e6f72af323d1acea7745240bd2f44e8b36
3
+ metadata.gz: 91faac8d32a587e89936bc66f94459251f40b7a5c59de022e240684f76b632da
4
+ data.tar.gz: 58fbb7700a5f72959bb94e1b6afdd5ebc20532e9ba5af471b312664fbe9124c9
5
5
  SHA512:
6
- metadata.gz: '068f7913582ba815958d342421467c0af7a88ca7ec98643e2d3503c1c5cf36a74d284928f8e4df4a100e874170ca3eed13d2e6ff1c4c448ebbc3fea05e19b5fe'
7
- data.tar.gz: 9991d33a718322c301de8fff0a705f209d1853fb5d60bb1dc00a6f0d39e16fb5c9c85ef1af0a1e772c56d7e894f43461d994ebe66dd1ac15b7a24df65026b2e8
6
+ metadata.gz: 1951e8e761f305e1fb07817b11377a051ba6c3715e1e1c6fe54e3d06f742ebce67699c883478be5a8f8299dd2ffacbd59be7308591d7fd7cf88e5f6fedf3e8c8
7
+ data.tar.gz: ab2ddab57baa7d797fd5da05d9e79dd0a8993d8b0c850ead972dbea48bfd72a609530ee825c11f767aeb5a73c3ccae98e29b1b119ee0db56defa19b2dee73569
data/CHANGELOG.md CHANGED
@@ -0,0 +1,11 @@
1
+ ## 0.1.0
2
+
3
+ - **Breaking:** extracted the Logto auth engine (`YiffSpace::Auth::*`) into a
4
+ separate gem, [`yiffspace-auth`](https://github.com/YiffSpace/Auth.rb). Apps
5
+ using auth need to add that gem alongside `yiffspace`.
6
+ - `YiffSpace::Configuration#auth`/`#add_auth`/`#add_default_auth` and the
7
+ `logto_api_*`/`discord_bot_token` settings moved to `yiffspace-auth`.
8
+ - Replaced the dead `YiffSpace::Railtie` with a real `YiffSpace::Engine <
9
+ Rails::Engine`, so the shared `app/` directory (ApplicationController,
10
+ layout, error view, CSS, ActiveJob serializers) actually loads into host
11
+ apps again.
@@ -31,12 +31,6 @@ module YiffSpace
31
31
  # The `last_ip_addr` attribute of the User model, used by the UserResolvableMethods concern
32
32
  attr_accessor(:last_ip_addr_attribute)
33
33
 
34
- # Logto Management API credentials (shared across all auth clients).
35
- attr_accessor(:logto_api_client_id, :logto_api_client_secret, :logto_api_resource)
36
-
37
- # Discord bot token used to look up Discord users (shared across all auth clients).
38
- attr_accessor(:discord_bot_token)
39
-
40
34
  # The anonymous user's name, can be a proc
41
35
  attr_reader(:anonymous_user_name)
42
36
 
@@ -58,10 +52,6 @@ module YiffSpace
58
52
  @default_ip_address = "127.0.0.1"
59
53
  @last_ip_addr_attribute = :last_ip_addr
60
54
  @anonymous_user_name = -> { "Anonymous" }
61
- @logto_api_client_id = nil
62
- @logto_api_client_secret = nil
63
- @logto_api_resource = nil
64
- @discord_bot_token = nil
65
55
  end
66
56
 
67
57
  def user_class
@@ -103,21 +93,6 @@ module YiffSpace
103
93
  @anonymous_user_name = value.is_a?(Proc) ? value : -> { value }
104
94
  end
105
95
 
106
- def auth(&block)
107
- client = YiffSpace::Auth.register(Auth::DEFAULT_CLIENT_NAME) unless YiffSpace::Auth.instance_variable_get(:@clients).key?(Auth::DEFAULT_CLIENT_NAME)
108
- client ||= YiffSpace::Auth[Auth::DEFAULT_CLIENT_NAME]
109
- block&.call(client)
110
- client
111
- end
112
-
113
- def add_auth(name, &)
114
- YiffSpace::Auth.register(name, &)
115
- end
116
-
117
- def add_default_auth(&)
118
- add_auth(Auth::DEFAULT_CLIENT_NAME, &)
119
- end
120
-
121
96
  def images
122
97
  @images ||= Images.new
123
98
  end
@@ -1,18 +1,20 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require("rails")
4
+
3
5
  module YiffSpace
4
- class Railtie < Rails::Railtie
6
+ class Engine < ::Rails::Engine
7
+ config.root = File.expand_path("../..", __dir__)
8
+
9
+ initializer("yiffspace.assets") do |app|
10
+ app.config.assets.precompile += %w[yiffspace/application.css] if app.config.respond_to?(:assets)
11
+ end
12
+
5
13
  initializer("yiffspace.serializers") do
6
14
  ActiveSupport.on_load(:active_job) do
7
15
  ActiveJob::Serializers.add_serializers(
8
- Serializers::AnonymousAuthInfoSerializer,
9
- Serializers::AnonymousUserInfoSerializer,
10
- Serializers::AuthInfoSerializer,
11
16
  Serializers::AvatarSerializer,
12
17
  Serializers::BannerSerializer,
13
- Serializers::DiscordInfoSerializer,
14
- Serializers::PermissionsSerializer,
15
- Serializers::UserInfoSerializer,
16
18
  Serializers::UserResolvableSerializer,
17
19
  )
18
20
  end
@@ -23,17 +23,17 @@ module YiffSpace
23
23
  # https://www.postgresql.org/docs/current/static/functions-matching.html#FUNCTIONS-POSIX-REGEXP
24
24
  # "(?e)" means force use of ERE syntax; see sections 9.7.3.1 and 9.7.3.4.
25
25
  def regex(conditions = {}, flags: "e", **kwargs)
26
- conditions.merge!(kwargs) if conditions.is_a?(Hash)
26
+ conditions.merge!(kwargs) if conditions.is_a?(::Hash)
27
27
  build(conditions, :regex, flags)
28
28
  end
29
29
 
30
30
  def not_regex(conditions = {}, flags: "e", **kwargs)
31
- conditions.merge!(kwargs) if conditions.is_a?(Hash)
31
+ conditions.merge!(kwargs) if conditions.is_a?(::Hash)
32
32
  build(conditions, :not_regex, flags)
33
33
  end
34
34
 
35
35
  def tsquery(conditions = {}, ts_config: "english", **kwargs)
36
- conditions.merge!(kwargs) if conditions.is_a?(Hash)
36
+ conditions.merge!(kwargs) if conditions.is_a?(::Hash)
37
37
  build(conditions, :tsquery, ts_config)
38
38
  end
39
39
 
@@ -84,9 +84,9 @@ module YiffSpace
84
84
 
85
85
  conditions.each do |key, value|
86
86
  case key
87
- when String, Symbol
87
+ when ::String, ::Symbol
88
88
  key = key.to_s
89
- if value.is_a?(Hash)
89
+ if value.is_a?(::Hash)
90
90
  pairs.concat(normalize_conditions(value, model, key))
91
91
  elsif key.include?(".")
92
92
  table, col = key.split(".", 2)
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module YiffSpace
4
- VERSION = "0.0.25"
4
+ VERSION = "0.1.0"
5
5
  end
data/lib/yiffspace.rb CHANGED
@@ -20,12 +20,11 @@ loader = Zeitwerk::Loader.for_gem
20
20
  loader.inflector.inflect({ "postgresql" => "PostgreSQL", "yiffspace" => "YiffSpace", "query_dsl" => "QueryDSL" })
21
21
  loader.ignore("#{__dir__}/yiffspace/core_ext")
22
22
  loader.ignore("#{__dir__}/yiffspace/include")
23
- loader.ignore("#{__dir__}/yiffspace/railtie.rb")
24
- loader.ignore("#{__dir__}/yiffspace/auth/engine.rb")
23
+ loader.ignore("#{__dir__}/yiffspace/engine.rb")
25
24
  loader.setup
26
25
 
27
- # Require the auth engine eagerly so it registers with Rails before the host app's
26
+ # Require the engine eagerly so it registers with Rails before the host app's
28
27
  # 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)
28
+ # the engine is only loaded lazily (after Zeitwerk setup) and its app/controllers
29
+ # path is never added to the app's autoload roots.
30
+ require_relative("yiffspace/engine") if defined?(Rails)
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: yiffspace
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.25
4
+ version: 0.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Donovan_DMC
@@ -37,20 +37,6 @@ dependencies:
37
37
  - - ">="
38
38
  - !ruby/object:Gem::Version
39
39
  version: '0.24'
40
- - !ruby/object:Gem::Dependency
41
- name: logto
42
- requirement: !ruby/object:Gem::Requirement
43
- requirements:
44
- - - ">="
45
- - !ruby/object:Gem::Version
46
- version: 0.2.0
47
- type: :runtime
48
- prerelease: false
49
- version_requirements: !ruby/object:Gem::Requirement
50
- requirements:
51
- - - ">="
52
- - !ruby/object:Gem::Version
53
- version: 0.2.0
54
40
  - !ruby/object:Gem::Dependency
55
41
  name: rails
56
42
  requirement: !ruby/object:Gem::Requirement
@@ -108,29 +94,10 @@ files:
108
94
  - app/assets/stylesheets/yiffspace/application.css
109
95
  - app/controllers/yiff_space/application_controller.rb
110
96
  - app/helpers/yiff_space/application_helper.rb
111
- - app/helpers/yiff_space/auth_helper.rb
112
97
  - app/models/yiff_space/application_record.rb
113
98
  - app/views/layouts/yiff_space/application.html.erb
114
99
  - app/views/yiff_space/error.html.erb
115
- - engines/auth/app/controllers/yiff_space/auth/application_controller.rb
116
- - engines/auth/app/controllers/yiff_space/auth/root_controller.rb
117
- - engines/auth/app/controllers/yiff_space/auth/webhook_controller.rb
118
- - engines/auth/app/views/yiff_space/auth/root/permissions.html.erb
119
- - engines/auth/config/routes.rb
120
- - lib/tasks/yiffspace_tasks.rake
121
100
  - lib/yiffspace.rb
122
- - lib/yiffspace/auth.rb
123
- - lib/yiffspace/auth/api_user.rb
124
- - lib/yiffspace/auth/auth_info.rb
125
- - lib/yiffspace/auth/auth_info/anonymous.rb
126
- - lib/yiffspace/auth/client.rb
127
- - lib/yiffspace/auth/discord_info.rb
128
- - lib/yiffspace/auth/engine.rb
129
- - lib/yiffspace/auth/helper.rb
130
- - lib/yiffspace/auth/permissions.rb
131
- - lib/yiffspace/auth/set_client_name.rb
132
- - lib/yiffspace/auth/user_info.rb
133
- - lib/yiffspace/auth/user_info/anonymous.rb
134
101
  - lib/yiffspace/concerns/active_record_extensions.rb
135
102
  - lib/yiffspace/concerns/api_methods.rb
136
103
  - lib/yiffspace/concerns/attribute_matchers.rb
@@ -146,8 +113,6 @@ files:
146
113
  - lib/yiffspace/config_builder.rb
147
114
  - lib/yiffspace/configuration.rb
148
115
  - lib/yiffspace/configuration/images.rb
149
- - lib/yiffspace/core_ext/action_dispatch/set_auth_client.rb
150
- - lib/yiffspace/core_ext/action_dispatch/set_auth_client/scoped.rb
151
116
  - lib/yiffspace/core_ext/active_record/all.rb
152
117
  - lib/yiffspace/core_ext/active_record/where_chain.rb
153
118
  - lib/yiffspace/core_ext/all.rb
@@ -158,14 +123,12 @@ files:
158
123
  - lib/yiffspace/core_ext/enumerable/parallel.rb
159
124
  - lib/yiffspace/core_ext/hash/all.rb
160
125
  - lib/yiffspace/core_ext/hash/to_open_hash.rb
161
- - lib/yiffspace/core_ext/logto/named_session_storage.rb
162
126
  - lib/yiffspace/core_ext/object/all.rb
163
127
  - lib/yiffspace/core_ext/object/to_b.rb
164
128
  - lib/yiffspace/core_ext/object/truthy_falsy.rb
165
129
  - lib/yiffspace/core_ext/string/all.rb
166
130
  - lib/yiffspace/core_ext/string/sql.rb
167
- - lib/yiffspace/extensions/action_dispatch/set_auth_client.rb
168
- - lib/yiffspace/extensions/action_dispatch/set_auth_client/scoped.rb
131
+ - lib/yiffspace/engine.rb
169
132
  - lib/yiffspace/extensions/active_record/where_chain.rb
170
133
  - lib/yiffspace/extensions/arel/nodes/cross_join_lateral.rb
171
134
  - lib/yiffspace/extensions/arel/nodes/left_join_lateral.rb
@@ -175,7 +138,6 @@ files:
175
138
  - lib/yiffspace/extensions/arel/visitors/postgresql/left_join_lateral.rb
176
139
  - lib/yiffspace/extensions/enumerable/parallel.rb
177
140
  - lib/yiffspace/extensions/hash/to_open_hash.rb
178
- - lib/yiffspace/extensions/logto/named_session_storage.rb
179
141
  - lib/yiffspace/extensions/object/to_b.rb
180
142
  - lib/yiffspace/extensions/object/truthy_falsy.rb
181
143
  - lib/yiffspace/extensions/string/sql.rb
@@ -217,19 +179,11 @@ files:
217
179
  - lib/yiffspace/include/user_name_methods.rb
218
180
  - lib/yiffspace/include/user_resolvable.rb
219
181
  - lib/yiffspace/include/user_resolvable_methods.rb
220
- - lib/yiffspace/logto_management_client.rb
221
- - lib/yiffspace/railtie.rb
222
182
  - lib/yiffspace/search/query_builder.rb
223
183
  - lib/yiffspace/search/query_dsl.rb
224
184
  - lib/yiffspace/search/query_helper.rb
225
- - lib/yiffspace/serializers/anonymous_auth_info_serializer.rb
226
- - lib/yiffspace/serializers/anonymous_user_info_serializer.rb
227
- - lib/yiffspace/serializers/auth_info_serializer.rb
228
185
  - lib/yiffspace/serializers/avatar_serializer.rb
229
186
  - lib/yiffspace/serializers/banner_serializer.rb
230
- - lib/yiffspace/serializers/discord_info_serializer.rb
231
- - lib/yiffspace/serializers/permissions_serializer.rb
232
- - lib/yiffspace/serializers/user_info_serializer.rb
233
187
  - lib/yiffspace/serializers/user_resolvable_serializer.rb
234
188
  - lib/yiffspace/utils.rb
235
189
  - lib/yiffspace/utils/cache.rb
@@ -244,7 +198,6 @@ files:
244
198
  - lib/yiffspace/utils/table_builder.rb
245
199
  - lib/yiffspace/utils/trace_logger.rb
246
200
  - lib/yiffspace/utils/user_attribute.rb
247
- - lib/yiffspace/utils/user_deduper.rb
248
201
  - lib/yiffspace/utils/user_like.rb
249
202
  - lib/yiffspace/utils/user_resolvable.rb
250
203
  - lib/yiffspace/utils/user_to_id.rb
@@ -1,6 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module YiffSpace
4
- module AuthHelper
5
- end
6
- end
@@ -1,11 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module YiffSpace
4
- module Auth
5
- class ApplicationController < ::YiffSpace::ApplicationController
6
- include(Helper)
7
-
8
- helper(Helper)
9
- end
10
- end
11
- end
@@ -1,49 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module YiffSpace
4
- module Auth
5
- class RootController < ApplicationController
6
- include(Helper)
7
-
8
- before_action(:sync_auth_if_dirty!)
9
-
10
- def show
11
- client.sign_in(redirect_uri: auth_client_config.redirect_uri, post_redirect_uri: params[:path] || "/")
12
- end
13
-
14
- def cb
15
- client.handle_sign_in_callback(url: request.original_url)
16
- user = client.fetch_user_info
17
- self.user = UserInfo.new(id: user["identities"]["discord"]["userId"], user: user, discord: user["identities"]["discord"]["details"]["rawData"])
18
- token = client.access_token_claims(resource: auth_client_config.resource)
19
- 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)
20
- end
21
-
22
- def permissions; end
23
-
24
- def logout
25
- client.sign_out(post_logout_redirect_uri: request.base_url)
26
- full_reset!
27
- end
28
-
29
- def debug
30
- return render("yiffspace/error", locals: { message: "Access Denied" }, status: :forbidden) unless YiffSpace::Auth.enable_debug_action?
31
-
32
- render(json: {
33
- env: request.env.select { |env| env.start_with?("yiffspace.") },
34
- params: params,
35
- session: session,
36
- client: auth_client_config.as_json.merge(client_secret: "[REDACTED]"),
37
- user: client.fetch_user_info,
38
- token: client.access_token_claims(resource: auth_client_config.resource),
39
- })
40
- end
41
-
42
- private
43
-
44
- def client
45
- @client ||= auth_client_config.logto(self)
46
- end
47
- end
48
- end
49
- end
@@ -1,73 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require("openssl")
4
- require("active_support/security_utils")
5
-
6
- module YiffSpace
7
- module Auth
8
- class WebhookController < ApplicationController
9
- skip_before_action(:verify_authenticity_token)
10
-
11
- HANDLED_EVENTS = %w[
12
- User.Roles.Updated
13
- User.SuspensionStatus.Updated
14
- User.Deleted
15
- Role.Scopes.Updated
16
- ].freeze
17
- DIRTY_FLAG_TTL = 24.hours
18
-
19
- def create
20
- unless verify_signature
21
- render(plain: "Unauthorized", status: :unauthorized)
22
- return
23
- end
24
-
25
- payload = JSON.parse(request.raw_post)
26
- event = payload["event"]
27
-
28
- handle_event(event, payload) if HANDLED_EVENTS.include?(event)
29
-
30
- head(:ok)
31
- rescue JSON::ParserError
32
- render(plain: "Bad Request", status: :bad_request)
33
- end
34
-
35
- private
36
-
37
- def verify_signature
38
- secret = auth_client_config.logto_webhook_secret
39
- return true if secret.blank?
40
-
41
- received = request.headers["logto-signature-sha-256"].to_s
42
- expected = OpenSSL::HMAC.hexdigest("SHA256", secret, request.raw_post)
43
- ActiveSupport::SecurityUtils.secure_compare(received, expected)
44
- end
45
-
46
- def handle_event(event, payload)
47
- data = payload["data"] || {}
48
-
49
- if event == "Role.Scopes.Updated"
50
- handle_role_scopes_updated(data)
51
- else
52
- user_id = data["id"]
53
- mark_dirty(user_id) if user_id.present?
54
- end
55
- end
56
-
57
- def handle_role_scopes_updated(data)
58
- role_id = data["id"]
59
- return if role_id.blank?
60
-
61
- management = auth_client_config.logto_management
62
- users = management.get_users_with_role(role_id)
63
- users.each { |u| mark_dirty(u["id"]) }
64
- rescue StandardError => e
65
- Rails.logger.error("[YiffSpace::Auth::WebhookController] Role.Scopes.Updated fan-out failed: #{e.message}")
66
- end
67
-
68
- def mark_dirty(user_id)
69
- Rails.cache.write(format(Helper::DIRTY_FLAG_KEY, user_id), true, expires_in: DIRTY_FLAG_TTL)
70
- end
71
- end
72
- end
73
- end
@@ -1,14 +0,0 @@
1
- <h1 class="title">Permissions</h1>
2
- <% if logged_in? %>
3
- <% if auth.permissions.any? %>
4
- <ul class="permissions-list">
5
- <% auth.permissions.each do |perm| %>
6
- <li class="permission"><%= perm %></li>
7
- <% end %>
8
- </ul>
9
- <% else %>
10
- <p class="message">You have no permissions.</p>
11
- <% end %>
12
- <% else %>
13
- <p class="message">You are not logged in.</p>
14
- <% end %>
@@ -1,12 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- YiffSpace::Auth::Engine.routes.draw do
4
- constraints(YiffSpace::Auth::SetClientName.default) do
5
- post(:webhook, controller: :webhook)
6
- get(:cb, controller: :root)
7
- get(:logout, controller: :root)
8
- get(:permissions, controller: :root)
9
- get(:debug, controller: :root) if YiffSpace::Auth.enable_debug_action?
10
- root(action: :show, controller: :root, as: :auth)
11
- end
12
- end
@@ -1,41 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- namespace(:yiffspace) do
4
- desc("Report and interactively remove duplicate/orphaned Logto users left behind by " \
5
- "get_or_create_user races. Prompts for confirmation before deleting each one. " \
6
- "Pass AUTH_CLIENT=name to use a registered auth client other than :default " \
7
- "(e.g. AUTH_CLIENT=yiffyapi_manage).")
8
- task(dedupe_users: :environment) do
9
- client_name = (ENV["AUTH_CLIENT"] || YiffSpace::Auth::DEFAULT_CLIENT_NAME).to_sym
10
- management = YiffSpace::Auth[client_name].logto_management
11
-
12
- puts("Scanning users via auth client #{client_name.inspect}...")
13
- result = YiffSpace::Utils::UserDeduper.scan(management)
14
-
15
- puts("\n#{result[:conflicts].size} discord id(s) with more than one linked user (ambiguous - not handled by this task, review manually):")
16
- result[:conflicts].each do |discord_id, group|
17
- puts(" discordId=#{discord_id}: #{group.map { |u| "#{u.id} (#{u.name})" }.join(', ')}")
18
- end
19
-
20
- puts("\n#{result[:unresolved_orphans].size} orphaned user(s) with no matching linked account (not handled by this task, review manually):")
21
- result[:unresolved_orphans].each do |user|
22
- puts(" #{user.id} (name=#{user.name}, avatar=#{user.data.avatar})")
23
- end
24
-
25
- puts("\n#{result[:deletable_orphans].size} confirmed duplicate(s) - orphan left by a losing get_or_create_user race:")
26
- if result[:deletable_orphans].empty?
27
- puts(" none found")
28
- else
29
- result[:deletable_orphans].each do |orphan, keeper|
30
- print(" delete #{orphan.id} (name=#{orphan.name}, avatar=#{orphan.data.avatar}), keeping #{keeper.id} (name=#{keeper.name}) for discordId=#{YiffSpace::Utils::UserDeduper.discord_id_for(keeper)}? [y/N] ")
31
- answer = $stdin.gets&.strip&.downcase
32
- if answer == "y"
33
- management.delete_user(orphan.id)
34
- puts(" deleted #{orphan.id}")
35
- else
36
- puts(" skipped")
37
- end
38
- end
39
- end
40
- end
41
- end
@@ -1,43 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module YiffSpace
4
- module Auth
5
- class ApiUser
6
- attr_reader(:data)
7
-
8
- def initialize(data)
9
- @data = Utils::OpenHash.from(data)
10
- end
11
-
12
- delegate(:id, :name, to: :data)
13
-
14
- def discord_id
15
- data.identities.discord.userId
16
- end
17
-
18
- def created_at
19
- Time.zone.at(data.createdAt)
20
- end
21
-
22
- def updated_at
23
- Time.zone.at(data.updatedAt)
24
- end
25
-
26
- def last_sign_in_at
27
- data.lastSignInAt.nil? ? nil : Time.zone.at(data.lastSignInAt)
28
- end
29
-
30
- def discord
31
- DiscordInfo.new(data.identities.discord.details.rawData)
32
- end
33
-
34
- def avatar
35
- Images::Avatar.get_for(discord_id, :discord)
36
- end
37
-
38
- def banner
39
- Images::Banner.get_for(discord_id, :discord)
40
- end
41
- end
42
- end
43
- end
@@ -1,60 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require("singleton")
4
-
5
- module YiffSpace
6
- module Auth
7
- class AuthInfo
8
- class Anonymous
9
- include(::Singleton)
10
-
11
- %i[id token].each do |attr|
12
- define_method(attr) { |*, **| raise(NotImplementedError, "#{attr} is not present on anonymous auth") }
13
- end
14
-
15
- def roles
16
- []
17
- end
18
-
19
- def permissions
20
- Permissions.new([])
21
- end
22
-
23
- def has_permission?(*)
24
- false
25
- end
26
-
27
- def anonymous?
28
- true
29
- end
30
-
31
- # this feels wrong, but it hopefully shouldn't break anything
32
- def present?
33
- false
34
- end
35
-
36
- def blank?
37
- true
38
- end
39
-
40
- def serializable_hash(*)
41
- nil
42
- end
43
-
44
- def to_session
45
- serializable_hash
46
- end
47
-
48
- def self.from_json(*)
49
- Anonymous.instance
50
- end
51
-
52
- def self.from_session(data)
53
- return nil if data.blank?
54
-
55
- from_json(data)
56
- end
57
- end
58
- end
59
- end
60
- end
@@ -1,78 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module YiffSpace
4
- module Auth
5
- class AuthInfo
6
- attr_reader(:id, :token, :roles, :permissions, :client_id)
7
-
8
- # @param id String
9
- # @param roles Array(String)
10
- # @param permissions Array(String)
11
- # @param token LogtoClient::AccessTokenClaims
12
- # @param client_id String
13
- def initialize(id:, roles:, permissions:, token:, client_id:)
14
- raise(ArgumentError, "no id provided") if id.blank?
15
- raise(ArgumentError, "no token provided") if token.blank?
16
- raise(ArgumentError, "no client id provided") if client_id.blank?
17
-
18
- @id = id
19
- @token = token
20
- @roles = Array(roles)
21
- @permissions = Permissions.new(permissions, separator: YiffSpace::Auth.get_by_id(client_id).permissions_separator)
22
- @client_id = client_id
23
- end
24
-
25
- def anonymous?
26
- false
27
- end
28
-
29
- # this feels wrong, but it hopefully shouldn't break anything
30
- def present?
31
- true
32
- end
33
-
34
- def blank?
35
- false
36
- end
37
-
38
- def has_permission?(name)
39
- permissions.include?(name.to_s)
40
- end
41
-
42
- def serializable_hash(*)
43
- {
44
- "id" => id,
45
- "token" => token.as_json,
46
- "roles" => roles,
47
- "permissions" => permissions.values,
48
- "client_id" => client_id,
49
- }
50
- end
51
-
52
- def to_session
53
- serializable_hash
54
- end
55
-
56
- def self.from_json(data)
57
- raise(ArgumentError, "invalid data") if data.blank?
58
-
59
- data = JSON.parse(data) if data.is_a?(String)
60
- data = ::YiffSpace::Utils::OpenHash.from(data)
61
-
62
- new(
63
- id: data.id,
64
- token: data.token,
65
- roles: data.roles,
66
- permissions: data.permissions,
67
- client_id: data.client_id,
68
- )
69
- end
70
-
71
- def self.from_session(data)
72
- return nil if data.blank?
73
-
74
- from_json(data)
75
- end
76
- end
77
- end
78
- end