masks 0.4.0 → 0.6.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 (180) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +29 -0
  3. data/LICENSE +21 -0
  4. data/README.md +235 -29
  5. data/app/controllers/masks/rails/avatars_controller.rb +51 -0
  6. data/app/controllers/masks/rails/base_controller.rb +13 -0
  7. data/app/controllers/masks/rails/handshakes_controller.rb +86 -0
  8. data/app/controllers/masks/rails/sessions_controller.rb +118 -0
  9. data/app/views/layouts/masks/rails/plain.html.erb +47 -0
  10. data/app/views/masks/rails/handshakes/refused.html.erb +12 -0
  11. data/app/views/masks/rails/handshakes/show.html.erb +40 -0
  12. data/config/routes.rb +11 -82
  13. data/lib/generators/masks/install/install_generator.rb +35 -22
  14. data/lib/generators/masks/install/templates/masks.rb.tt +38 -0
  15. data/lib/masks/client/claims.rb +144 -0
  16. data/lib/masks/client/errors.rb +60 -0
  17. data/lib/masks/client/handshake.rb +104 -0
  18. data/lib/masks/client/http.rb +96 -0
  19. data/lib/masks/client/introspection.rb +29 -0
  20. data/lib/masks/client/issuer.rb +92 -0
  21. data/lib/masks/client/pkce.rb +27 -0
  22. data/lib/masks/client/rack.rb +62 -0
  23. data/lib/masks/client/registration.rb +115 -0
  24. data/lib/masks/client/registry.rb +25 -0
  25. data/lib/masks/client/resource.rb +92 -0
  26. data/lib/masks/client/session.rb +146 -0
  27. data/lib/masks/client/stores.rb +40 -0
  28. data/lib/masks/client/tokens.rb +70 -0
  29. data/lib/masks/client/tracker.rb +122 -0
  30. data/lib/masks/client/verifier.rb +42 -0
  31. data/lib/masks/client.rb +51 -0
  32. data/lib/masks/rails/authentication.rb +260 -0
  33. data/lib/masks/rails/configurable.rb +11 -0
  34. data/lib/masks/rails/configuration.rb +184 -0
  35. data/lib/masks/rails/credentials.rb +60 -0
  36. data/lib/masks/rails/engine.rb +20 -0
  37. data/lib/masks/rails/protected_resource.rb +51 -0
  38. data/lib/masks/rails.rb +10 -0
  39. data/lib/masks/version.rb +1 -3
  40. data/lib/masks.rb +3 -183
  41. metadata +48 -416
  42. data/MIT-LICENSE +0 -20
  43. data/Rakefile +0 -11
  44. data/app/assets/builds/masks/application.css +0 -1
  45. data/app/assets/builds/masks/application.js +0 -8549
  46. data/app/assets/builds/masks/application.js.map +0 -7
  47. data/app/assets/images/masks.png +0 -0
  48. data/app/assets/javascripts/application.js +0 -2
  49. data/app/assets/javascripts/controllers/application.js +0 -9
  50. data/app/assets/javascripts/controllers/emails_controller.js +0 -28
  51. data/app/assets/javascripts/controllers/index.js +0 -21
  52. data/app/assets/javascripts/controllers/keys_controller.js +0 -20
  53. data/app/assets/javascripts/controllers/recover_controller.js +0 -21
  54. data/app/assets/javascripts/controllers/recover_password_controller.js +0 -21
  55. data/app/assets/javascripts/controllers/session_controller.js +0 -94
  56. data/app/assets/javascripts/controllers/table_controller.js +0 -15
  57. data/app/assets/manifest.js +0 -2
  58. data/app/assets/masks_manifest.js +0 -2
  59. data/app/assets/stylesheets/application.css +0 -34
  60. data/app/controllers/concerns/masks/controller.rb +0 -114
  61. data/app/controllers/masks/actors_controller.rb +0 -15
  62. data/app/controllers/masks/application_controller.rb +0 -35
  63. data/app/controllers/masks/backup_codes_controller.rb +0 -34
  64. data/app/controllers/masks/debug_controller.rb +0 -9
  65. data/app/controllers/masks/devices_controller.rb +0 -20
  66. data/app/controllers/masks/emails_controller.rb +0 -60
  67. data/app/controllers/masks/error_controller.rb +0 -14
  68. data/app/controllers/masks/keys_controller.rb +0 -45
  69. data/app/controllers/masks/manage/actors_controller.rb +0 -83
  70. data/app/controllers/masks/manage/base_controller.rb +0 -20
  71. data/app/controllers/masks/manage/clients_controller.rb +0 -84
  72. data/app/controllers/masks/manage/dashboard_controller.rb +0 -15
  73. data/app/controllers/masks/manage/devices_controller.rb +0 -19
  74. data/app/controllers/masks/one_time_code_controller.rb +0 -49
  75. data/app/controllers/masks/openid/authorizations_controller.rb +0 -45
  76. data/app/controllers/masks/openid/discoveries_controller.rb +0 -55
  77. data/app/controllers/masks/openid/tokens_controller.rb +0 -45
  78. data/app/controllers/masks/openid/userinfo_controller.rb +0 -28
  79. data/app/controllers/masks/passwords_controller.rb +0 -33
  80. data/app/controllers/masks/recoveries_controller.rb +0 -43
  81. data/app/controllers/masks/sessions_controller.rb +0 -53
  82. data/app/helpers/masks/application_helper.rb +0 -49
  83. data/app/jobs/masks/application_job.rb +0 -7
  84. data/app/jobs/masks/expire_actors_job.rb +0 -15
  85. data/app/jobs/masks/expire_recoveries_job.rb +0 -15
  86. data/app/mailers/masks/actor_mailer.rb +0 -22
  87. data/app/mailers/masks/application_mailer.rb +0 -15
  88. data/app/models/concerns/masks/access.rb +0 -162
  89. data/app/models/concerns/masks/actor.rb +0 -132
  90. data/app/models/concerns/masks/adapter.rb +0 -68
  91. data/app/models/concerns/masks/role.rb +0 -9
  92. data/app/models/concerns/masks/scoped.rb +0 -54
  93. data/app/models/masks/access/actor_password.rb +0 -21
  94. data/app/models/masks/access/actor_scopes.rb +0 -18
  95. data/app/models/masks/access/actor_signup.rb +0 -21
  96. data/app/models/masks/actors/anonymous.rb +0 -40
  97. data/app/models/masks/actors/system.rb +0 -24
  98. data/app/models/masks/adapters/active_record.rb +0 -85
  99. data/app/models/masks/application_model.rb +0 -15
  100. data/app/models/masks/application_record.rb +0 -8
  101. data/app/models/masks/check.rb +0 -192
  102. data/app/models/masks/credential.rb +0 -166
  103. data/app/models/masks/credentials/access_token.rb +0 -60
  104. data/app/models/masks/credentials/backup_code.rb +0 -30
  105. data/app/models/masks/credentials/device.rb +0 -59
  106. data/app/models/masks/credentials/email.rb +0 -48
  107. data/app/models/masks/credentials/factor2.rb +0 -71
  108. data/app/models/masks/credentials/key.rb +0 -38
  109. data/app/models/masks/credentials/last_login.rb +0 -12
  110. data/app/models/masks/credentials/masquerade.rb +0 -32
  111. data/app/models/masks/credentials/nickname.rb +0 -63
  112. data/app/models/masks/credentials/one_time_code.rb +0 -34
  113. data/app/models/masks/credentials/password.rb +0 -28
  114. data/app/models/masks/credentials/recovery.rb +0 -71
  115. data/app/models/masks/credentials/return_to.rb +0 -27
  116. data/app/models/masks/credentials/session.rb +0 -67
  117. data/app/models/masks/device.rb +0 -30
  118. data/app/models/masks/error.rb +0 -51
  119. data/app/models/masks/event.rb +0 -14
  120. data/app/models/masks/mask.rb +0 -266
  121. data/app/models/masks/openid/authorization.rb +0 -116
  122. data/app/models/masks/openid/token.rb +0 -56
  123. data/app/models/masks/rails/actor.rb +0 -212
  124. data/app/models/masks/rails/actor_role.rb +0 -12
  125. data/app/models/masks/rails/device.rb +0 -47
  126. data/app/models/masks/rails/email.rb +0 -96
  127. data/app/models/masks/rails/key.rb +0 -61
  128. data/app/models/masks/rails/openid/access_token.rb +0 -55
  129. data/app/models/masks/rails/openid/authorization.rb +0 -45
  130. data/app/models/masks/rails/openid/client.rb +0 -186
  131. data/app/models/masks/rails/openid/id_token.rb +0 -43
  132. data/app/models/masks/rails/recovery.rb +0 -116
  133. data/app/models/masks/rails/role.rb +0 -20
  134. data/app/models/masks/rails/scope.rb +0 -15
  135. data/app/models/masks/session.rb +0 -447
  136. data/app/models/masks/sessions/access.rb +0 -27
  137. data/app/models/masks/sessions/inline.rb +0 -16
  138. data/app/models/masks/sessions/request.rb +0 -42
  139. data/app/resources/masks/actor_resource.rb +0 -9
  140. data/app/resources/masks/session_resource.rb +0 -15
  141. data/app/views/layouts/masks/application.html.erb +0 -17
  142. data/app/views/layouts/masks/mailer.html.erb +0 -17
  143. data/app/views/layouts/masks/mailer.text.erb +0 -1
  144. data/app/views/layouts/masks/manage.html.erb +0 -42
  145. data/app/views/masks/actor_mailer/recover_credentials.html.erb +0 -32
  146. data/app/views/masks/actor_mailer/recover_credentials.text.erb +0 -1
  147. data/app/views/masks/actor_mailer/verify_email.html.erb +0 -33
  148. data/app/views/masks/actor_mailer/verify_email.text.erb +0 -8
  149. data/app/views/masks/actors/current.html.erb +0 -145
  150. data/app/views/masks/application/_header.html.erb +0 -30
  151. data/app/views/masks/backup_codes/new.html.erb +0 -117
  152. data/app/views/masks/emails/new.html.erb +0 -109
  153. data/app/views/masks/emails/verify.html.erb +0 -51
  154. data/app/views/masks/keys/new.html.erb +0 -127
  155. data/app/views/masks/manage/actors/index.html.erb +0 -104
  156. data/app/views/masks/manage/actors/show.html.erb +0 -172
  157. data/app/views/masks/manage/clients/index.html.erb +0 -102
  158. data/app/views/masks/manage/clients/show.html.erb +0 -156
  159. data/app/views/masks/manage/dashboard/index.html.erb +0 -10
  160. data/app/views/masks/manage/devices/index.html.erb +0 -47
  161. data/app/views/masks/one_time_code/new.html.erb +0 -167
  162. data/app/views/masks/openid/authorizations/error.html.erb +0 -23
  163. data/app/views/masks/openid/authorizations/new.html.erb +0 -46
  164. data/app/views/masks/passwords/edit.html.erb +0 -71
  165. data/app/views/masks/recoveries/new.html.erb +0 -69
  166. data/app/views/masks/recoveries/password.html.erb +0 -63
  167. data/app/views/masks/sessions/new.html.erb +0 -152
  168. data/config/brakeman.ignore +0 -28
  169. data/config/initializers/inflections.rb +0 -5
  170. data/config/locales/en.yml +0 -307
  171. data/db/migrate/20231205173845_create_actors.rb +0 -94
  172. data/db/migrate/20240329182422_support_openid.rb +0 -64
  173. data/lib/generators/masks/install/USAGE +0 -8
  174. data/lib/generators/masks/install/templates/initializer.rb +0 -5
  175. data/lib/generators/masks/install/templates/masks.json +0 -9
  176. data/lib/masks/configuration.rb +0 -249
  177. data/lib/masks/engine.rb +0 -25
  178. data/lib/masks/middleware.rb +0 -70
  179. data/lib/tasks/masks_tasks.rake +0 -72
  180. data/masks.json +0 -315
@@ -1,186 +0,0 @@
1
- # frozen_string_literal: true
2
- module Masks
3
- module Rails
4
- module OpenID
5
- class Client < ApplicationRecord
6
- include Masks::Scoped
7
-
8
- self.table_name = "openid_clients"
9
-
10
- validates :name, presence: true
11
-
12
- after_initialize :generate_credentials
13
- before_validation :generate_key, on: :create
14
-
15
- serialize :scopes, coder: JSON
16
- serialize :redirect_uris, coder: JSON
17
- serialize :response_types, coder: JSON
18
- serialize :grant_types, coder: JSON
19
-
20
- validates :key, :secret, :scopes, presence: true
21
- validates :key, uniqueness: true
22
- validates :client_type,
23
- inclusion: {
24
- in: %w[public confidential]
25
- },
26
- presence: true
27
- validates :subject_type,
28
- inclusion: {
29
- in: Masks.configuration.openid[:subject_types]
30
- },
31
- presence: true
32
- validate :validate_expiries
33
-
34
- has_many :access_tokens,
35
- class_name: Masks.configuration.models[:openid_access_token],
36
- inverse_of: :openid_client
37
- has_many :authorizations,
38
- class_name: Masks.configuration.models[:openid_authorization],
39
- inverse_of: :openid_client
40
- has_many :saved_roles,
41
- class_name: Masks.configuration.models[:role],
42
- autosave: true
43
-
44
- def to_param
45
- key
46
- end
47
-
48
- def response_types
49
- case client_type
50
- when "confidential"
51
- ["code"]
52
- when "public"
53
- ["token", "id_token", "id_token token"]
54
- end
55
- end
56
-
57
- def grant_types
58
- case client_type
59
- when "confidential"
60
- %w[refresh_token authorization_code client_credentials]
61
- else
62
- []
63
- end
64
- end
65
-
66
- def scopes
67
- self[:scopes]
68
- end
69
-
70
- def roles(record, **opts)
71
- case record
72
- when Class, String
73
- saved_roles.where(record_type: record.to_s, **opts).includes(
74
- :record
75
- )
76
- else
77
- saved_roles.where(record:, **opts)
78
- end
79
- end
80
-
81
- def issuer
82
- Masks::Engine.routes.url_helpers.openid_issuer_url(
83
- id: key,
84
- host: Masks.configuration.site_url
85
- )
86
- end
87
-
88
- def kid
89
- :default
90
- end
91
-
92
- def private_key
93
- OpenSSL::PKey::RSA.new(rsa_private_key)
94
- end
95
-
96
- delegate :public_key, to: :private_key
97
-
98
- def subject(actor)
99
- case subject_type
100
- when "nickname"
101
- actor.nickname
102
- else
103
- Digest::SHA256.hexdigest(
104
- [
105
- sector_identifier,
106
- actor.actor_id,
107
- Masks.configuration.openid[:pairwise_salt]
108
- ].join("/")
109
- )
110
- end
111
- end
112
-
113
- def audience
114
- key
115
- end
116
-
117
- def auto_consent?
118
- !consent
119
- end
120
-
121
- def pairwise_subject?
122
- sector_identifier && subject_type == "pairwise"
123
- end
124
-
125
- def assign_scopes!(*scopes)
126
- self.scopes = [*scopes, *self.scopes].uniq.compact
127
- save!
128
- end
129
-
130
- def remove_scopes!(*scopes)
131
- scopes.each { |scope| self.scopes.delete(scope) }
132
-
133
- save!
134
- end
135
-
136
- def code_expires_at
137
- Time.now + ChronicDuration.parse(code_expires_in)
138
- end
139
-
140
- def token_expires_at
141
- Time.now + ChronicDuration.parse(token_expires_in)
142
- end
143
-
144
- def refresh_expires_at
145
- Time.now + ChronicDuration.parse(refresh_expires_in)
146
- end
147
-
148
- private
149
-
150
- def generate_credentials
151
- self.secret ||= SecureRandom.uuid
152
- self.client_type ||= "confidential"
153
- self.subject_type ||= "nickname"
154
- self.scopes ||= Masks.configuration.openid[:scopes] || []
155
- self.rsa_private_key ||= OpenSSL::PKey::RSA.generate(2048).to_pem
156
- self.sector_identifier ||=
157
- URI.parse(Masks.configuration.site_url).host
158
- self.code_expires_in ||= "5 minutes"
159
- self.token_expires_in ||= "1 day"
160
- self.refresh_expires_in ||= "1 week"
161
- end
162
-
163
- def generate_key
164
- return unless name
165
-
166
- key = name.parameterize
167
- count = self.class.where("key LIKE ?", "#{key}%").count
168
-
169
- self.key = count.positive? ? "#{key}-#{count + 1}" : key
170
- end
171
-
172
- def validate_expiries
173
- %i[
174
- code_expires_in
175
- token_expires_in
176
- refresh_expires_in
177
- ].each do |param|
178
- unless ChronicDuration.parse(send(param))
179
- errors.add(param, :invalid)
180
- end
181
- end
182
- end
183
- end
184
- end
185
- end
186
- end
@@ -1,43 +0,0 @@
1
- # frozen_string_literal: true
2
- module Masks
3
- module Rails
4
- module OpenID
5
- class IdToken < ApplicationRecord
6
- self.table_name = "openid_id_tokens"
7
-
8
- belongs_to :actor, class_name: Masks.configuration.models[:actor]
9
- belongs_to :openid_client,
10
- class_name: Masks.configuration.models[:openid_client]
11
-
12
- def to_response_object(with = {})
13
- subject =
14
- if openid_client.pairwise_subject?
15
- openid_client.subject_for(actor)
16
- else
17
- actor.actor_id
18
- end
19
-
20
- claims = {
21
- sub: subject,
22
- iss: openid_client.issuer,
23
- aud: openid_client.audience,
24
- exp: expires_at.to_i,
25
- iat: created_at.to_i,
26
- nonce:
27
- }
28
-
29
- id_token = OpenIDConnect::ResponseObject::IdToken.new(claims)
30
- id_token.code = with[:code] if with[:code]
31
- id_token.access_token = with[:access_token] if with[:access_token]
32
- id_token
33
- end
34
-
35
- def to_jwt(with = {})
36
- to_response_object(with).to_jwt(openid_client.private_key) do |jwt|
37
- jwt.kid = openid_client.kid
38
- end
39
- end
40
- end
41
- end
42
- end
43
- end
@@ -1,116 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Masks
4
- module Rails
5
- class Recovery < ApplicationRecord
6
- self.table_name = "recoveries"
7
-
8
- scope :recent,
9
- lambda {
10
- where(
11
- "created_at >= ?",
12
- Masks.configuration.lifetimes[:recovery_email]&.ago ||
13
- 1.hour.ago
14
- )
15
- }
16
- scope :expired,
17
- lambda {
18
- where(
19
- "created_at < ?",
20
- Masks.configuration.lifetimes[:recovery_email]&.ago ||
21
- 1.hour.ago
22
- )
23
- }
24
-
25
- belongs_to :actor, class_name: Masks.configuration.models[:actor]
26
-
27
- validates :token, presence: true, uniqueness: { scope: :actor_id }
28
- validates :contact, presence: true, if: :actor
29
- validate :validates_actor
30
-
31
- attribute :configuration
32
- attribute :session
33
- attribute :value
34
-
35
- after_initialize :generate_token
36
- after_initialize :load_actor, unless: :actor_id
37
-
38
- def to
39
- case contact
40
- when Email
41
- contact.email
42
- end
43
- end
44
-
45
- def notified?
46
- notified_at.present?
47
- end
48
-
49
- def reset_password!(password)
50
- return unless actor && persisted?
51
-
52
- actor.password = password
53
-
54
- return unless actor.valid?
55
-
56
- actor.save!
57
- destroy!
58
- end
59
-
60
- def notify!
61
- return if !valid? || notified?
62
-
63
- self.notified_at = Time.current
64
- save!
65
-
66
- case contact
67
- when Email
68
- ActorMailer.with(recovery: id).recover_credentials.deliver_later
69
- end
70
- end
71
-
72
- def contact
73
- return unless actor
74
-
75
- @contact ||=
76
- begin
77
- contact =
78
- if email
79
- actor.emails.find_by(verified: true, email:)
80
- elsif phone
81
- # TODO
82
- end
83
-
84
- contact ||= actor.emails.where(verified: true).first
85
- contact
86
- end
87
- end
88
-
89
- def to_param
90
- token
91
- end
92
-
93
- private
94
-
95
- def generate_token
96
- self.token ||= SecureRandom.hex(64)
97
- end
98
-
99
- def validates_actor
100
- return if !actor || actor.valid?
101
-
102
- actor.errors.full_messages.each { |error| errors.add(:base, error) }
103
- end
104
-
105
- def load_actor
106
- return unless value
107
-
108
- loaded =
109
- self.actor = configuration.find_actor(session, email:, nickname:)
110
-
111
- loaded.recoveries << self if loaded
112
- loaded
113
- end
114
- end
115
- end
116
- end
@@ -1,20 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Masks
4
- module Rails
5
- class Role < ApplicationRecord
6
- include Masks::Role
7
-
8
- self.table_name = "roles"
9
-
10
- belongs_to :actor, polymorphic: true, autosave: true
11
- belongs_to :record, polymorphic: true, autosave: true
12
-
13
- validates :type,
14
- presence: true,
15
- uniqueness: {
16
- scope: %i[actor_id actor_type record_id record_type]
17
- }
18
- end
19
- end
20
- end
@@ -1,15 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Masks
4
- module Rails
5
- class Scope < ApplicationRecord
6
- self.table_name = "scopes"
7
-
8
- validates :name, presence: true, uniqueness: { scope: :actor_id }
9
-
10
- belongs_to :actor,
11
- polymorphic: true,
12
- class_name: Masks.configuration.models[:actor]
13
- end
14
- end
15
- end