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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +16 -0
- data/LICENSE +21 -0
- data/README.md +215 -29
- data/app/controllers/masks/rails/base_controller.rb +13 -0
- data/app/controllers/masks/rails/handshakes_controller.rb +87 -0
- data/app/controllers/masks/rails/sessions_controller.rb +113 -0
- data/app/views/layouts/masks/rails/plain.html.erb +47 -0
- data/app/views/masks/rails/handshakes/refused.html.erb +12 -0
- data/app/views/masks/rails/handshakes/show.html.erb +40 -0
- data/config/routes.rb +10 -82
- data/lib/generators/masks/install/install_generator.rb +35 -22
- data/lib/generators/masks/install/templates/masks.rb.tt +38 -0
- data/lib/masks/client/claims.rb +103 -0
- data/lib/masks/client/errors.rb +52 -0
- data/lib/masks/client/handshake.rb +104 -0
- data/lib/masks/client/http.rb +81 -0
- data/lib/masks/client/introspection.rb +29 -0
- data/lib/masks/client/issuer.rb +76 -0
- data/lib/masks/client/pkce.rb +27 -0
- data/lib/masks/client/rack.rb +62 -0
- data/lib/masks/client/registration.rb +91 -0
- data/lib/masks/client/registry.rb +25 -0
- data/lib/masks/client/resource.rb +92 -0
- data/lib/masks/client/session.rb +146 -0
- data/lib/masks/client/stores.rb +40 -0
- data/lib/masks/client/tokens.rb +70 -0
- data/lib/masks/client/tracker.rb +122 -0
- data/lib/masks/client/verifier.rb +42 -0
- data/lib/masks/client.rb +51 -0
- data/lib/masks/rails/authentication.rb +217 -0
- data/lib/masks/rails/configurable.rb +11 -0
- data/lib/masks/rails/configuration.rb +172 -0
- data/lib/masks/rails/credentials.rb +60 -0
- data/lib/masks/rails/engine.rb +20 -0
- data/lib/masks/rails/protected_resource.rb +51 -0
- data/lib/masks/rails.rb +10 -0
- data/lib/masks/version.rb +1 -3
- data/lib/masks.rb +3 -183
- metadata +47 -416
- data/MIT-LICENSE +0 -20
- data/Rakefile +0 -11
- data/app/assets/builds/masks/application.css +0 -1
- data/app/assets/builds/masks/application.js +0 -8549
- data/app/assets/builds/masks/application.js.map +0 -7
- data/app/assets/images/masks.png +0 -0
- data/app/assets/javascripts/application.js +0 -2
- data/app/assets/javascripts/controllers/application.js +0 -9
- data/app/assets/javascripts/controllers/emails_controller.js +0 -28
- data/app/assets/javascripts/controllers/index.js +0 -21
- data/app/assets/javascripts/controllers/keys_controller.js +0 -20
- data/app/assets/javascripts/controllers/recover_controller.js +0 -21
- data/app/assets/javascripts/controllers/recover_password_controller.js +0 -21
- data/app/assets/javascripts/controllers/session_controller.js +0 -94
- data/app/assets/javascripts/controllers/table_controller.js +0 -15
- data/app/assets/manifest.js +0 -2
- data/app/assets/masks_manifest.js +0 -2
- data/app/assets/stylesheets/application.css +0 -34
- data/app/controllers/concerns/masks/controller.rb +0 -114
- data/app/controllers/masks/actors_controller.rb +0 -15
- data/app/controllers/masks/application_controller.rb +0 -35
- data/app/controllers/masks/backup_codes_controller.rb +0 -34
- data/app/controllers/masks/debug_controller.rb +0 -9
- data/app/controllers/masks/devices_controller.rb +0 -20
- data/app/controllers/masks/emails_controller.rb +0 -60
- data/app/controllers/masks/error_controller.rb +0 -14
- data/app/controllers/masks/keys_controller.rb +0 -45
- data/app/controllers/masks/manage/actors_controller.rb +0 -83
- data/app/controllers/masks/manage/base_controller.rb +0 -20
- data/app/controllers/masks/manage/clients_controller.rb +0 -84
- data/app/controllers/masks/manage/dashboard_controller.rb +0 -15
- data/app/controllers/masks/manage/devices_controller.rb +0 -19
- data/app/controllers/masks/one_time_code_controller.rb +0 -49
- data/app/controllers/masks/openid/authorizations_controller.rb +0 -45
- data/app/controllers/masks/openid/discoveries_controller.rb +0 -55
- data/app/controllers/masks/openid/tokens_controller.rb +0 -45
- data/app/controllers/masks/openid/userinfo_controller.rb +0 -28
- data/app/controllers/masks/passwords_controller.rb +0 -33
- data/app/controllers/masks/recoveries_controller.rb +0 -43
- data/app/controllers/masks/sessions_controller.rb +0 -53
- data/app/helpers/masks/application_helper.rb +0 -49
- data/app/jobs/masks/application_job.rb +0 -7
- data/app/jobs/masks/expire_actors_job.rb +0 -15
- data/app/jobs/masks/expire_recoveries_job.rb +0 -15
- data/app/mailers/masks/actor_mailer.rb +0 -22
- data/app/mailers/masks/application_mailer.rb +0 -15
- data/app/models/concerns/masks/access.rb +0 -162
- data/app/models/concerns/masks/actor.rb +0 -132
- data/app/models/concerns/masks/adapter.rb +0 -68
- data/app/models/concerns/masks/role.rb +0 -9
- data/app/models/concerns/masks/scoped.rb +0 -54
- data/app/models/masks/access/actor_password.rb +0 -21
- data/app/models/masks/access/actor_scopes.rb +0 -18
- data/app/models/masks/access/actor_signup.rb +0 -21
- data/app/models/masks/actors/anonymous.rb +0 -40
- data/app/models/masks/actors/system.rb +0 -24
- data/app/models/masks/adapters/active_record.rb +0 -85
- data/app/models/masks/application_model.rb +0 -15
- data/app/models/masks/application_record.rb +0 -8
- data/app/models/masks/check.rb +0 -192
- data/app/models/masks/credential.rb +0 -166
- data/app/models/masks/credentials/access_token.rb +0 -60
- data/app/models/masks/credentials/backup_code.rb +0 -30
- data/app/models/masks/credentials/device.rb +0 -59
- data/app/models/masks/credentials/email.rb +0 -48
- data/app/models/masks/credentials/factor2.rb +0 -71
- data/app/models/masks/credentials/key.rb +0 -38
- data/app/models/masks/credentials/last_login.rb +0 -12
- data/app/models/masks/credentials/masquerade.rb +0 -32
- data/app/models/masks/credentials/nickname.rb +0 -63
- data/app/models/masks/credentials/one_time_code.rb +0 -34
- data/app/models/masks/credentials/password.rb +0 -28
- data/app/models/masks/credentials/recovery.rb +0 -71
- data/app/models/masks/credentials/return_to.rb +0 -27
- data/app/models/masks/credentials/session.rb +0 -67
- data/app/models/masks/device.rb +0 -30
- data/app/models/masks/error.rb +0 -51
- data/app/models/masks/event.rb +0 -14
- data/app/models/masks/mask.rb +0 -266
- data/app/models/masks/openid/authorization.rb +0 -116
- data/app/models/masks/openid/token.rb +0 -56
- data/app/models/masks/rails/actor.rb +0 -212
- data/app/models/masks/rails/actor_role.rb +0 -12
- data/app/models/masks/rails/device.rb +0 -47
- data/app/models/masks/rails/email.rb +0 -96
- data/app/models/masks/rails/key.rb +0 -61
- data/app/models/masks/rails/openid/access_token.rb +0 -55
- data/app/models/masks/rails/openid/authorization.rb +0 -45
- data/app/models/masks/rails/openid/client.rb +0 -186
- data/app/models/masks/rails/openid/id_token.rb +0 -43
- data/app/models/masks/rails/recovery.rb +0 -116
- data/app/models/masks/rails/role.rb +0 -20
- data/app/models/masks/rails/scope.rb +0 -15
- data/app/models/masks/session.rb +0 -447
- data/app/models/masks/sessions/access.rb +0 -27
- data/app/models/masks/sessions/inline.rb +0 -16
- data/app/models/masks/sessions/request.rb +0 -42
- data/app/resources/masks/actor_resource.rb +0 -9
- data/app/resources/masks/session_resource.rb +0 -15
- data/app/views/layouts/masks/application.html.erb +0 -17
- data/app/views/layouts/masks/mailer.html.erb +0 -17
- data/app/views/layouts/masks/mailer.text.erb +0 -1
- data/app/views/layouts/masks/manage.html.erb +0 -42
- data/app/views/masks/actor_mailer/recover_credentials.html.erb +0 -32
- data/app/views/masks/actor_mailer/recover_credentials.text.erb +0 -1
- data/app/views/masks/actor_mailer/verify_email.html.erb +0 -33
- data/app/views/masks/actor_mailer/verify_email.text.erb +0 -8
- data/app/views/masks/actors/current.html.erb +0 -145
- data/app/views/masks/application/_header.html.erb +0 -30
- data/app/views/masks/backup_codes/new.html.erb +0 -117
- data/app/views/masks/emails/new.html.erb +0 -109
- data/app/views/masks/emails/verify.html.erb +0 -51
- data/app/views/masks/keys/new.html.erb +0 -127
- data/app/views/masks/manage/actors/index.html.erb +0 -104
- data/app/views/masks/manage/actors/show.html.erb +0 -172
- data/app/views/masks/manage/clients/index.html.erb +0 -102
- data/app/views/masks/manage/clients/show.html.erb +0 -156
- data/app/views/masks/manage/dashboard/index.html.erb +0 -10
- data/app/views/masks/manage/devices/index.html.erb +0 -47
- data/app/views/masks/one_time_code/new.html.erb +0 -167
- data/app/views/masks/openid/authorizations/error.html.erb +0 -23
- data/app/views/masks/openid/authorizations/new.html.erb +0 -46
- data/app/views/masks/passwords/edit.html.erb +0 -71
- data/app/views/masks/recoveries/new.html.erb +0 -69
- data/app/views/masks/recoveries/password.html.erb +0 -63
- data/app/views/masks/sessions/new.html.erb +0 -152
- data/config/brakeman.ignore +0 -28
- data/config/initializers/inflections.rb +0 -5
- data/config/locales/en.yml +0 -307
- data/db/migrate/20231205173845_create_actors.rb +0 -94
- data/db/migrate/20240329182422_support_openid.rb +0 -64
- data/lib/generators/masks/install/USAGE +0 -8
- data/lib/generators/masks/install/templates/initializer.rb +0 -5
- data/lib/generators/masks/install/templates/masks.json +0 -9
- data/lib/masks/configuration.rb +0 -249
- data/lib/masks/engine.rb +0 -25
- data/lib/masks/middleware.rb +0 -70
- data/lib/tasks/masks_tasks.rake +0 -72
- data/masks.json +0 -315
|
@@ -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,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
|