rodauth-rails 0.12.0 → 0.16.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 +36 -0
- data/README.md +304 -98
- data/lib/generators/rodauth/templates/app/lib/rodauth_app.rb +8 -4
- data/lib/generators/rodauth/templates/app/models/account.rb +1 -0
- data/lib/generators/rodauth/templates/app/views/rodauth/_email_auth_request_form.html.erb +1 -1
- data/lib/generators/rodauth/templates/app/views/rodauth/_field.html.erb +2 -2
- data/lib/generators/rodauth/templates/app/views/rodauth/_field_error.html.erb +2 -2
- data/lib/generators/rodauth/templates/app/views/rodauth/_global_logout_field.html.erb +1 -1
- data/lib/generators/rodauth/templates/app/views/rodauth/_login_confirm_field.html.erb +1 -1
- data/lib/generators/rodauth/templates/app/views/rodauth/_login_display.html.erb +1 -1
- data/lib/generators/rodauth/templates/app/views/rodauth/_login_field.html.erb +1 -1
- data/lib/generators/rodauth/templates/app/views/rodauth/_login_form.html.erb +3 -3
- data/lib/generators/rodauth/templates/app/views/rodauth/_login_form_footer.html.erb +2 -2
- data/lib/generators/rodauth/templates/app/views/rodauth/_login_form_header.html.erb +2 -2
- data/lib/generators/rodauth/templates/app/views/rodauth/_login_hidden_field.html.erb +1 -1
- data/lib/generators/rodauth/templates/app/views/rodauth/_new_password_field.html.erb +1 -1
- data/lib/generators/rodauth/templates/app/views/rodauth/_otp_auth_code_field.html.erb +1 -1
- data/lib/generators/rodauth/templates/app/views/rodauth/_password_confirm_field.html.erb +1 -1
- data/lib/generators/rodauth/templates/app/views/rodauth/_password_field.html.erb +1 -1
- data/lib/generators/rodauth/templates/app/views/rodauth/_recovery_code_field.html.erb +1 -1
- data/lib/generators/rodauth/templates/app/views/rodauth/_recovery_codes_form.html.erb +4 -4
- data/lib/generators/rodauth/templates/app/views/rodauth/_sms_code_field.html.erb +1 -1
- data/lib/generators/rodauth/templates/app/views/rodauth/_sms_phone_field.html.erb +1 -1
- data/lib/generators/rodauth/templates/app/views/rodauth/add_recovery_codes.html.erb +2 -2
- data/lib/generators/rodauth/templates/app/views/rodauth/change_login.html.erb +3 -3
- data/lib/generators/rodauth/templates/app/views/rodauth/change_password.html.erb +3 -3
- data/lib/generators/rodauth/templates/app/views/rodauth/close_account.html.erb +2 -2
- data/lib/generators/rodauth/templates/app/views/rodauth/confirm_password.html.erb +1 -1
- data/lib/generators/rodauth/templates/app/views/rodauth/create_account.html.erb +4 -4
- data/lib/generators/rodauth/templates/app/views/rodauth/email_auth.html.erb +1 -1
- data/lib/generators/rodauth/templates/app/views/rodauth/logout.html.erb +2 -2
- data/lib/generators/rodauth/templates/app/views/rodauth/multi_phase_login.html.erb +1 -1
- data/lib/generators/rodauth/templates/app/views/rodauth/otp_auth.html.erb +1 -1
- data/lib/generators/rodauth/templates/app/views/rodauth/otp_disable.html.erb +2 -2
- data/lib/generators/rodauth/templates/app/views/rodauth/otp_setup.html.erb +7 -7
- data/lib/generators/rodauth/templates/app/views/rodauth/recovery_auth.html.erb +1 -1
- data/lib/generators/rodauth/templates/app/views/rodauth/remember.html.erb +4 -4
- data/lib/generators/rodauth/templates/app/views/rodauth/reset_password.html.erb +2 -2
- data/lib/generators/rodauth/templates/app/views/rodauth/reset_password_request.html.erb +2 -2
- data/lib/generators/rodauth/templates/app/views/rodauth/sms_auth.html.erb +1 -1
- data/lib/generators/rodauth/templates/app/views/rodauth/sms_confirm.html.erb +1 -1
- data/lib/generators/rodauth/templates/app/views/rodauth/sms_disable.html.erb +2 -2
- data/lib/generators/rodauth/templates/app/views/rodauth/sms_request.html.erb +1 -1
- data/lib/generators/rodauth/templates/app/views/rodauth/sms_setup.html.erb +2 -2
- data/lib/generators/rodauth/templates/app/views/rodauth/two_factor_auth.html.erb +1 -1
- data/lib/generators/rodauth/templates/app/views/rodauth/two_factor_disable.html.erb +2 -2
- data/lib/generators/rodauth/templates/app/views/rodauth/two_factor_manage.html.erb +6 -6
- data/lib/generators/rodauth/templates/app/views/rodauth/unlock_account.html.erb +2 -2
- data/lib/generators/rodauth/templates/app/views/rodauth/unlock_account_request.html.erb +1 -1
- data/lib/generators/rodauth/templates/app/views/rodauth/verify_account.html.erb +3 -3
- data/lib/generators/rodauth/templates/app/views/rodauth/verify_account_resend.html.erb +2 -2
- data/lib/generators/rodauth/templates/app/views/rodauth/verify_login_change.html.erb +1 -1
- data/lib/generators/rodauth/templates/app/views/rodauth/webauthn_auth.html.erb +7 -7
- data/lib/generators/rodauth/templates/app/views/rodauth/webauthn_remove.html.erb +5 -5
- data/lib/generators/rodauth/templates/app/views/rodauth/webauthn_setup.html.erb +7 -7
- data/lib/generators/rodauth/views_generator.rb +29 -4
- data/lib/rodauth/rails/auth.rb +10 -13
- data/lib/rodauth/rails/controller_methods.rb +43 -1
- data/lib/rodauth/rails/feature/base.rb +8 -8
- data/lib/rodauth/rails/feature/callbacks.rb +6 -2
- data/lib/rodauth/rails/feature/internal_request.rb +50 -0
- data/lib/rodauth/rails/feature/render.rb +7 -0
- data/lib/rodauth/rails/feature.rb +2 -0
- data/lib/rodauth/rails/model/associations.rb +195 -0
- data/lib/rodauth/rails/model.rb +101 -0
- data/lib/rodauth/rails/tasks.rake +5 -5
- data/lib/rodauth/rails/version.rb +1 -1
- data/lib/rodauth/rails.rb +30 -13
- data/rodauth-rails.gemspec +4 -1
- metadata +50 -5
|
@@ -4,13 +4,55 @@ module Rodauth
|
|
|
4
4
|
def self.included(controller)
|
|
5
5
|
# ActionController::API doesn't have helper methods
|
|
6
6
|
if controller.respond_to?(:helper_method)
|
|
7
|
-
controller.helper_method :rodauth
|
|
7
|
+
controller.helper_method :rodauth, :current_account
|
|
8
8
|
end
|
|
9
9
|
end
|
|
10
10
|
|
|
11
11
|
def rodauth(name = nil)
|
|
12
12
|
request.env.fetch ["rodauth", *name].join(".")
|
|
13
13
|
end
|
|
14
|
+
|
|
15
|
+
def current_account(name = nil)
|
|
16
|
+
table = rodauth(name).accounts_table
|
|
17
|
+
model = table.to_s.classify.constantize
|
|
18
|
+
id = rodauth(name).session_value
|
|
19
|
+
|
|
20
|
+
@current_account ||= {}
|
|
21
|
+
@current_account[name] ||= fetch_account(model, id) do
|
|
22
|
+
rodauth(name).clear_session
|
|
23
|
+
rodauth(name).login_required
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
private
|
|
28
|
+
|
|
29
|
+
def fetch_account(model, id, ¬_found)
|
|
30
|
+
if defined?(ActiveRecord::Base) && model < ActiveRecord::Base
|
|
31
|
+
begin
|
|
32
|
+
model.find(id)
|
|
33
|
+
rescue ActiveRecord::RecordNotFound
|
|
34
|
+
not_found.call
|
|
35
|
+
end
|
|
36
|
+
elsif model < Sequel::Model
|
|
37
|
+
begin
|
|
38
|
+
model.with_pk!(id)
|
|
39
|
+
rescue Sequel::NoMatchingRow
|
|
40
|
+
not_found.call
|
|
41
|
+
end
|
|
42
|
+
else
|
|
43
|
+
fail Error, "unsupported model type: #{model}"
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def rodauth_response
|
|
48
|
+
res = catch(:halt) { return yield }
|
|
49
|
+
|
|
50
|
+
self.status = res[0]
|
|
51
|
+
self.headers.merge! res[1]
|
|
52
|
+
self.response_body = res[2]
|
|
53
|
+
|
|
54
|
+
res
|
|
55
|
+
end
|
|
14
56
|
end
|
|
15
57
|
end
|
|
16
58
|
end
|
|
@@ -22,6 +22,14 @@ module Rodauth
|
|
|
22
22
|
rails_controller_instance.instance_exec(&block)
|
|
23
23
|
end
|
|
24
24
|
|
|
25
|
+
def rails_controller
|
|
26
|
+
if only_json? && Rodauth::Rails.api_only?
|
|
27
|
+
ActionController::API
|
|
28
|
+
else
|
|
29
|
+
ActionController::Base
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
|
|
25
33
|
delegate :rails_routes, :rails_request, to: :scope
|
|
26
34
|
|
|
27
35
|
private
|
|
@@ -48,14 +56,6 @@ module Rodauth
|
|
|
48
56
|
def rails_api_controller?
|
|
49
57
|
defined?(ActionController::API) && rails_controller <= ActionController::API
|
|
50
58
|
end
|
|
51
|
-
|
|
52
|
-
def rails_controller
|
|
53
|
-
if only_json? && Rodauth::Rails.api_only?
|
|
54
|
-
ActionController::API
|
|
55
|
-
else
|
|
56
|
-
ActionController::Base
|
|
57
|
-
end
|
|
58
|
-
end
|
|
59
59
|
end
|
|
60
60
|
end
|
|
61
61
|
end
|
|
@@ -4,13 +4,17 @@ module Rodauth
|
|
|
4
4
|
module Callbacks
|
|
5
5
|
private
|
|
6
6
|
|
|
7
|
+
def _around_rodauth
|
|
8
|
+
rails_controller_around { super }
|
|
9
|
+
end
|
|
10
|
+
|
|
7
11
|
# Runs controller callbacks and rescue handlers around Rodauth actions.
|
|
8
|
-
def
|
|
12
|
+
def rails_controller_around
|
|
9
13
|
result = nil
|
|
10
14
|
|
|
11
15
|
rails_controller_rescue do
|
|
12
16
|
rails_controller_callbacks do
|
|
13
|
-
result = catch(:halt) {
|
|
17
|
+
result = catch(:halt) { yield }
|
|
14
18
|
end
|
|
15
19
|
end
|
|
16
20
|
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
module Rodauth
|
|
2
|
+
module Rails
|
|
3
|
+
module Feature
|
|
4
|
+
module InternalRequest
|
|
5
|
+
def post_configure
|
|
6
|
+
super
|
|
7
|
+
return unless internal_request?
|
|
8
|
+
|
|
9
|
+
self.class.define_singleton_method(:internal_request) do |route, opts = {}, &blk|
|
|
10
|
+
url_options = ::Rails.application.config.action_mailer.default_url_options || {}
|
|
11
|
+
|
|
12
|
+
scheme = url_options[:protocol]
|
|
13
|
+
port = url_options[:port]
|
|
14
|
+
port||= Rack::Request::DEFAULT_PORTS[scheme] if Rack.release < "2"
|
|
15
|
+
host = url_options[:host]
|
|
16
|
+
host_with_port = host && port ? "#{host}:#{port}" : host
|
|
17
|
+
|
|
18
|
+
env = {
|
|
19
|
+
"HTTP_HOST" => host_with_port,
|
|
20
|
+
"rack.url_scheme" => scheme,
|
|
21
|
+
"SERVER_NAME" => host,
|
|
22
|
+
"SERVER_PORT" => port,
|
|
23
|
+
}.compact
|
|
24
|
+
|
|
25
|
+
opts = opts.merge(env: env) { |k, v1, v2| v2.merge(v1) }
|
|
26
|
+
|
|
27
|
+
super(route, opts, &blk)
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
private
|
|
32
|
+
|
|
33
|
+
def rails_controller_around
|
|
34
|
+
return yield if internal_request?
|
|
35
|
+
super
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def rails_instrument_request
|
|
39
|
+
return yield if internal_request?
|
|
40
|
+
super
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def rails_instrument_redirection
|
|
44
|
+
return yield if internal_request?
|
|
45
|
+
super
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
end
|
|
@@ -35,6 +35,13 @@ module Rodauth
|
|
|
35
35
|
rescue ActionView::MissingTemplate
|
|
36
36
|
nil
|
|
37
37
|
end
|
|
38
|
+
|
|
39
|
+
# Only look up template formats that the current request is accepting.
|
|
40
|
+
def _rails_controller_instance
|
|
41
|
+
controller = super
|
|
42
|
+
controller.formats = rails_request.formats.map(&:ref).compact
|
|
43
|
+
controller
|
|
44
|
+
end
|
|
38
45
|
end
|
|
39
46
|
end
|
|
40
47
|
end
|
|
@@ -10,6 +10,7 @@ module Rodauth
|
|
|
10
10
|
require "rodauth/rails/feature/render"
|
|
11
11
|
require "rodauth/rails/feature/email"
|
|
12
12
|
require "rodauth/rails/feature/instrumentation"
|
|
13
|
+
require "rodauth/rails/feature/internal_request"
|
|
13
14
|
|
|
14
15
|
include Rodauth::Rails::Feature::Base
|
|
15
16
|
include Rodauth::Rails::Feature::Callbacks
|
|
@@ -17,5 +18,6 @@ module Rodauth
|
|
|
17
18
|
include Rodauth::Rails::Feature::Render
|
|
18
19
|
include Rodauth::Rails::Feature::Email
|
|
19
20
|
include Rodauth::Rails::Feature::Instrumentation
|
|
21
|
+
include Rodauth::Rails::Feature::InternalRequest
|
|
20
22
|
end
|
|
21
23
|
end
|
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
module Rodauth
|
|
2
|
+
module Rails
|
|
3
|
+
class Model
|
|
4
|
+
class Associations
|
|
5
|
+
attr_reader :rodauth
|
|
6
|
+
|
|
7
|
+
def self.call(rodauth)
|
|
8
|
+
new(rodauth).call
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def initialize(rodauth)
|
|
12
|
+
@rodauth = rodauth
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def call
|
|
16
|
+
rodauth.features
|
|
17
|
+
.select { |feature| respond_to?(feature, true) }
|
|
18
|
+
.flat_map { |feature| send(feature) }
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
private
|
|
22
|
+
|
|
23
|
+
def remember
|
|
24
|
+
{
|
|
25
|
+
name: :remember_key,
|
|
26
|
+
type: :has_one,
|
|
27
|
+
table: rodauth.remember_table,
|
|
28
|
+
foreign_key: rodauth.remember_id_column,
|
|
29
|
+
}
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def verify_account
|
|
33
|
+
{
|
|
34
|
+
name: :verification_key,
|
|
35
|
+
type: :has_one,
|
|
36
|
+
table: rodauth.verify_account_table,
|
|
37
|
+
foreign_key: rodauth.verify_account_id_column,
|
|
38
|
+
}
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def reset_password
|
|
42
|
+
{
|
|
43
|
+
name: :password_reset_key,
|
|
44
|
+
type: :has_one,
|
|
45
|
+
table: rodauth.reset_password_table,
|
|
46
|
+
foreign_key: rodauth.reset_password_id_column,
|
|
47
|
+
}
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def verify_login_change
|
|
51
|
+
{
|
|
52
|
+
name: :login_change_key,
|
|
53
|
+
type: :has_one,
|
|
54
|
+
table: rodauth.verify_login_change_table,
|
|
55
|
+
foreign_key: rodauth.verify_login_change_id_column,
|
|
56
|
+
}
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def lockout
|
|
60
|
+
[
|
|
61
|
+
{
|
|
62
|
+
name: :lockout,
|
|
63
|
+
type: :has_one,
|
|
64
|
+
table: rodauth.account_lockouts_table,
|
|
65
|
+
foreign_key: rodauth.account_lockouts_id_column,
|
|
66
|
+
},
|
|
67
|
+
{
|
|
68
|
+
name: :login_failure,
|
|
69
|
+
type: :has_one,
|
|
70
|
+
table: rodauth.account_login_failures_table,
|
|
71
|
+
foreign_key: rodauth.account_login_failures_id_column,
|
|
72
|
+
}
|
|
73
|
+
]
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def email_auth
|
|
77
|
+
{
|
|
78
|
+
name: :email_auth_key,
|
|
79
|
+
type: :has_one,
|
|
80
|
+
table: rodauth.email_auth_table,
|
|
81
|
+
foreign_key: rodauth.email_auth_id_column,
|
|
82
|
+
}
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
def account_expiration
|
|
86
|
+
{
|
|
87
|
+
name: :activity_time,
|
|
88
|
+
type: :has_one,
|
|
89
|
+
table: rodauth.account_activity_table,
|
|
90
|
+
foreign_key: rodauth.account_activity_id_column,
|
|
91
|
+
}
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
def active_sessions
|
|
95
|
+
{
|
|
96
|
+
name: :active_session_keys,
|
|
97
|
+
type: :has_many,
|
|
98
|
+
table: rodauth.active_sessions_table,
|
|
99
|
+
foreign_key: rodauth.active_sessions_account_id_column,
|
|
100
|
+
}
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
def audit_logging
|
|
104
|
+
{
|
|
105
|
+
name: :authentication_audit_logs,
|
|
106
|
+
type: :has_many,
|
|
107
|
+
table: rodauth.audit_logging_table,
|
|
108
|
+
foreign_key: rodauth.audit_logging_account_id_column,
|
|
109
|
+
dependent: nil,
|
|
110
|
+
}
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
def disallow_password_reuse
|
|
114
|
+
{
|
|
115
|
+
name: :previous_password_hashes,
|
|
116
|
+
type: :has_many,
|
|
117
|
+
table: rodauth.previous_password_hash_table,
|
|
118
|
+
foreign_key: rodauth.previous_password_account_id_column,
|
|
119
|
+
}
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
def jwt_refresh
|
|
123
|
+
{
|
|
124
|
+
name: :jwt_refresh_keys,
|
|
125
|
+
type: :has_many,
|
|
126
|
+
table: rodauth.jwt_refresh_token_table,
|
|
127
|
+
foreign_key: rodauth.jwt_refresh_token_account_id_column,
|
|
128
|
+
}
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
def password_expiration
|
|
132
|
+
{
|
|
133
|
+
name: :password_change_time,
|
|
134
|
+
type: :has_one,
|
|
135
|
+
table: rodauth.password_expiration_table,
|
|
136
|
+
foreign_key: rodauth.password_expiration_id_column,
|
|
137
|
+
}
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
def single_session
|
|
141
|
+
{
|
|
142
|
+
name: :session_key,
|
|
143
|
+
type: :has_one,
|
|
144
|
+
table: rodauth.single_session_table,
|
|
145
|
+
foreign_key: rodauth.single_session_id_column,
|
|
146
|
+
}
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
def otp
|
|
150
|
+
{
|
|
151
|
+
name: :otp_key,
|
|
152
|
+
type: :has_one,
|
|
153
|
+
table: rodauth.otp_keys_table,
|
|
154
|
+
foreign_key: rodauth.otp_keys_id_column,
|
|
155
|
+
}
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
def sms_codes
|
|
159
|
+
{
|
|
160
|
+
name: :sms_code,
|
|
161
|
+
type: :has_one,
|
|
162
|
+
table: rodauth.sms_codes_table,
|
|
163
|
+
foreign_key: rodauth.sms_id_column,
|
|
164
|
+
}
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
def recovery_codes
|
|
168
|
+
{
|
|
169
|
+
name: :recovery_codes,
|
|
170
|
+
type: :has_many,
|
|
171
|
+
table: rodauth.recovery_codes_table,
|
|
172
|
+
foreign_key: rodauth.recovery_codes_id_column,
|
|
173
|
+
}
|
|
174
|
+
end
|
|
175
|
+
|
|
176
|
+
def webauthn
|
|
177
|
+
[
|
|
178
|
+
{
|
|
179
|
+
name: :webauthn_user_id,
|
|
180
|
+
type: :has_one,
|
|
181
|
+
table: rodauth.webauthn_user_ids_table,
|
|
182
|
+
foreign_key: rodauth.webauthn_user_ids_account_id_column,
|
|
183
|
+
},
|
|
184
|
+
{
|
|
185
|
+
name: :webauthn_keys,
|
|
186
|
+
type: :has_many,
|
|
187
|
+
table: rodauth.webauthn_keys_table,
|
|
188
|
+
foreign_key: rodauth.webauthn_keys_account_id_column,
|
|
189
|
+
}
|
|
190
|
+
]
|
|
191
|
+
end
|
|
192
|
+
end
|
|
193
|
+
end
|
|
194
|
+
end
|
|
195
|
+
end
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
module Rodauth
|
|
2
|
+
module Rails
|
|
3
|
+
class Model < Module
|
|
4
|
+
require "rodauth/rails/model/associations"
|
|
5
|
+
|
|
6
|
+
def initialize(auth_class, association_options: {})
|
|
7
|
+
@auth_class = auth_class
|
|
8
|
+
@association_options = association_options
|
|
9
|
+
|
|
10
|
+
define_methods
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def included(model)
|
|
14
|
+
fail Rodauth::Rails::Error, "must be an Active Record model" unless model < ActiveRecord::Base
|
|
15
|
+
|
|
16
|
+
define_associations(model)
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
private
|
|
20
|
+
|
|
21
|
+
def define_methods
|
|
22
|
+
rodauth = @auth_class.allocate.freeze
|
|
23
|
+
|
|
24
|
+
attr_reader :password
|
|
25
|
+
|
|
26
|
+
define_method(:password=) do |password|
|
|
27
|
+
@password = password
|
|
28
|
+
password_hash = rodauth.send(:password_hash, password) if password
|
|
29
|
+
set_password_hash(password_hash)
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
define_method(:set_password_hash) do |password_hash|
|
|
33
|
+
if rodauth.account_password_hash_column
|
|
34
|
+
public_send(:"#{rodauth.account_password_hash_column}=", password_hash)
|
|
35
|
+
else
|
|
36
|
+
if password_hash
|
|
37
|
+
record = self.password_hash || build_password_hash
|
|
38
|
+
record.public_send(:"#{rodauth.password_hash_column}=", password_hash)
|
|
39
|
+
else
|
|
40
|
+
self.password_hash&.mark_for_destruction
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def define_associations(model)
|
|
47
|
+
define_password_hash_association(model) unless rodauth.account_password_hash_column
|
|
48
|
+
|
|
49
|
+
feature_associations.each do |association|
|
|
50
|
+
define_association(model, **association)
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def define_password_hash_association(model)
|
|
55
|
+
password_hash_id_column = rodauth.password_hash_id_column
|
|
56
|
+
scope = -> { select(password_hash_id_column) } if rodauth.send(:use_database_authentication_functions?)
|
|
57
|
+
|
|
58
|
+
define_association model,
|
|
59
|
+
type: :has_one,
|
|
60
|
+
name: :password_hash,
|
|
61
|
+
table: rodauth.password_hash_table,
|
|
62
|
+
foreign_key: password_hash_id_column,
|
|
63
|
+
scope: scope,
|
|
64
|
+
autosave: true
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def define_association(model, type:, name:, table:, foreign_key:, scope: nil, **options)
|
|
68
|
+
associated_model = Class.new(model.superclass)
|
|
69
|
+
associated_model.table_name = table
|
|
70
|
+
associated_model.belongs_to :account,
|
|
71
|
+
class_name: model.name,
|
|
72
|
+
foreign_key: foreign_key,
|
|
73
|
+
inverse_of: name
|
|
74
|
+
|
|
75
|
+
model.const_set(name.to_s.singularize.camelize, associated_model)
|
|
76
|
+
|
|
77
|
+
model.public_send type, name, scope,
|
|
78
|
+
class_name: associated_model.name,
|
|
79
|
+
foreign_key: foreign_key,
|
|
80
|
+
dependent: :destroy,
|
|
81
|
+
inverse_of: :account,
|
|
82
|
+
**options,
|
|
83
|
+
**association_options(name)
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
def feature_associations
|
|
87
|
+
Rodauth::Rails::Model::Associations.call(rodauth)
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
def association_options(name)
|
|
91
|
+
options = @association_options
|
|
92
|
+
options = options.call(name) if options.respond_to?(:call)
|
|
93
|
+
options || {}
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
def rodauth
|
|
97
|
+
@auth_class.allocate
|
|
98
|
+
end
|
|
99
|
+
end
|
|
100
|
+
end
|
|
101
|
+
end
|
|
@@ -4,15 +4,15 @@ namespace :rodauth do
|
|
|
4
4
|
|
|
5
5
|
puts "Routes handled by #{app}:"
|
|
6
6
|
|
|
7
|
-
app.opts[:rodauths].
|
|
8
|
-
|
|
7
|
+
app.opts[:rodauths].each do |configuration_name, auth_class|
|
|
8
|
+
auth_class.configure { enable :path_class_methods }
|
|
9
9
|
|
|
10
|
-
routes =
|
|
10
|
+
routes = auth_class.routes.map do |handle_method|
|
|
11
11
|
path_method = "#{handle_method.to_s.sub(/\Ahandle_/, "")}_path"
|
|
12
12
|
|
|
13
13
|
[
|
|
14
|
-
|
|
15
|
-
"rodauth#{
|
|
14
|
+
auth_class.public_send(path_method),
|
|
15
|
+
"rodauth#{configuration_name && "(:#{configuration_name})"}.#{path_method}",
|
|
16
16
|
]
|
|
17
17
|
end
|
|
18
18
|
|
data/lib/rodauth/rails.rb
CHANGED
|
@@ -9,28 +9,45 @@ module Rodauth
|
|
|
9
9
|
# This allows the developer to avoid loading Rodauth at boot time.
|
|
10
10
|
autoload :App, "rodauth/rails/app"
|
|
11
11
|
autoload :Auth, "rodauth/rails/auth"
|
|
12
|
+
autoload :Model, "rodauth/rails/model"
|
|
12
13
|
|
|
13
14
|
@app = nil
|
|
14
15
|
@middleware = true
|
|
15
16
|
|
|
17
|
+
LOCK = Mutex.new
|
|
18
|
+
|
|
16
19
|
class << self
|
|
17
|
-
def rodauth(name = nil)
|
|
18
|
-
|
|
20
|
+
def rodauth(name = nil, query: nil, form: nil, account: nil, **options)
|
|
21
|
+
auth_class = app.rodauth(name)
|
|
19
22
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
host = url_options[:host]
|
|
24
|
-
host += ":#{port}" if port
|
|
23
|
+
unless auth_class
|
|
24
|
+
fail ArgumentError, "undefined rodauth configuration: #{name.inspect}"
|
|
25
|
+
end
|
|
25
26
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
27
|
+
LOCK.synchronize do
|
|
28
|
+
unless auth_class.features.include?(:internal_request)
|
|
29
|
+
auth_class.configure { enable :internal_request }
|
|
30
|
+
warn "Rodauth::Rails.rodauth requires the internal_request feature to be enabled. For now it was enabled automatically, but this behaviour will be removed in version 1.0."
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
if query || form
|
|
35
|
+
warn "The :query and :form keyword arguments for Rodauth::Rails.rodauth have been deprecated. Please use the :params argument supported by internal_request feature instead."
|
|
36
|
+
options[:params] = query || form
|
|
37
|
+
end
|
|
30
38
|
|
|
31
|
-
|
|
39
|
+
if account
|
|
40
|
+
options[:account_id] = account.id
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
auth_class.internal_request_eval(options) do
|
|
44
|
+
@account = account.attributes.symbolize_keys if account
|
|
45
|
+
self
|
|
46
|
+
end
|
|
47
|
+
end
|
|
32
48
|
|
|
33
|
-
|
|
49
|
+
def model(name = nil, **options)
|
|
50
|
+
Rodauth::Rails::Model.new(app.rodauth(name), **options)
|
|
34
51
|
end
|
|
35
52
|
|
|
36
53
|
# routing constraint that requires authentication
|
data/rodauth-rails.gemspec
CHANGED
|
@@ -17,10 +17,13 @@ Gem::Specification.new do |spec|
|
|
|
17
17
|
spec.require_paths = ["lib"]
|
|
18
18
|
|
|
19
19
|
spec.add_dependency "railties", ">= 4.2", "< 7"
|
|
20
|
-
spec.add_dependency "rodauth", "~> 2.
|
|
20
|
+
spec.add_dependency "rodauth", "~> 2.15"
|
|
21
21
|
spec.add_dependency "sequel-activerecord_connection", "~> 1.1"
|
|
22
22
|
spec.add_dependency "tilt"
|
|
23
23
|
spec.add_dependency "bcrypt"
|
|
24
24
|
|
|
25
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"
|
|
26
29
|
end
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: rodauth-rails
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.16.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Janko Marohnić
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2021-
|
|
11
|
+
date: 2021-09-26 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: railties
|
|
@@ -36,14 +36,14 @@ dependencies:
|
|
|
36
36
|
requirements:
|
|
37
37
|
- - "~>"
|
|
38
38
|
- !ruby/object:Gem::Version
|
|
39
|
-
version: '2.
|
|
39
|
+
version: '2.15'
|
|
40
40
|
type: :runtime
|
|
41
41
|
prerelease: false
|
|
42
42
|
version_requirements: !ruby/object:Gem::Requirement
|
|
43
43
|
requirements:
|
|
44
44
|
- - "~>"
|
|
45
45
|
- !ruby/object:Gem::Version
|
|
46
|
-
version: '2.
|
|
46
|
+
version: '2.15'
|
|
47
47
|
- !ruby/object:Gem::Dependency
|
|
48
48
|
name: sequel-activerecord_connection
|
|
49
49
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -100,6 +100,48 @@ dependencies:
|
|
|
100
100
|
- - ">="
|
|
101
101
|
- !ruby/object:Gem::Version
|
|
102
102
|
version: '0'
|
|
103
|
+
- !ruby/object:Gem::Dependency
|
|
104
|
+
name: rotp
|
|
105
|
+
requirement: !ruby/object:Gem::Requirement
|
|
106
|
+
requirements:
|
|
107
|
+
- - ">="
|
|
108
|
+
- !ruby/object:Gem::Version
|
|
109
|
+
version: '0'
|
|
110
|
+
type: :development
|
|
111
|
+
prerelease: false
|
|
112
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
113
|
+
requirements:
|
|
114
|
+
- - ">="
|
|
115
|
+
- !ruby/object:Gem::Version
|
|
116
|
+
version: '0'
|
|
117
|
+
- !ruby/object:Gem::Dependency
|
|
118
|
+
name: rqrcode
|
|
119
|
+
requirement: !ruby/object:Gem::Requirement
|
|
120
|
+
requirements:
|
|
121
|
+
- - ">="
|
|
122
|
+
- !ruby/object:Gem::Version
|
|
123
|
+
version: '0'
|
|
124
|
+
type: :development
|
|
125
|
+
prerelease: false
|
|
126
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
127
|
+
requirements:
|
|
128
|
+
- - ">="
|
|
129
|
+
- !ruby/object:Gem::Version
|
|
130
|
+
version: '0'
|
|
131
|
+
- !ruby/object:Gem::Dependency
|
|
132
|
+
name: webauthn
|
|
133
|
+
requirement: !ruby/object:Gem::Requirement
|
|
134
|
+
requirements:
|
|
135
|
+
- - ">="
|
|
136
|
+
- !ruby/object:Gem::Version
|
|
137
|
+
version: '0'
|
|
138
|
+
type: :development
|
|
139
|
+
prerelease: false
|
|
140
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
141
|
+
requirements:
|
|
142
|
+
- - ">="
|
|
143
|
+
- !ruby/object:Gem::Version
|
|
144
|
+
version: '0'
|
|
103
145
|
description: Provides Rails integration for Rodauth.
|
|
104
146
|
email:
|
|
105
147
|
- janko.marohnic@gmail.com
|
|
@@ -212,8 +254,11 @@ files:
|
|
|
212
254
|
- lib/rodauth/rails/feature/csrf.rb
|
|
213
255
|
- lib/rodauth/rails/feature/email.rb
|
|
214
256
|
- lib/rodauth/rails/feature/instrumentation.rb
|
|
257
|
+
- lib/rodauth/rails/feature/internal_request.rb
|
|
215
258
|
- lib/rodauth/rails/feature/render.rb
|
|
216
259
|
- lib/rodauth/rails/middleware.rb
|
|
260
|
+
- lib/rodauth/rails/model.rb
|
|
261
|
+
- lib/rodauth/rails/model/associations.rb
|
|
217
262
|
- lib/rodauth/rails/railtie.rb
|
|
218
263
|
- lib/rodauth/rails/tasks.rake
|
|
219
264
|
- lib/rodauth/rails/version.rb
|
|
@@ -237,7 +282,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
237
282
|
- !ruby/object:Gem::Version
|
|
238
283
|
version: '0'
|
|
239
284
|
requirements: []
|
|
240
|
-
rubygems_version: 3.2.
|
|
285
|
+
rubygems_version: 3.2.15
|
|
241
286
|
signing_key:
|
|
242
287
|
specification_version: 4
|
|
243
288
|
summary: Provides Rails integration for Rodauth.
|