rodauth-model 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.
- checksums.yaml +7 -0
- data/CHANGELOG.md +5 -0
- data/LICENSE.txt +21 -0
- data/README.md +202 -0
- data/lib/rodauth/model/active_record.rb +91 -0
- data/lib/rodauth/model/associations.rb +61 -0
- data/lib/rodauth/model.rb +60 -0
- data/lib/rodauth-model.rb +3 -0
- data/rodauth-model.gemspec +29 -0
- metadata +166 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 7ea8768862eb1ba1bf2bdf1bb93872c0167230bf8c139ca49db5b17927288797
|
4
|
+
data.tar.gz: fe85b970b503ecd33a9c074d1b8763616e65fac5e88fd0fbbd49d2b986ae29ea
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 4b3f777be5c15eadacb69e074a4bf7b9aacad161e3b6c98f4c2f7ac0a3712af07259e82e62b339e18539522d98694d5d38d95318a11b10cac43c3cf042e87f0e
|
7
|
+
data.tar.gz: 7788e39bd9de5138773a90c5cac2babdef39da6b9a2a557a37af902c4b1bc851ec26e7e09dd6c6a62d799c3b39198750c39a24560025c2acb7e9fb0223bb4379
|
data/CHANGELOG.md
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2022 Janko Marohnić
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
13
|
+
all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
+
THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,202 @@
|
|
1
|
+
# rodauth-model
|
2
|
+
|
3
|
+
Extension for [Rodauth] providing a mixin for the account model that defines password attribute and associations based on enabled authentication features. At the moment only Active Record is supported.
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
```sh
|
8
|
+
$ bundle add rodauth-model
|
9
|
+
```
|
10
|
+
|
11
|
+
## Usage
|
12
|
+
|
13
|
+
Assuming with have a `RodauthApp` Roda subclass with Rodauth configured, we can build the mixin from a Rodauth class, and include it into the account model:
|
14
|
+
|
15
|
+
```rb
|
16
|
+
require "rodauth/model" # require before enabling any authentication features
|
17
|
+
|
18
|
+
class RodauthApp < Roda
|
19
|
+
plugin :rodauth do
|
20
|
+
# ...
|
21
|
+
end
|
22
|
+
end
|
23
|
+
```
|
24
|
+
```rb
|
25
|
+
class Account < ActiveRecord::Base
|
26
|
+
include Rodauth::Model(RodauthApp.rodauth)
|
27
|
+
end
|
28
|
+
```
|
29
|
+
|
30
|
+
If you have multiple Rodauth configurations, pass the one for which you want associations to be defined.
|
31
|
+
|
32
|
+
```rb
|
33
|
+
class Account < ActiveRecord::Base
|
34
|
+
include Rodauth::Model(RodauthApp.rodauth(:admin))
|
35
|
+
end
|
36
|
+
```
|
37
|
+
|
38
|
+
### Password attribute
|
39
|
+
|
40
|
+
Regardless of whether you're storing the password hash in a column in the accounts table, or in a separate table, the `#password` attribute can be used to set or clear the password hash.
|
41
|
+
|
42
|
+
```rb
|
43
|
+
account = Account.create!(email: "user@example.com", password: "secret")
|
44
|
+
|
45
|
+
# when password hash is stored in a column on the accounts table
|
46
|
+
account.password_hash #=> "$2a$12$k/Ub1I2iomi84RacqY89Hu4.M0vK7klRnRtzorDyvOkVI.hKhkNw."
|
47
|
+
|
48
|
+
# when password hash is stored in a separate table
|
49
|
+
account.password_hash #=> #<Account::PasswordHash...> (record from `account_password_hashes` table)
|
50
|
+
account.password_hash.password_hash #=> "$2a$12$k/Ub1..." (inaccessible when using database authentication functions)
|
51
|
+
|
52
|
+
account.password = nil # clears password hash
|
53
|
+
account.password_hash #=> nil
|
54
|
+
```
|
55
|
+
|
56
|
+
Note that the password attribute doesn't come with validations, making it unsuitable for forms. It was primarily intended to allow easily creating accounts in development console and in tests.
|
57
|
+
|
58
|
+
### Associations
|
59
|
+
|
60
|
+
The mixin defines associations for Rodauth tables associated to the accounts table:
|
61
|
+
|
62
|
+
```rb
|
63
|
+
account.remember_key #=> #<Account::RememberKey> (record from `account_remember_keys` table)
|
64
|
+
account.active_session_keys #=> [#<Account::ActiveSessionKey>,...] (records from `account_active_session_keys` table)
|
65
|
+
```
|
66
|
+
|
67
|
+
You can also reference the associated models directly:
|
68
|
+
|
69
|
+
```rb
|
70
|
+
# model referencing the `account_authentication_audit_logs` table
|
71
|
+
Account::AuthenticationAuditLog.where(message: "login").group(:account_id)
|
72
|
+
```
|
73
|
+
|
74
|
+
The associated models define the inverse `belongs_to :account` association:
|
75
|
+
|
76
|
+
```rb
|
77
|
+
Account::ActiveSessionKey.includes(:account).map(&:account)
|
78
|
+
```
|
79
|
+
|
80
|
+
### Association options
|
81
|
+
|
82
|
+
By default, all associations except for audit logs have `dependent: :delete` set, to allow for easy deletion of account records in the console. You can use `:association_options` to modify global or per-association options:
|
83
|
+
|
84
|
+
```rb
|
85
|
+
# don't auto-delete associations when account model is deleted
|
86
|
+
Rodauth::Model(RodauthApp.rodauth, association_options: { dependent: nil })
|
87
|
+
|
88
|
+
# require authentication audit logs to be eager loaded before retrieval
|
89
|
+
Rodauth::Model(RodauthApp.rodauth, association_options: -> (name) {
|
90
|
+
{ strict_loading: true } if name == :authentication_audit_logs
|
91
|
+
})
|
92
|
+
```
|
93
|
+
|
94
|
+
## Association reference
|
95
|
+
|
96
|
+
Below is a list of all associations defined depending on the features loaded:
|
97
|
+
|
98
|
+
| Feature | Association | Type | Model | Table (default) |
|
99
|
+
| :------ | :---------- | :--- | :---- | :---- |
|
100
|
+
| account_expiration | `:activity_time` | `has_one` | `ActivityTime` | `account_activity_times` |
|
101
|
+
| active_sessions | `:active_session_keys` | `has_many` | `ActiveSessionKey` | `account_active_session_keys` |
|
102
|
+
| audit_logging | `:authentication_audit_logs` | `has_many` | `AuthenticationAuditLog` | `account_authentication_audit_logs` |
|
103
|
+
| disallow_password_reuse | `:previous_password_hashes` | `has_many` | `PreviousPasswordHash` | `account_previous_password_hashes` |
|
104
|
+
| email_auth | `:email_auth_key` | `has_one` | `EmailAuthKey` | `account_email_auth_keys` |
|
105
|
+
| jwt_refresh | `:jwt_refresh_keys` | `has_many` | `JwtRefreshKey` | `account_jwt_refresh_keys` |
|
106
|
+
| lockout | `:lockout` | `has_one` | `Lockout` | `account_lockouts` |
|
107
|
+
| lockout | `:login_failure` | `has_one` | `LoginFailure` | `account_login_failures` |
|
108
|
+
| otp | `:otp_key` | `has_one` | `OtpKey` | `account_otp_keys` |
|
109
|
+
| password_expiration | `:password_change_time` | `has_one` | `PasswordChangeTime` | `account_password_change_times` |
|
110
|
+
| recovery_codes | `:recovery_codes` | `has_many` | `RecoveryCode` | `account_recovery_codes` |
|
111
|
+
| remember | `:remember_key` | `has_one` | `RememberKey` | `account_remember_keys` |
|
112
|
+
| reset_password | `:password_reset_key` | `has_one` | `PasswordResetKey` | `account_password_reset_keys` |
|
113
|
+
| single_session | `:session_key` | `has_one` | `SessionKey` | `account_session_keys` |
|
114
|
+
| sms_codes | `:sms_code` | `has_one` | `SmsCode` | `account_sms_codes` |
|
115
|
+
| verify_account | `:verification_key` | `has_one` | `VerificationKey` | `account_verification_keys` |
|
116
|
+
| verify_login_change | `:login_change_key` | `has_one` | `LoginChangeKey` | `account_login_change_keys` |
|
117
|
+
| webauthn | `:webauthn_keys` | `has_many` | `WebauthnKey` | `account_webauthn_keys` |
|
118
|
+
| webauthn | `:webauthn_user_id` | `has_one` | `WebauthnUserId` | `account_webauthn_user_ids` |
|
119
|
+
|
120
|
+
Note that some Rodauth tables use composite primary keys, which Active Record doesn't support out of the box. For associations to work properly, you might need to add the [composite_primary_keys] gem to your Gemfile.
|
121
|
+
|
122
|
+
## Extending associations
|
123
|
+
|
124
|
+
It's possible to register custom associations for an external feature, which the model mixin would pick up and automatically define the association on the model if the feature is enabled.
|
125
|
+
|
126
|
+
```rb
|
127
|
+
# lib/rodauth/features/foo.rb
|
128
|
+
module Rodauth
|
129
|
+
Feature.define(:foo, :Foo) do
|
130
|
+
auth_value_method :foo_table, :account_foos
|
131
|
+
auth_value_method :foo_id_column, :id
|
132
|
+
# ...
|
133
|
+
end
|
134
|
+
|
135
|
+
if defined?(Model)
|
136
|
+
Model.register_association(:foo) do
|
137
|
+
{ name: :foo, type: :one, table: foo_table, key: foo_id_column }
|
138
|
+
end
|
139
|
+
end
|
140
|
+
end
|
141
|
+
```
|
142
|
+
|
143
|
+
The `Rodauth::Model.register_association` method receives the feature name and a block, which is evaluted in the context of a Rodauth instance and should return the association definition with the following items:
|
144
|
+
|
145
|
+
* `:name` – association name
|
146
|
+
* `:type` – relationship type (`:one` for one-to-one, `:many` for one-to-many)
|
147
|
+
* `:table` – associated table name
|
148
|
+
* `:key` – foreign key on the associated table
|
149
|
+
|
150
|
+
It's possible to register multiple associations for the same Rodauth feature.
|
151
|
+
|
152
|
+
## Examples
|
153
|
+
|
154
|
+
### Checking whether account has multifactor authentication enabled
|
155
|
+
|
156
|
+
```rb
|
157
|
+
class Account < ActiveRecord::Base
|
158
|
+
include Rodauth::Model(RodauthApp.rodauth)
|
159
|
+
|
160
|
+
def mfa_enabled?
|
161
|
+
otp_key || (sms_code && sms_code.num_failures.nil?) || recovery_codes.any?
|
162
|
+
end
|
163
|
+
end
|
164
|
+
```
|
165
|
+
|
166
|
+
### Retrieving all accounts with multifactor authentication enabled
|
167
|
+
|
168
|
+
```rb
|
169
|
+
class Account < ActiveRecord::Base
|
170
|
+
include Rodauth::Model(RodauthApp.rodauth)
|
171
|
+
|
172
|
+
scope :otp_setup, -> { where(otp_key: OtpKey.all) }
|
173
|
+
scope :sms_codes_setup, -> { where(sms_code: SmsCode.where(num_failures: nil)) }
|
174
|
+
scope :recovery_codes_setup, -> { where(recovery_codes: RecoveryCode.all) }
|
175
|
+
scope :mfa_enabled, -> { merge(otp_setup.or(sms_codes_setup).or(recovery_codes_setup)) }
|
176
|
+
end
|
177
|
+
```
|
178
|
+
|
179
|
+
## Future plans
|
180
|
+
|
181
|
+
### Sequel support
|
182
|
+
|
183
|
+
Currently on Active Record models are supported, but I would like support Sequel models in the near future as well.
|
184
|
+
|
185
|
+
### Joined associations
|
186
|
+
|
187
|
+
It's possible to have multiple Rodauth configurations that operate on the same tables, but it's currently possible to define associations just for a single configuration. I would like to support grabbing associations from multiple associations.
|
188
|
+
|
189
|
+
## Contributing
|
190
|
+
|
191
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/janko/rodauth-model. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [code of conduct](https://github.com/janko/rodauth-model/blob/main/CODE_OF_CONDUCT.md).
|
192
|
+
|
193
|
+
## License
|
194
|
+
|
195
|
+
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
196
|
+
|
197
|
+
## Code of Conduct
|
198
|
+
|
199
|
+
Everyone interacting in the Rodauth::Model project's codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/janko/rodauth-model/blob/main/CODE_OF_CONDUCT.md).
|
200
|
+
|
201
|
+
[Rodauth]: https://rodauth.jeremyevans.net
|
202
|
+
[composite_primary_keys]: https://github.com/composite-primary-keys/composite_primary_keys
|
@@ -0,0 +1,91 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "rodauth/model/associations"
|
4
|
+
|
5
|
+
module Rodauth
|
6
|
+
class Model
|
7
|
+
module ActiveRecord
|
8
|
+
ASSOCIATION_TYPES = { one: :has_one, many: :has_many }
|
9
|
+
|
10
|
+
private
|
11
|
+
|
12
|
+
def define_methods(model)
|
13
|
+
rodauth = @auth_class.allocate.freeze
|
14
|
+
|
15
|
+
attr_reader :password
|
16
|
+
|
17
|
+
define_method(:password=) do |password|
|
18
|
+
@password = password
|
19
|
+
password_hash = rodauth.send(:password_hash, password) if password
|
20
|
+
set_password_hash(password_hash)
|
21
|
+
end
|
22
|
+
|
23
|
+
define_method(:set_password_hash) do |password_hash|
|
24
|
+
if rodauth.account_password_hash_column
|
25
|
+
public_send(:"#{rodauth.account_password_hash_column}=", password_hash)
|
26
|
+
else
|
27
|
+
if password_hash
|
28
|
+
record = self.password_hash || build_password_hash
|
29
|
+
record.public_send(:"#{rodauth.password_hash_column}=", password_hash)
|
30
|
+
else
|
31
|
+
self.password_hash&.mark_for_destruction
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def define_associations(model)
|
38
|
+
define_password_hash_association(model) unless rodauth.account_password_hash_column
|
39
|
+
|
40
|
+
feature_associations.each do |association|
|
41
|
+
association[:type] = ASSOCIATION_TYPES.fetch(association[:type])
|
42
|
+
association[:foreign_key] = association.delete(:key)
|
43
|
+
|
44
|
+
define_association(model, **association)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def define_password_hash_association(model)
|
49
|
+
password_hash_id_column = rodauth.password_hash_id_column
|
50
|
+
scope = -> { select(password_hash_id_column) } if rodauth.send(:use_database_authentication_functions?)
|
51
|
+
|
52
|
+
define_association model,
|
53
|
+
type: :has_one,
|
54
|
+
name: :password_hash,
|
55
|
+
table: rodauth.password_hash_table,
|
56
|
+
foreign_key: password_hash_id_column,
|
57
|
+
scope: scope,
|
58
|
+
autosave: true
|
59
|
+
end
|
60
|
+
|
61
|
+
def define_association(model, type:, name:, table:, foreign_key:, scope: nil, **options)
|
62
|
+
associated_model = Class.new(model.superclass)
|
63
|
+
associated_model.table_name = table
|
64
|
+
associated_model.belongs_to :account,
|
65
|
+
class_name: model.name,
|
66
|
+
foreign_key: foreign_key,
|
67
|
+
inverse_of: name
|
68
|
+
|
69
|
+
model.const_set(name.to_s.singularize.camelize, associated_model)
|
70
|
+
|
71
|
+
unless name == :authentication_audit_logs
|
72
|
+
dependent = type == :has_many ? :delete_all : :delete
|
73
|
+
end
|
74
|
+
|
75
|
+
model.public_send type, name, scope,
|
76
|
+
class_name: associated_model.name,
|
77
|
+
foreign_key: foreign_key,
|
78
|
+
dependent: dependent,
|
79
|
+
inverse_of: :account,
|
80
|
+
**options,
|
81
|
+
**association_options(name)
|
82
|
+
end
|
83
|
+
|
84
|
+
def association_options(name)
|
85
|
+
options = @association_options
|
86
|
+
options = options.call(name) if options.respond_to?(:call)
|
87
|
+
options || {}
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Rodauth
|
4
|
+
Model.register_association(:remember) do
|
5
|
+
{ name: :remember_key, type: :one, table: remember_table, key: remember_id_column }
|
6
|
+
end
|
7
|
+
Model.register_association(:verify_account) do
|
8
|
+
{ name: :verification_key, type: :one, table: verify_account_table, key: verify_account_id_column }
|
9
|
+
end
|
10
|
+
Model.register_association(:reset_password) do
|
11
|
+
{ name: :password_reset_key, type: :one, table: reset_password_table, key: reset_password_id_column }
|
12
|
+
end
|
13
|
+
Model.register_association(:verify_login_change) do
|
14
|
+
{ name: :login_change_key, type: :one, table: verify_login_change_table, key: verify_login_change_id_column }
|
15
|
+
end
|
16
|
+
Model.register_association(:lockout) do
|
17
|
+
{ name: :lockout, type: :one, table: account_lockouts_table, key: account_lockouts_id_column }
|
18
|
+
end
|
19
|
+
Model.register_association(:lockout) do
|
20
|
+
{ name: :login_failure, type: :one, table: account_login_failures_table, key: account_login_failures_id_column }
|
21
|
+
end
|
22
|
+
Model.register_association(:email_auth) do
|
23
|
+
{ name: :email_auth_key, type: :one, table: email_auth_table, key: email_auth_id_column }
|
24
|
+
end
|
25
|
+
Model.register_association(:account_expiration) do
|
26
|
+
{ name: :activity_time, type: :one, table: account_activity_table, key: account_activity_id_column }
|
27
|
+
end
|
28
|
+
Model.register_association(:active_sessions) do
|
29
|
+
{ name: :active_session_keys, type: :many, table: active_sessions_table, key: active_sessions_account_id_column }
|
30
|
+
end
|
31
|
+
Model.register_association(:audit_logging) do
|
32
|
+
{ name: :authentication_audit_logs, type: :many, table: audit_logging_table, key: audit_logging_account_id_column }
|
33
|
+
end
|
34
|
+
Model.register_association(:disallow_password_reuse) do
|
35
|
+
{ name: :previous_password_hashes, type: :many, table: previous_password_hash_table, key: previous_password_account_id_column }
|
36
|
+
end
|
37
|
+
Model.register_association(:jwt_refresh) do
|
38
|
+
{ name: :jwt_refresh_keys, type: :many, table: jwt_refresh_token_table, key: jwt_refresh_token_account_id_column }
|
39
|
+
end
|
40
|
+
Model.register_association(:password_expiration) do
|
41
|
+
{ name: :password_change_time, type: :one, table: password_expiration_table, key: password_expiration_id_column }
|
42
|
+
end
|
43
|
+
Model.register_association(:single_session) do
|
44
|
+
{ name: :session_key, type: :one, table: single_session_table, key: single_session_id_column }
|
45
|
+
end
|
46
|
+
Model.register_association(:otp) do
|
47
|
+
{ name: :otp_key, type: :one, table: otp_keys_table, key: otp_keys_id_column }
|
48
|
+
end
|
49
|
+
Model.register_association(:sms_codes) do
|
50
|
+
{ name: :sms_code, type: :one, table: sms_codes_table, key: sms_id_column }
|
51
|
+
end
|
52
|
+
Model.register_association(:recovery_codes) do
|
53
|
+
{ name: :recovery_codes, type: :many, table: recovery_codes_table, key: recovery_codes_id_column }
|
54
|
+
end
|
55
|
+
Model.register_association(:webauthn) do
|
56
|
+
{ name: :webauthn_user_id, type: :one, table: webauthn_user_ids_table, key: webauthn_user_ids_account_id_column }
|
57
|
+
end
|
58
|
+
Model.register_association(:webauthn) do
|
59
|
+
{ name: :webauthn_keys, type: :many, table: webauthn_keys_table, key: webauthn_keys_account_id_column }
|
60
|
+
end
|
61
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Rodauth
|
4
|
+
def self.Model(*args, **options)
|
5
|
+
Rodauth::Model.new(*args, **options)
|
6
|
+
end
|
7
|
+
|
8
|
+
class Model < Module
|
9
|
+
Error = Class.new(StandardError)
|
10
|
+
|
11
|
+
autoload :ActiveRecord, "rodauth/model/active_record"
|
12
|
+
|
13
|
+
def self.associations
|
14
|
+
@associations ||= {}
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.register_association(feature, &block)
|
18
|
+
associations[feature] ||= []
|
19
|
+
associations[feature] << block
|
20
|
+
end
|
21
|
+
|
22
|
+
def initialize(auth_class, association_options: {})
|
23
|
+
@auth_class = auth_class
|
24
|
+
@association_options = association_options
|
25
|
+
end
|
26
|
+
|
27
|
+
def included(model)
|
28
|
+
if defined?(::ActiveRecord::Base) && model < ::ActiveRecord::Base
|
29
|
+
extend Rodauth::Model::ActiveRecord
|
30
|
+
elsif defined?(::Sequel::Model) && model < ::Sequel::Model
|
31
|
+
raise Error, "Sequel models are not yet supported"
|
32
|
+
else
|
33
|
+
raise Error, "must be an Active Record model"
|
34
|
+
end
|
35
|
+
|
36
|
+
define_associations(model)
|
37
|
+
define_methods(model)
|
38
|
+
end
|
39
|
+
|
40
|
+
def inspect
|
41
|
+
"#<#{self.class}(#{@auth_class.inspect})>"
|
42
|
+
end
|
43
|
+
|
44
|
+
private
|
45
|
+
|
46
|
+
def feature_associations
|
47
|
+
self.class.associations
|
48
|
+
.values_at(*rodauth.features)
|
49
|
+
.compact
|
50
|
+
.flatten
|
51
|
+
.map { |block| rodauth.instance_exec(&block) }
|
52
|
+
end
|
53
|
+
|
54
|
+
def rodauth
|
55
|
+
@auth_class.allocate
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
require "rodauth/model/associations"
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
Gem::Specification.new do |spec|
|
4
|
+
spec.name = "rodauth-model"
|
5
|
+
spec.version = "0.1.0"
|
6
|
+
spec.authors = ["Janko Marohnić"]
|
7
|
+
spec.email = ["janko@hey.com"]
|
8
|
+
|
9
|
+
spec.description = "Provides model mixin for Active Record and Sequel that defines password attribute and associations based on Rodauth configuration."
|
10
|
+
spec.summary = spec.description
|
11
|
+
spec.homepage = "https://github.com/janko/rodauth-model"
|
12
|
+
spec.license = "MIT"
|
13
|
+
spec.required_ruby_version = ">= 2.3"
|
14
|
+
|
15
|
+
spec.metadata["source_code_uri"] = "https://github.com/janko/rodauth-model"
|
16
|
+
|
17
|
+
spec.files = Dir["README.md", "LICENSE.txt", "CHANGELOG.md", "lib/**/*", "*.gemspec"]
|
18
|
+
spec.require_paths = ["lib"]
|
19
|
+
|
20
|
+
spec.add_dependency "rodauth", "~> 2.0"
|
21
|
+
|
22
|
+
spec.add_development_dependency "minitest"
|
23
|
+
spec.add_development_dependency "minitest-hooks"
|
24
|
+
spec.add_development_dependency "bcrypt"
|
25
|
+
spec.add_development_dependency "jwt"
|
26
|
+
spec.add_development_dependency "rotp"
|
27
|
+
spec.add_development_dependency "rqrcode"
|
28
|
+
spec.add_development_dependency "webauthn" unless RUBY_ENGINE == "jruby"
|
29
|
+
end
|
metadata
ADDED
@@ -0,0 +1,166 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: rodauth-model
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Janko Marohnić
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2022-05-07 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: rodauth
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '2.0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '2.0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: minitest
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: minitest-hooks
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: bcrypt
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: jwt
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ">="
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ">="
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: rotp
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - ">="
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '0'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - ">="
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '0'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: rqrcode
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - ">="
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '0'
|
104
|
+
type: :development
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - ">="
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '0'
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: webauthn
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - ">="
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '0'
|
118
|
+
type: :development
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - ">="
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: '0'
|
125
|
+
description: Provides model mixin for Active Record and Sequel that defines password
|
126
|
+
attribute and associations based on Rodauth configuration.
|
127
|
+
email:
|
128
|
+
- janko@hey.com
|
129
|
+
executables: []
|
130
|
+
extensions: []
|
131
|
+
extra_rdoc_files: []
|
132
|
+
files:
|
133
|
+
- CHANGELOG.md
|
134
|
+
- LICENSE.txt
|
135
|
+
- README.md
|
136
|
+
- lib/rodauth-model.rb
|
137
|
+
- lib/rodauth/model.rb
|
138
|
+
- lib/rodauth/model/active_record.rb
|
139
|
+
- lib/rodauth/model/associations.rb
|
140
|
+
- rodauth-model.gemspec
|
141
|
+
homepage: https://github.com/janko/rodauth-model
|
142
|
+
licenses:
|
143
|
+
- MIT
|
144
|
+
metadata:
|
145
|
+
source_code_uri: https://github.com/janko/rodauth-model
|
146
|
+
post_install_message:
|
147
|
+
rdoc_options: []
|
148
|
+
require_paths:
|
149
|
+
- lib
|
150
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
151
|
+
requirements:
|
152
|
+
- - ">="
|
153
|
+
- !ruby/object:Gem::Version
|
154
|
+
version: '2.3'
|
155
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
156
|
+
requirements:
|
157
|
+
- - ">="
|
158
|
+
- !ruby/object:Gem::Version
|
159
|
+
version: '0'
|
160
|
+
requirements: []
|
161
|
+
rubygems_version: 3.3.3
|
162
|
+
signing_key:
|
163
|
+
specification_version: 4
|
164
|
+
summary: Provides model mixin for Active Record and Sequel that defines password attribute
|
165
|
+
and associations based on Rodauth configuration.
|
166
|
+
test_files: []
|