masks 0.4.0 → 0.5.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 (179) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +16 -0
  3. data/LICENSE +21 -0
  4. data/README.md +215 -29
  5. data/app/controllers/masks/rails/base_controller.rb +13 -0
  6. data/app/controllers/masks/rails/handshakes_controller.rb +87 -0
  7. data/app/controllers/masks/rails/sessions_controller.rb +113 -0
  8. data/app/views/layouts/masks/rails/plain.html.erb +47 -0
  9. data/app/views/masks/rails/handshakes/refused.html.erb +12 -0
  10. data/app/views/masks/rails/handshakes/show.html.erb +40 -0
  11. data/config/routes.rb +10 -82
  12. data/lib/generators/masks/install/install_generator.rb +35 -22
  13. data/lib/generators/masks/install/templates/masks.rb.tt +38 -0
  14. data/lib/masks/client/claims.rb +103 -0
  15. data/lib/masks/client/errors.rb +52 -0
  16. data/lib/masks/client/handshake.rb +104 -0
  17. data/lib/masks/client/http.rb +81 -0
  18. data/lib/masks/client/introspection.rb +29 -0
  19. data/lib/masks/client/issuer.rb +76 -0
  20. data/lib/masks/client/pkce.rb +27 -0
  21. data/lib/masks/client/rack.rb +62 -0
  22. data/lib/masks/client/registration.rb +91 -0
  23. data/lib/masks/client/registry.rb +25 -0
  24. data/lib/masks/client/resource.rb +92 -0
  25. data/lib/masks/client/session.rb +146 -0
  26. data/lib/masks/client/stores.rb +40 -0
  27. data/lib/masks/client/tokens.rb +70 -0
  28. data/lib/masks/client/tracker.rb +122 -0
  29. data/lib/masks/client/verifier.rb +42 -0
  30. data/lib/masks/client.rb +51 -0
  31. data/lib/masks/rails/authentication.rb +217 -0
  32. data/lib/masks/rails/configurable.rb +11 -0
  33. data/lib/masks/rails/configuration.rb +172 -0
  34. data/lib/masks/rails/credentials.rb +60 -0
  35. data/lib/masks/rails/engine.rb +20 -0
  36. data/lib/masks/rails/protected_resource.rb +51 -0
  37. data/lib/masks/rails.rb +10 -0
  38. data/lib/masks/version.rb +1 -3
  39. data/lib/masks.rb +3 -183
  40. metadata +47 -416
  41. data/MIT-LICENSE +0 -20
  42. data/Rakefile +0 -11
  43. data/app/assets/builds/masks/application.css +0 -1
  44. data/app/assets/builds/masks/application.js +0 -8549
  45. data/app/assets/builds/masks/application.js.map +0 -7
  46. data/app/assets/images/masks.png +0 -0
  47. data/app/assets/javascripts/application.js +0 -2
  48. data/app/assets/javascripts/controllers/application.js +0 -9
  49. data/app/assets/javascripts/controllers/emails_controller.js +0 -28
  50. data/app/assets/javascripts/controllers/index.js +0 -21
  51. data/app/assets/javascripts/controllers/keys_controller.js +0 -20
  52. data/app/assets/javascripts/controllers/recover_controller.js +0 -21
  53. data/app/assets/javascripts/controllers/recover_password_controller.js +0 -21
  54. data/app/assets/javascripts/controllers/session_controller.js +0 -94
  55. data/app/assets/javascripts/controllers/table_controller.js +0 -15
  56. data/app/assets/manifest.js +0 -2
  57. data/app/assets/masks_manifest.js +0 -2
  58. data/app/assets/stylesheets/application.css +0 -34
  59. data/app/controllers/concerns/masks/controller.rb +0 -114
  60. data/app/controllers/masks/actors_controller.rb +0 -15
  61. data/app/controllers/masks/application_controller.rb +0 -35
  62. data/app/controllers/masks/backup_codes_controller.rb +0 -34
  63. data/app/controllers/masks/debug_controller.rb +0 -9
  64. data/app/controllers/masks/devices_controller.rb +0 -20
  65. data/app/controllers/masks/emails_controller.rb +0 -60
  66. data/app/controllers/masks/error_controller.rb +0 -14
  67. data/app/controllers/masks/keys_controller.rb +0 -45
  68. data/app/controllers/masks/manage/actors_controller.rb +0 -83
  69. data/app/controllers/masks/manage/base_controller.rb +0 -20
  70. data/app/controllers/masks/manage/clients_controller.rb +0 -84
  71. data/app/controllers/masks/manage/dashboard_controller.rb +0 -15
  72. data/app/controllers/masks/manage/devices_controller.rb +0 -19
  73. data/app/controllers/masks/one_time_code_controller.rb +0 -49
  74. data/app/controllers/masks/openid/authorizations_controller.rb +0 -45
  75. data/app/controllers/masks/openid/discoveries_controller.rb +0 -55
  76. data/app/controllers/masks/openid/tokens_controller.rb +0 -45
  77. data/app/controllers/masks/openid/userinfo_controller.rb +0 -28
  78. data/app/controllers/masks/passwords_controller.rb +0 -33
  79. data/app/controllers/masks/recoveries_controller.rb +0 -43
  80. data/app/controllers/masks/sessions_controller.rb +0 -53
  81. data/app/helpers/masks/application_helper.rb +0 -49
  82. data/app/jobs/masks/application_job.rb +0 -7
  83. data/app/jobs/masks/expire_actors_job.rb +0 -15
  84. data/app/jobs/masks/expire_recoveries_job.rb +0 -15
  85. data/app/mailers/masks/actor_mailer.rb +0 -22
  86. data/app/mailers/masks/application_mailer.rb +0 -15
  87. data/app/models/concerns/masks/access.rb +0 -162
  88. data/app/models/concerns/masks/actor.rb +0 -132
  89. data/app/models/concerns/masks/adapter.rb +0 -68
  90. data/app/models/concerns/masks/role.rb +0 -9
  91. data/app/models/concerns/masks/scoped.rb +0 -54
  92. data/app/models/masks/access/actor_password.rb +0 -21
  93. data/app/models/masks/access/actor_scopes.rb +0 -18
  94. data/app/models/masks/access/actor_signup.rb +0 -21
  95. data/app/models/masks/actors/anonymous.rb +0 -40
  96. data/app/models/masks/actors/system.rb +0 -24
  97. data/app/models/masks/adapters/active_record.rb +0 -85
  98. data/app/models/masks/application_model.rb +0 -15
  99. data/app/models/masks/application_record.rb +0 -8
  100. data/app/models/masks/check.rb +0 -192
  101. data/app/models/masks/credential.rb +0 -166
  102. data/app/models/masks/credentials/access_token.rb +0 -60
  103. data/app/models/masks/credentials/backup_code.rb +0 -30
  104. data/app/models/masks/credentials/device.rb +0 -59
  105. data/app/models/masks/credentials/email.rb +0 -48
  106. data/app/models/masks/credentials/factor2.rb +0 -71
  107. data/app/models/masks/credentials/key.rb +0 -38
  108. data/app/models/masks/credentials/last_login.rb +0 -12
  109. data/app/models/masks/credentials/masquerade.rb +0 -32
  110. data/app/models/masks/credentials/nickname.rb +0 -63
  111. data/app/models/masks/credentials/one_time_code.rb +0 -34
  112. data/app/models/masks/credentials/password.rb +0 -28
  113. data/app/models/masks/credentials/recovery.rb +0 -71
  114. data/app/models/masks/credentials/return_to.rb +0 -27
  115. data/app/models/masks/credentials/session.rb +0 -67
  116. data/app/models/masks/device.rb +0 -30
  117. data/app/models/masks/error.rb +0 -51
  118. data/app/models/masks/event.rb +0 -14
  119. data/app/models/masks/mask.rb +0 -266
  120. data/app/models/masks/openid/authorization.rb +0 -116
  121. data/app/models/masks/openid/token.rb +0 -56
  122. data/app/models/masks/rails/actor.rb +0 -212
  123. data/app/models/masks/rails/actor_role.rb +0 -12
  124. data/app/models/masks/rails/device.rb +0 -47
  125. data/app/models/masks/rails/email.rb +0 -96
  126. data/app/models/masks/rails/key.rb +0 -61
  127. data/app/models/masks/rails/openid/access_token.rb +0 -55
  128. data/app/models/masks/rails/openid/authorization.rb +0 -45
  129. data/app/models/masks/rails/openid/client.rb +0 -186
  130. data/app/models/masks/rails/openid/id_token.rb +0 -43
  131. data/app/models/masks/rails/recovery.rb +0 -116
  132. data/app/models/masks/rails/role.rb +0 -20
  133. data/app/models/masks/rails/scope.rb +0 -15
  134. data/app/models/masks/session.rb +0 -447
  135. data/app/models/masks/sessions/access.rb +0 -27
  136. data/app/models/masks/sessions/inline.rb +0 -16
  137. data/app/models/masks/sessions/request.rb +0 -42
  138. data/app/resources/masks/actor_resource.rb +0 -9
  139. data/app/resources/masks/session_resource.rb +0 -15
  140. data/app/views/layouts/masks/application.html.erb +0 -17
  141. data/app/views/layouts/masks/mailer.html.erb +0 -17
  142. data/app/views/layouts/masks/mailer.text.erb +0 -1
  143. data/app/views/layouts/masks/manage.html.erb +0 -42
  144. data/app/views/masks/actor_mailer/recover_credentials.html.erb +0 -32
  145. data/app/views/masks/actor_mailer/recover_credentials.text.erb +0 -1
  146. data/app/views/masks/actor_mailer/verify_email.html.erb +0 -33
  147. data/app/views/masks/actor_mailer/verify_email.text.erb +0 -8
  148. data/app/views/masks/actors/current.html.erb +0 -145
  149. data/app/views/masks/application/_header.html.erb +0 -30
  150. data/app/views/masks/backup_codes/new.html.erb +0 -117
  151. data/app/views/masks/emails/new.html.erb +0 -109
  152. data/app/views/masks/emails/verify.html.erb +0 -51
  153. data/app/views/masks/keys/new.html.erb +0 -127
  154. data/app/views/masks/manage/actors/index.html.erb +0 -104
  155. data/app/views/masks/manage/actors/show.html.erb +0 -172
  156. data/app/views/masks/manage/clients/index.html.erb +0 -102
  157. data/app/views/masks/manage/clients/show.html.erb +0 -156
  158. data/app/views/masks/manage/dashboard/index.html.erb +0 -10
  159. data/app/views/masks/manage/devices/index.html.erb +0 -47
  160. data/app/views/masks/one_time_code/new.html.erb +0 -167
  161. data/app/views/masks/openid/authorizations/error.html.erb +0 -23
  162. data/app/views/masks/openid/authorizations/new.html.erb +0 -46
  163. data/app/views/masks/passwords/edit.html.erb +0 -71
  164. data/app/views/masks/recoveries/new.html.erb +0 -69
  165. data/app/views/masks/recoveries/password.html.erb +0 -63
  166. data/app/views/masks/sessions/new.html.erb +0 -152
  167. data/config/brakeman.ignore +0 -28
  168. data/config/initializers/inflections.rb +0 -5
  169. data/config/locales/en.yml +0 -307
  170. data/db/migrate/20231205173845_create_actors.rb +0 -94
  171. data/db/migrate/20240329182422_support_openid.rb +0 -64
  172. data/lib/generators/masks/install/USAGE +0 -8
  173. data/lib/generators/masks/install/templates/initializer.rb +0 -5
  174. data/lib/generators/masks/install/templates/masks.json +0 -9
  175. data/lib/masks/configuration.rb +0 -249
  176. data/lib/masks/engine.rb +0 -25
  177. data/lib/masks/middleware.rb +0 -70
  178. data/lib/tasks/masks_tasks.rake +0 -72
  179. data/masks.json +0 -315
@@ -1,15 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Masks
4
- # @visibility private
5
- class ApplicationMailer < ActionMailer::Base
6
- default from: "from@example.com"
7
- layout "mailer"
8
-
9
- helper do
10
- def logged_in?
11
- false
12
- end
13
- end
14
- end
15
- end
@@ -1,162 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Masks
4
- # Concern to help with building access classes.
5
- #
6
- # Access classes must include this module, which will result in the class
7
- # behaving like an +ActiveModel+ instance, with attributes, validations, and
8
- # json serialization available by default.
9
- #
10
- # After including the module, classes must call +access+ to register the
11
- # class and its canonical name.
12
- #
13
- # @example
14
- # class ExampleAccess
15
- # include Masks::Access
16
- #
17
- # access 'example'
18
- #
19
- # def say_hi
20
- # puts 'hello world!'
21
- # end
22
- # end
23
- #
24
- # # Later, this class can be accessed with a valid session,
25
- # # provided there is a corresponding mask that allows it.
26
- # access = Masks.access('example', session)
27
- # access.say_hi if access
28
- #
29
- # @see Masks::Access::ClassMethods
30
- module Access
31
- extend ActiveSupport::Concern
32
-
33
- class << self
34
- # @visibility private
35
- def classes
36
- @classes ||= {}
37
- end
38
-
39
- # @visibility private
40
- def register(name, **defaults)
41
- classes[name.to_s] = defaults
42
- end
43
-
44
- # @visibility private
45
- def defaults(name)
46
- classes.fetch(name.to_s, nil)
47
- end
48
- end
49
-
50
- included do
51
- attr_accessor :session
52
-
53
- def actor
54
- raise Masks::Error::InvalidSession unless session
55
-
56
- session.actor
57
- end
58
-
59
- delegate :config,
60
- :roles,
61
- :role?,
62
- :role_records,
63
- :scopes,
64
- :scope?,
65
- :params,
66
- to: :session
67
-
68
- delegate :access_config, to: :class
69
- end
70
-
71
- # Class methods for classes that include +Masks::Access+.
72
- module ClassMethods
73
- # Overrides `new` to ensure classes are constructed with proper access.
74
- # @visibility private
75
- def new(*args, **opts)
76
- original =
77
- if args[0].is_a?(Masks::Session)
78
- args.delete_at(0)
79
- elsif opts[:session]
80
- opts.delete(:session)
81
- else
82
- raise Masks::Error::InvalidSession
83
- end
84
-
85
- model = original.config.model(:access)
86
- session = model.new(name: access_name, original:)
87
- session.mask!
88
-
89
- raise Masks::Error::Unauthorized unless session.passed?
90
-
91
- instance = super(*args, **opts)
92
- instance.session = session
93
- instance
94
- end
95
-
96
- # Returns the canonical access name for the class.
97
- #
98
- # @return [String]
99
- def access_name
100
- @access_name
101
- end
102
-
103
- # Registers the class by the supplied name.
104
- #
105
- # Any +opts+ provided will be used as defaults for instances,
106
- # in addition to the data supplied in the app's configuration.
107
- #
108
- # This can be called multiple times. If names are the same, +opts+
109
- # will be deep merged together. Different names can be supplied as
110
- # well.
111
- #
112
- # @param [String] name
113
- # @param [Hash] opts
114
- # @return [nil]
115
- def access(name, **opts)
116
- @access_name = name
117
-
118
- Masks::Access.register(access_name, **opts.merge(cls: self))
119
-
120
- nil
121
- end
122
-
123
- # Returns the configuration for the class.
124
- #
125
- # This is a combination of data provided to +access+ along with whatever
126
- # is specifed in the configuration object for the access class.
127
- #
128
- # @return [String]
129
- def access_config
130
- Masks.configuration.access(access_name)
131
- end
132
-
133
- # Builds a new access class, given a variety of arguments.
134
- #
135
- # @overload build(request)
136
- # @param [ActionDispatch::Request] request
137
- # @overload build(controller)
138
- # @param [ActionController::Metal] controller
139
- # @overload build(session)
140
- # @param [Masks::Session] session
141
- # @overload build(actor)
142
- # @param [Masks::Actor] actor
143
- # @overload build(**attrs)
144
- # @param [ActionController::Metal] controller
145
- # @return [Masks::Access]
146
- def build(arg1 = nil, **args)
147
- case arg1
148
- when ActionDispatch::Request
149
- new(session: Masks::Sessions::Request.new(session: arg1))
150
- when ActionController::Metal
151
- new(session: arg1.send(:masked_session))
152
- when Masks::Session
153
- new(session: arg1, **args)
154
- when Masks::Actor
155
- new(session: Masks::Sessions::Actor.new(arg1, **opts))
156
- when nil
157
- new(**opts)
158
- end
159
- end
160
- end
161
- end
162
- end
@@ -1,132 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Masks
4
- # An interface that all masked actors should adhere to.
5
- #
6
- # @see Masks::Scoped Masks::Scoped
7
- # @see Masks::Rails::Actor Masks::Rails::Actor
8
- # @see Actors::Anonymous
9
- # @see Actors::System
10
- module Actor
11
- include Scoped
12
-
13
- # A unique identifier for the actor.
14
- #
15
- # This value is used for internal references to actors, e.g. when they are
16
- # stored in the rails session.
17
- #
18
- # @return [String]
19
- def actor_id
20
- nickname
21
- end
22
-
23
- # A session identifier for the actor.
24
- #
25
- # This value is used for internal references to actors, e.g. when they are
26
- # stored in the rails session.
27
- #
28
- # @return [String]
29
- def session_key
30
- Digest::MD5.hexdigest(
31
- [Masks.configuration.version, version, actor_id].join("-")
32
- )
33
- end
34
-
35
- # An internal version counter for the actor.
36
- #
37
- # Session keys use this value so they automatically expire when it changes.
38
- #
39
- # @return [String]
40
- def version
41
- raise NotImplementedError unless defined?(super)
42
-
43
- super
44
- end
45
-
46
- # A nickname for the actor.
47
- #
48
- # @return [String]
49
- def nickname
50
- raise NotImplementedError unless defined?(super)
51
-
52
- super
53
- end
54
-
55
- # Sets a password for the actor.
56
- #
57
- # @param [String] password
58
- # @return [String]
59
- def password=(password)
60
- raise NotImplementedError unless defined?(super)
61
-
62
- super
63
- end
64
-
65
- # Sets the current session on the actor.
66
- #
67
- # @param [Masks::Session] session
68
- # @return [String]
69
- def session=(session)
70
- raise NotImplementedError unless defined?(super)
71
-
72
- super
73
- end
74
-
75
- # Validates the given password.
76
- #
77
- # @param [String] password
78
- # @return [Boolean]
79
- def authenticate(password)
80
- raise NotImplementedError unless defined?(super)
81
-
82
- super
83
- end
84
-
85
- # Returns a list of scopes granted to the actor.
86
- #
87
- # @return [Array<String>] An array of scopes (as strings)
88
- def scopes
89
- raise NotImplementedError
90
- end
91
-
92
- # A callback that is invoked for masked sessions involving this actor.
93
- #
94
- # This method is only called when everything else—credentials, checks,
95
- # and other mask rules—have passed. If this method returns a truthy value
96
- # the session will pass, otherwise it will fail.
97
- #
98
- # This is a great place to add final checks, validations, and onboarding
99
- # data to the actor before saving it.
100
- #
101
- # @return [Boolean]
102
- def mask!
103
- raise NotImplementedError
104
- end
105
-
106
- # Whether or not the actor requires a second layer of authentication.
107
- #
108
- # @return [Boolean]
109
- def factor2?
110
- false
111
- end
112
-
113
- # Whether or not the actor is anonymous, e.g. instantiated but un-identified.
114
- #
115
- # @return [Boolean]
116
- def anonymous?
117
- false
118
- end
119
-
120
- # Whether or not to save the results of any masked sessions involving this actor.
121
- #
122
- # Typically this is best controlled at the mask level, but there are some cases
123
- # where it is useful to control at the actor-level. For example, the implementation
124
- # for anonymous actors always returns `true` for this method, so that anonymous
125
- # actors never end up in the rails session or other databases.
126
- #
127
- # @return [Boolean]
128
- def backup?
129
- !anonymous?
130
- end
131
- end
132
- end
@@ -1,68 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Masks
4
- # An interface that all configuration adapters should adhere to.
5
- #
6
- # @see Masks::Adapters::ActiveRecord
7
- module Adapter
8
- # Creates a new adapter.
9
- #
10
- # @param [Masks::Configuration] config
11
- # @return [Masks::Adapter]
12
- def initialize(config)
13
- @config = config
14
- end
15
-
16
- # Returns an actor given the passed options, which may
17
- # contain a nickname and/or an email.
18
- #
19
- # @param [Masks::Session] session
20
- # @param [Hash] opts
21
- # @return [Masks::Actor] or nil if not found
22
- def find_actor(session, **opts)
23
- raise NotImplementedError
24
- end
25
-
26
- # Returns a list of actors matching the passed actor_ids.
27
- #
28
- # @param [Masks::Session] session
29
- # @param [Array] actor_ids
30
- # @return [Array<Masks::Actor>]
31
- def find_actors(session, actor_ids)
32
- raise NotImplementedError
33
- end
34
-
35
- # Expires any outdated or invalid actors.
36
- #
37
- # @return
38
- def expire_actors
39
- raise NotImplementedError
40
- end
41
-
42
- # Builds an actor from the passed options, which may contain
43
- # a nickname or email. Additional attributes, like a password,
44
- # will not be supplied.
45
- #
46
- # @param [Masks::Session] session
47
- # @param [Hash] opts
48
- # @return [Masks::Actor]
49
- def build_actor(session, **opts)
50
- raise NotImplementedError
51
- end
52
-
53
- # @visibility private
54
- def find_recovery(session, **opts)
55
- raise NotImplementedError
56
- end
57
-
58
- # @visibility private
59
- def build_recovery(session, **opts)
60
- raise NotImplementedError
61
- end
62
-
63
- # @visibility private
64
- def expire_recoveries
65
- raise NotImplementedError
66
- end
67
- end
68
- end
@@ -1,9 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Masks
4
- # An interface that all roles should adhere to.
5
- #
6
- # @see Masks::Rails::Role Masks::Rails::Role
7
- module Role
8
- end
9
- end
@@ -1,54 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Masks
4
- # A smaller interface that all scoped actors should adhere to.
5
- #
6
- # @see Masks::Rails::Actor Masks::Rails::Actor
7
- # @see Masks::Actor Masks::Actor
8
- module Scoped
9
- # Returns a list of scopes granted to the actor.
10
- #
11
- # @return [Array<String>] An array of scopes (as strings)
12
- def scopes
13
- raise NotImplementedError
14
- end
15
-
16
- # Returns whether or not a scope is available.
17
- #
18
- # In practice this is similar to calling +scopes.include?(scope)+,
19
- # but implementations may provide faster implementations.
20
- #
21
- # @param [String] scope
22
- # @return [Boolean]
23
- def scope?(scope)
24
- scopes.include?(scope.to_s)
25
- end
26
-
27
- # Returns a list of Masks::Role records for the scoped actor.
28
- #
29
- # @param [String|Object] record or type
30
- # @param [Hash] opts to use for additional filtering
31
- # @return [Masks::Role]
32
- def roles(record, **opts)
33
- raise NotImplementedError
34
- end
35
-
36
- # Returns whether or not a role is available to the scoped actor.
37
- #
38
- # @param [String|Object] record or type
39
- # @param [Hash] opts to use for additional filtering
40
- # @return [Boolean]
41
- def role?(record, **opts)
42
- roles(record, **opts).any?
43
- end
44
-
45
- # Similar to roles_for, except all _records_ are returned instead of the role.
46
- #
47
- # @param [String|Object] record_type record or type
48
- # @param [Hash] opts to use for additional filtering
49
- # @return [Object] a list of records, duplicates removed
50
- def role_records(record_type, **opts)
51
- roles(record_type, **opts).map(&:record).uniq
52
- end
53
- end
54
- end
@@ -1,21 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Masks
4
- module Access
5
- # Access class for +actor.password+
6
- #
7
- # This access class can change that actor's password.
8
- class ActorPassword
9
- include Access
10
-
11
- access "actor.password"
12
-
13
- def change_password(password, **opts)
14
- actor = opts[:actor] || self.actor
15
- actor.changed_password_at = Time.current
16
- actor.password = password
17
- actor.save if actor.valid?
18
- end
19
- end
20
- end
21
- end
@@ -1,18 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Masks
4
- module Access
5
- # Access class for +actor.scopes+
6
- #
7
- # This access class can add or remove scopes from an actor.
8
- class ActorScopes
9
- include Access
10
-
11
- access "actor.scopes"
12
-
13
- def assign_scopes(scopes)
14
- actor.assign_scopes!(*scopes)
15
- end
16
- end
17
- end
18
- end
@@ -1,21 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Masks
4
- module Access
5
- # Access class for +actor.signup+.
6
- #
7
- # This access class creates a new actor.
8
- class ActorSignup
9
- include Access
10
-
11
- access "actor.signup"
12
-
13
- def signup(**opts)
14
- actor = config.build_actor(session, **opts.slice(:nickname, :email))
15
- actor.password = opts[:password]
16
- actor.save if actor.valid?
17
- actor
18
- end
19
- end
20
- end
21
- end
@@ -1,40 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Masks
4
- module Actors
5
- # An anonymous actor, used for cases where deemed acceptable.
6
- #
7
- # @see Masks::Actor
8
- class Anonymous < ApplicationModel
9
- include Masks::Actor
10
-
11
- attribute :session
12
-
13
- # Generates and returns random nickname for the actor.
14
- #
15
- # @return [String]
16
- def nickname
17
- @nickname ||= "anon:#{SecureRandom.hex}"
18
- end
19
-
20
- # @return [Array] an empty array, since no scopes are available to anonymous actors
21
- def scopes
22
- []
23
- end
24
-
25
- # This is a no-op for anonymous actors. It always returns true.
26
- #
27
- # @return [Boolean]
28
- def mask!
29
- true
30
- end
31
-
32
- # Mark this actor as anonymous.
33
- #
34
- # @return [Boolean]
35
- def anonymous?
36
- true
37
- end
38
- end
39
- end
40
- end
@@ -1,24 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Masks
4
- module Actors
5
- # Actor for system tasks.
6
- class System < ApplicationModel
7
- include Masks::Actor
8
-
9
- attribute :session
10
-
11
- def nickname
12
- @nickname ||= "system:#{SecureRandom.hex}"
13
- end
14
-
15
- def scopes
16
- []
17
- end
18
-
19
- def mask!
20
- true
21
- end
22
- end
23
- end
24
- end
@@ -1,85 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Masks
4
- module Adapters
5
- # ActiveRecord adapter for masks.
6
- #
7
- # Although this is designed for masks built-in models, any models
8
- # adhering to the same interface can be used. It is also possible to
9
- # override and extend the models used in the configuration.
10
- #
11
- # @see Masks::Adapter
12
- class ActiveRecord
13
- include Masks::Adapter
14
-
15
- def find_key(_session, secret:)
16
- Masks::Rails::Key.find_by(sha: Masks::Rails::Key.sha(secret))
17
- end
18
-
19
- def find_device(session, actor: nil, key: nil)
20
- device = session.device
21
- actor ||= session.actor
22
-
23
- return unless device.known? && actor
24
-
25
- key ||=
26
- Digest::SHA512.hexdigest(
27
- [
28
- device.name,
29
- device.os_name,
30
- device.device_name,
31
- device.device_type
32
- ].compact.join("-")
33
- )
34
-
35
- record = Masks::Rails::Device.find_or_initialize_by(actor:, key:)
36
- record.session = session
37
- record
38
- end
39
-
40
- def find_actor(session, **opts)
41
- if opts[:email]
42
- session
43
- .mask
44
- .actor_scope
45
- .includes(:emails)
46
- .find_by(emails: { email: opts[:email]&.downcase, verified: true })
47
- elsif opts[:nickname]
48
- session.mask.actor_scope.find_by(nickname: opts[:nickname])
49
- end
50
- end
51
-
52
- def find_actors(session, ids)
53
- session.mask.actor_scope.where(nickname: ids).to_a
54
- end
55
-
56
- def build_actor(session, **opts)
57
- opts[:session] = session
58
- record =
59
- session.mask.actor_scope.new(session:, nickname: opts[:nickname])
60
- record.emails.build(email: opts[:email]) if opts[:email]
61
- record
62
- end
63
-
64
- def expire_actors
65
- @config.model(:actor).expired.destroy_all
66
- end
67
-
68
- def expire_recoveries
69
- @config.model(:recovery).expired.destroy_all
70
- end
71
-
72
- def find_recovery(_session, **opts)
73
- if opts[:token]
74
- @config.model(:recovery).recent.find_by(token: opts[:token])
75
- elsif opts[:id]
76
- @config.model(:recovery).recent.find_by(id: opts[:id])
77
- end
78
- end
79
-
80
- def build_recovery(session, **opts)
81
- @config.model(:recovery).new(configuration: @config, session:, **opts)
82
- end
83
- end
84
- end
85
- end
@@ -1,15 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Masks
4
- # Base model for synthetic +ActiveRecord+-style models in masks.
5
- #
6
- # Most models in masks use this in their inheritance tree, as it
7
- # provides attributes, validations, and other features from
8
- # +ActiveModel+.
9
- class ApplicationModel
10
- include ActiveModel::Model
11
- include ActiveModel::Validations
12
- include ActiveModel::Attributes
13
- include ActiveModel::Serializers::JSON
14
- end
15
- end
@@ -1,8 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Masks
4
- # Base model for +ActiveRecord+-backed database tables in masks.
5
- class ApplicationRecord < ActiveRecord::Base
6
- self.abstract_class = true
7
- end
8
- end