rodauth-rails 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/LICENSE.txt +21 -0
- data/README.md +589 -0
- data/lib/generators/rodauth/install_generator.rb +65 -0
- data/lib/generators/rodauth/mailer_generator.rb +38 -0
- data/lib/generators/rodauth/templates/app/controllers/rodauth_controller.rb +3 -0
- data/lib/generators/rodauth/templates/app/mailers/rodauth_mailer.rb +37 -0
- data/lib/generators/rodauth/templates/app/models/account.rb +2 -0
- data/lib/generators/rodauth/templates/config/initializers/rodauth.rb +3 -0
- data/lib/generators/rodauth/templates/config/initializers/sequel.rb +13 -0
- data/lib/generators/rodauth/templates/db/migrate/create_rodauth.rb +170 -0
- data/lib/generators/rodauth/templates/lib/rodauth_app.rb +186 -0
- data/lib/generators/rodauth/views_generator.rb +123 -0
- data/lib/rodauth/features/rails.rb +1 -0
- data/lib/rodauth/rails/app/flash.rb +50 -0
- data/lib/rodauth/rails/app.rb +45 -0
- data/lib/rodauth/rails/controller_methods.rb +20 -0
- data/lib/rodauth/rails/feature.rb +118 -0
- data/lib/rodauth/rails/middleware.rb +21 -0
- data/lib/rodauth/rails/railtie.rb +18 -0
- data/lib/rodauth/rails.rb +33 -0
- data/lib/rodauth-rails.rb +1 -0
- data/rodauth-rails.gemspec +22 -0
- metadata +147 -0
@@ -0,0 +1,38 @@
|
|
1
|
+
require "rails/generators/base"
|
2
|
+
require "rodauth/version"
|
3
|
+
|
4
|
+
module Rodauth
|
5
|
+
module Rails
|
6
|
+
module Generators
|
7
|
+
class MailerGenerator < ::Rails::Generators::Base
|
8
|
+
source_root "#{__dir__}/templates"
|
9
|
+
namespace "rodauth:mailer"
|
10
|
+
|
11
|
+
VIEWS = %w[
|
12
|
+
email_auth
|
13
|
+
password_changed
|
14
|
+
reset_password
|
15
|
+
unlock_account
|
16
|
+
verify_account
|
17
|
+
verify_login_change
|
18
|
+
]
|
19
|
+
|
20
|
+
class_option :name,
|
21
|
+
desc: "The name for the mailer and the views directory",
|
22
|
+
default: "rodauth"
|
23
|
+
|
24
|
+
def copy_mailer
|
25
|
+
template "app/mailers/rodauth_mailer.rb",
|
26
|
+
"app/mailers/#{options[:name].underscore}_mailer.rb"
|
27
|
+
end
|
28
|
+
|
29
|
+
def copy_mailer_views
|
30
|
+
VIEWS.each do |view|
|
31
|
+
template "app/views/rodauth_mailer/#{view}.text.erb",
|
32
|
+
"app/views/#{options[:name].underscore}_mailer/#{view}.text.erb"
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
class <%= options[:name].camelize %>Mailer < ApplicationMailer
|
2
|
+
def verify_account(recipient, email_link)
|
3
|
+
@email_link = email_link
|
4
|
+
|
5
|
+
mail to: recipient
|
6
|
+
end
|
7
|
+
|
8
|
+
def reset_password(recipient, email_link)
|
9
|
+
@email_link = email_link
|
10
|
+
|
11
|
+
mail to: recipient
|
12
|
+
end
|
13
|
+
|
14
|
+
def verify_login_change(recipient, old_login, new_login, email_link)
|
15
|
+
@old_login = old_login
|
16
|
+
@new_login = new_login
|
17
|
+
@email_link = email_link
|
18
|
+
|
19
|
+
mail to: recipient
|
20
|
+
end
|
21
|
+
|
22
|
+
def password_changed(recipient)
|
23
|
+
mail to: recipient
|
24
|
+
end
|
25
|
+
|
26
|
+
# def email_auth(recipient, email_link)
|
27
|
+
# @email_link = email_link
|
28
|
+
|
29
|
+
# mail to: recipient
|
30
|
+
# end
|
31
|
+
|
32
|
+
# def unlock_account(recipient, email_link)
|
33
|
+
# @email_link = email_link
|
34
|
+
|
35
|
+
# mail to: recipient
|
36
|
+
# end
|
37
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
require "sequel/core"
|
2
|
+
|
3
|
+
# initialize the appropriate Sequel adapter without creating a connection
|
4
|
+
<% case adapter -%>
|
5
|
+
<% when "postgresql" -%>
|
6
|
+
DB = Sequel.postgres(test: false)
|
7
|
+
<% when "mysql2" -%>
|
8
|
+
DB = Sequel.mysql2(test: false)
|
9
|
+
<% when "sqlite3" -%>
|
10
|
+
DB = Sequel.sqlite(test: false)
|
11
|
+
<% end -%>
|
12
|
+
# have Sequel use ActiveRecord's connection for database interaction
|
13
|
+
DB.extension :activerecord_connection
|
@@ -0,0 +1,170 @@
|
|
1
|
+
class CreateRodauth < ActiveRecord::Migration<%= migration_version %>
|
2
|
+
def change
|
3
|
+
<% if adapter == "postgresql" -%>
|
4
|
+
enable_extension "citext"
|
5
|
+
|
6
|
+
<% end -%>
|
7
|
+
create_table :accounts do |t|
|
8
|
+
<% case adapter -%>
|
9
|
+
<% when "postgresql" -%>
|
10
|
+
t.citext :email, null: false, index: { unique: true, where: "status IN ('verified', 'unverified')" }
|
11
|
+
<% else -%>
|
12
|
+
t.string :email, null: false, index: { unique: true }
|
13
|
+
<% end -%>
|
14
|
+
t.string :status, null: false, default: "verified"
|
15
|
+
end
|
16
|
+
|
17
|
+
# Used if storing password hashes in a separate table (default)
|
18
|
+
create_table :account_password_hashes do |t|
|
19
|
+
t.foreign_key :accounts, column: :id
|
20
|
+
t.string :password_hash, null: false
|
21
|
+
end
|
22
|
+
|
23
|
+
# Used by the password reset feature
|
24
|
+
create_table :account_password_reset_keys do |t|
|
25
|
+
t.foreign_key :accounts, column: :id
|
26
|
+
t.string :key, null: false
|
27
|
+
t.datetime :deadline, null: false
|
28
|
+
t.datetime :email_last_sent, null: false, default: -> { "CURRENT_TIMESTAMP" }
|
29
|
+
end
|
30
|
+
|
31
|
+
# Used by the account verification feature
|
32
|
+
create_table :account_verification_keys do |t|
|
33
|
+
t.foreign_key :accounts, column: :id
|
34
|
+
t.string :key, null: false
|
35
|
+
t.datetime :requested_at, null: false, default: -> { "CURRENT_TIMESTAMP" }
|
36
|
+
t.datetime :email_last_sent, null: false, default: -> { "CURRENT_TIMESTAMP" }
|
37
|
+
end
|
38
|
+
|
39
|
+
# Used by the verify login change feature
|
40
|
+
create_table :account_login_change_keys do |t|
|
41
|
+
t.foreign_key :accounts, column: :id
|
42
|
+
t.string :key, null: false
|
43
|
+
t.string :login, null: false
|
44
|
+
t.datetime :deadline, null: false
|
45
|
+
end
|
46
|
+
|
47
|
+
# Used by the remember me feature
|
48
|
+
create_table :account_remember_keys do |t|
|
49
|
+
t.foreign_key :accounts, column: :id
|
50
|
+
t.string :key, null: false
|
51
|
+
t.datetime :deadline, null: false
|
52
|
+
end
|
53
|
+
|
54
|
+
# # Used by the audit logging feature
|
55
|
+
# create_table :account_authentication_audit_logs do |t|
|
56
|
+
# t.references :account, null: false
|
57
|
+
# t.datetime :at, null: false, default: -> { "CURRENT_TIMESTAMP" }
|
58
|
+
# t.text :message, null: false
|
59
|
+
<% case adapter -%>
|
60
|
+
<% when "postgresql" -%>
|
61
|
+
# t.jsonb :metadata
|
62
|
+
<% when "sqlite3", "mysql2" -%>
|
63
|
+
# t.json :metadata
|
64
|
+
<% else -%>
|
65
|
+
# t.string :metadata
|
66
|
+
<% end -%>
|
67
|
+
# t.index [:account_id, :at], name: "audit_account_at_idx"
|
68
|
+
# t.index :at, name: "audit_at_idx"
|
69
|
+
# end
|
70
|
+
|
71
|
+
# # Used by the jwt refresh feature
|
72
|
+
# create_table :account_jwt_refresh_keys do |t|
|
73
|
+
# t.references :account, null: false
|
74
|
+
# t.string :key, null: false
|
75
|
+
# t.datetime :deadline, null: false
|
76
|
+
# t.index :account_id, name: "account_jwt_rk_account_id_idx"
|
77
|
+
# end
|
78
|
+
|
79
|
+
# # Used by the disallow_password_reuse feature
|
80
|
+
# create_table :account_previous_password_hashes do |t|
|
81
|
+
# t.references :account
|
82
|
+
# t.string :password_hash, null: false
|
83
|
+
# end
|
84
|
+
|
85
|
+
# # Used by the lockout feature
|
86
|
+
# create_table :account_login_failures do |t|
|
87
|
+
# t.foreign_key :accounts, column: :id
|
88
|
+
# t.integer :number, null: false, default: 1
|
89
|
+
# end
|
90
|
+
# create_table :account_lockouts do |t|
|
91
|
+
# t.foreign_key :accounts, column: :id
|
92
|
+
# t.string :key, null: false
|
93
|
+
# t.datetime :deadline, null: false
|
94
|
+
# t.datetime :email_last_sent
|
95
|
+
# end
|
96
|
+
|
97
|
+
# # Used by the email auth feature
|
98
|
+
# create_table :account_email_auth_keys do |t|
|
99
|
+
# t.foreign_key :accounts, column: :id
|
100
|
+
# t.string :key, null: false
|
101
|
+
# t.datetime :deadline, null: false
|
102
|
+
# t.datetime :email_last_sent, null: false, default: -> { "CURRENT_TIMESTAMP" }
|
103
|
+
# end
|
104
|
+
|
105
|
+
# # Used by the password expiration feature
|
106
|
+
# create_table :account_password_change_times do |t|
|
107
|
+
# t.foreign_key :accounts, column: :id
|
108
|
+
# t.datetime :changed_at, null: false, default: -> { "CURRENT_TIMESTAMP" }
|
109
|
+
# end
|
110
|
+
|
111
|
+
# # Used by the account expiration feature
|
112
|
+
# create_table :account_activity_times do |t|
|
113
|
+
# t.foreign_key :accounts, column: :id
|
114
|
+
# t.datetime :last_activity_at, null: false
|
115
|
+
# t.datetime :last_login_at, null: false
|
116
|
+
# t.datetime :expired_at
|
117
|
+
# end
|
118
|
+
|
119
|
+
# # Used by the single session feature
|
120
|
+
# create_table :account_session_keys do |t|
|
121
|
+
# t.foreign_key :accounts, column: :id
|
122
|
+
# t.string :key, null: false
|
123
|
+
# end
|
124
|
+
|
125
|
+
# # Used by the active sessions feature
|
126
|
+
# create_table :account_active_session_keys, primary_key: [:account_id, :session_id] do |t|
|
127
|
+
# t.references :account
|
128
|
+
# t.string :session_id
|
129
|
+
# t.datetime :created_at, null: false, default: -> { "CURRENT_TIMESTAMP" }
|
130
|
+
# t.datetime :last_use, null: false, default: -> { "CURRENT_TIMESTAMP" }
|
131
|
+
# end
|
132
|
+
|
133
|
+
# # Used by the webauthn feature
|
134
|
+
# create_table :account_webauthn_user_ids do |t|
|
135
|
+
# t.foreign_key :accounts, column: :id
|
136
|
+
# t.string :webauthn_id, null: false
|
137
|
+
# end
|
138
|
+
# create_table :account_webauthn_keys, primary_key: [:account_id, :webauthn_id] do |t|
|
139
|
+
# t.references :account
|
140
|
+
# t.string :webauthn_id
|
141
|
+
# t.string :public_key, null: false
|
142
|
+
# t.integer :sign_count, null: false
|
143
|
+
# t.datetime :last_use, null: false, default: -> { "CURRENT_TIMESTAMP" }
|
144
|
+
# end
|
145
|
+
|
146
|
+
# # Used by the otp feature
|
147
|
+
# create_table :account_otp_keys do |t|
|
148
|
+
# t.foreign_key :accounts, column: :id
|
149
|
+
# t.string :key, null: false
|
150
|
+
# t.integer :num_failures, null: false, default: 0
|
151
|
+
# t.datetime :last_use, null: false, default: -> { "CURRENT_TIMESTAMP" }
|
152
|
+
# end
|
153
|
+
|
154
|
+
# # Used by the recovery codes feature
|
155
|
+
# create_table :account_recovery_codes, primary_key: [:id, :code] do |t|
|
156
|
+
# t.integer :id
|
157
|
+
# t.foreign_key :accounts, column: :id
|
158
|
+
# t.string :code
|
159
|
+
# end
|
160
|
+
|
161
|
+
# # Used by the sms codes feature
|
162
|
+
# create_table :account_sms_codes do |t|
|
163
|
+
# t.foreign_key :accounts, column: :id
|
164
|
+
# t.string :phone_number, null: false
|
165
|
+
# t.integer :num_failures
|
166
|
+
# t.string :code
|
167
|
+
# t.datetime :code_issued_at, null: false, default: -> { "CURRENT_TIMESTAMP" }
|
168
|
+
# end
|
169
|
+
end
|
170
|
+
end
|
@@ -0,0 +1,186 @@
|
|
1
|
+
class RodauthApp < Rodauth::Rails::App
|
2
|
+
configure do
|
3
|
+
# List of authentication features that are loaded.
|
4
|
+
enable :create_account, :verify_account, :verify_account_grace_period,
|
5
|
+
:login, :remember, :logout,
|
6
|
+
:reset_password, :change_password, :change_password_notify,
|
7
|
+
:change_login, :verify_login_change,
|
8
|
+
:close_account
|
9
|
+
|
10
|
+
# See the Rodauth documentation for the list of available config options:
|
11
|
+
# http://rodauth.jeremyevans.net/documentation.html
|
12
|
+
|
13
|
+
# ==> General
|
14
|
+
# Specify the controller used for view rendering and CSRF verification.
|
15
|
+
rails_controller { RodauthController }
|
16
|
+
|
17
|
+
# Store account status in a text column.
|
18
|
+
account_status_column :status
|
19
|
+
account_unverified_status_value "unverified"
|
20
|
+
account_open_status_value "verified"
|
21
|
+
account_closed_status_value "closed"
|
22
|
+
|
23
|
+
# Store password hash in a column instead of a separate table.
|
24
|
+
# account_password_hash_column :password_digest
|
25
|
+
|
26
|
+
# Set password when creating account instead of when verifying.
|
27
|
+
verify_account_set_password? false
|
28
|
+
|
29
|
+
# Redirect back to originally requested location after authentication.
|
30
|
+
# login_return_to_requested_location? true
|
31
|
+
# two_factor_auth_return_to_requested_location? true # if using MFA
|
32
|
+
|
33
|
+
# Autologin the user after they have reset their password.
|
34
|
+
# reset_password_autologin? true
|
35
|
+
|
36
|
+
# Delete the account record when the user has closed their account.
|
37
|
+
# delete_account_on_close? true
|
38
|
+
|
39
|
+
# Redirect to the app from login and registration pages if already logged in.
|
40
|
+
# already_logged_in { redirect login_redirect }
|
41
|
+
|
42
|
+
# ==> Emails
|
43
|
+
# Uncomment the lines below once you've imported mailer views.
|
44
|
+
# send_reset_password_email do
|
45
|
+
# RodauthMailer.reset_password(email_to, password_reset_email_link).deliver_now
|
46
|
+
# end
|
47
|
+
# send_verify_account_email do
|
48
|
+
# RodauthMailer.verify_account(email_to, verify_account_email_link).deliver_now
|
49
|
+
# end
|
50
|
+
# send_verify_login_change_email do |login|
|
51
|
+
# RodauthMailer.verify_login_change(login, verify_login_change_old_login, verify_login_change_new_login, verify_login_change_email_link).deliver_now
|
52
|
+
# end
|
53
|
+
# send_password_changed_email do
|
54
|
+
# RodauthMailer.password_changed(email_to).deliver_now
|
55
|
+
# end
|
56
|
+
# # send_email_auth_email do
|
57
|
+
# # RodauthMailer.email_auth(email_to, email_auth_email_link).deliver_now
|
58
|
+
# # end
|
59
|
+
# # send_unlock_account_email do
|
60
|
+
<% if Rodauth::MAJOR == 1 -%>
|
61
|
+
# # @unlock_account_key_value = get_unlock_account_key
|
62
|
+
<% end -%>
|
63
|
+
# # RodauthMailer.unlock_account(email_to, unlock_account_email_link).deliver_now
|
64
|
+
# # end
|
65
|
+
|
66
|
+
# In the meantime you can tweak settings for emails created by Rodauth
|
67
|
+
# email_subject_prefix "[MyApp] "
|
68
|
+
# email_from "noreply@myapp.com"
|
69
|
+
# send_email(&:deliver_later)
|
70
|
+
# reset_password_email_body { "Click here to reset your password: #{reset_password_email_link}" }
|
71
|
+
|
72
|
+
# ==> Flash
|
73
|
+
# Match flash keys with ones already used in the Rails app.
|
74
|
+
# flash_notice_key :success # default is :notice
|
75
|
+
# flash_error_key :error # default is :alert
|
76
|
+
|
77
|
+
# Override default flash messages.
|
78
|
+
# create_account_notice_flash "Your account has been created. Please verify your account by visiting the confirmation link sent to your email address."
|
79
|
+
# login_error_flash "Login is required for accessing this page"
|
80
|
+
# login_notice_flash nil
|
81
|
+
|
82
|
+
# ==> Validation
|
83
|
+
# Override default validation error messages.
|
84
|
+
# no_matching_login_message "user with this email address doesn't exist"
|
85
|
+
# already_an_account_with_this_login_message "user with this email address already exists"
|
86
|
+
# password_too_short_message { "needs to have at least #{password_minimum_length} characters" }
|
87
|
+
# login_does_not_meet_requirements_message { "invalid email#{", #{login_requirement_message}" if login_requirement_message}" }
|
88
|
+
|
89
|
+
# Change minimum number of password characters required when creating an account.
|
90
|
+
# password_minimum_length 8
|
91
|
+
|
92
|
+
# ==> Remember Feature
|
93
|
+
# Remember all logged in users.
|
94
|
+
after_login { remember_login }
|
95
|
+
|
96
|
+
# Or only remember users that have ticked a "Remember Me" checkbox on login.
|
97
|
+
# after_login { remember_login if param_or_nil("remember") }
|
98
|
+
|
99
|
+
# Extend user's remember period when remembered via a cookie
|
100
|
+
extend_remember_deadline? true
|
101
|
+
|
102
|
+
# Consider remembered users to be multifactor-authenticated (if using MFA).
|
103
|
+
# after_load_memory { two_factor_update_session("totp") if two_factor_authentication_setup? }
|
104
|
+
|
105
|
+
# ==> Hooks
|
106
|
+
# Validate custom fields in the create account form.
|
107
|
+
# before_create_account do
|
108
|
+
# throw_error_status(422, "name", "must be present") if param("name").empty?
|
109
|
+
# end
|
110
|
+
|
111
|
+
# Perform additional actions after the account is created.
|
112
|
+
# after_create_account do
|
113
|
+
# Profile.create!(account_id: account[:id], name: param("name"))
|
114
|
+
# end
|
115
|
+
|
116
|
+
# Do additional cleanup after the account is closed.
|
117
|
+
# after_close_account do
|
118
|
+
# Profile.find_by!(account_id: account[:id]).destroy
|
119
|
+
# end
|
120
|
+
|
121
|
+
# ==> Redirects
|
122
|
+
# Redirect to home page after logout.
|
123
|
+
logout_redirect "/"
|
124
|
+
|
125
|
+
# Redirect to wherever login redirects to after account verification.
|
126
|
+
verify_account_redirect { login_redirect }
|
127
|
+
|
128
|
+
# Redirect to login page after password reset.
|
129
|
+
reset_password_redirect { login_path }
|
130
|
+
|
131
|
+
# ==> Deadlines
|
132
|
+
# Change default deadlines for some actions.
|
133
|
+
# verify_account_grace_period 3.days
|
134
|
+
# reset_password_deadline_interval Hash[hours: 6]
|
135
|
+
# verify_login_change_deadline_interval Hash[days: 2]
|
136
|
+
# remember_deadline_interval Hash[days: 30]
|
137
|
+
|
138
|
+
# ==> Extending
|
139
|
+
# Define any additional methods you want for the Rodauth object.
|
140
|
+
# auth_class_eval do
|
141
|
+
# def my_send_email(name, *args)
|
142
|
+
# AuthenticationMailer.public_send(name, *args).deliver_later
|
143
|
+
# end
|
144
|
+
# end
|
145
|
+
#
|
146
|
+
# Then use the new custom method in configuration blocks.
|
147
|
+
# send_password_reset_email do
|
148
|
+
# my_send_email(:password_reset, email_to, password_reset_email_link)
|
149
|
+
# end
|
150
|
+
end
|
151
|
+
|
152
|
+
# ==> Multiple configurations
|
153
|
+
# configure(:admin) do
|
154
|
+
# enable :http_basic_auth
|
155
|
+
#
|
156
|
+
# prefix "/admin"
|
157
|
+
# session_key :admin_id
|
158
|
+
# end
|
159
|
+
|
160
|
+
route do |r|
|
161
|
+
rodauth.load_memory # autologin remembered users
|
162
|
+
|
163
|
+
r.rodauth # route rodauth requests
|
164
|
+
|
165
|
+
# ==> Authenticating Requests
|
166
|
+
# Call `rodauth.require_authentication` for requests that you want to
|
167
|
+
# require authentication for. Some examples:
|
168
|
+
#
|
169
|
+
# next if r.path.start_with?("/docs") # skip authentication for documentation pages
|
170
|
+
# next if session[:admin] # skip authentication for admins
|
171
|
+
#
|
172
|
+
# # authenticate /dashboard/* and /account/* requests
|
173
|
+
# if r.path.start_with?("/dashboard") || r.path.start_with?("/account")
|
174
|
+
# rodauth.require_authentication
|
175
|
+
# end
|
176
|
+
|
177
|
+
# ==> Multiple configurations
|
178
|
+
# r.on "admin" do
|
179
|
+
# r.rodauth(:admin)
|
180
|
+
#
|
181
|
+
# unless rodauth(:admin).logged_in?
|
182
|
+
# rodauth(:admin).require_http_basic_auth
|
183
|
+
# end
|
184
|
+
# end
|
185
|
+
end
|
186
|
+
end
|
@@ -0,0 +1,123 @@
|
|
1
|
+
require "rails/generators/base"
|
2
|
+
require "rodauth/version"
|
3
|
+
|
4
|
+
module Rodauth
|
5
|
+
module Rails
|
6
|
+
module Generators
|
7
|
+
class ViewsGenerator < ::Rails::Generators::Base
|
8
|
+
source_root "#{__dir__}/templates"
|
9
|
+
namespace "rodauth:views"
|
10
|
+
|
11
|
+
VIEWS = {
|
12
|
+
login: %w[
|
13
|
+
_field _field_error _login_field _login_display _password_field
|
14
|
+
_submit _login_form _login_form_footer _login_form_header login
|
15
|
+
multi_phase_login
|
16
|
+
],
|
17
|
+
create_account: %w[
|
18
|
+
_field _field_error _login_field _login_confirm_field
|
19
|
+
_password_field _password_confirm_field _submit create_account
|
20
|
+
],
|
21
|
+
logout: %w[
|
22
|
+
_submit logout
|
23
|
+
],
|
24
|
+
reset_password: %w[
|
25
|
+
_field _field_error _login_field _login_hidden_field
|
26
|
+
_password_field _password_confirm_field _submit
|
27
|
+
reset_password_request reset_password
|
28
|
+
],
|
29
|
+
remember: %w[
|
30
|
+
_submit remember
|
31
|
+
],
|
32
|
+
change_login: %w[
|
33
|
+
_field _field_error _login_field _login_confirm_field
|
34
|
+
_password_field _submit change_login
|
35
|
+
],
|
36
|
+
change_password: %w[
|
37
|
+
_field _field_error _password_field _new_password_field
|
38
|
+
_password_confirm_field _submit change_password
|
39
|
+
],
|
40
|
+
close_account: %w[
|
41
|
+
_field _field_error _password_field _submit close_account
|
42
|
+
],
|
43
|
+
email_auth: %w[
|
44
|
+
_login_hidden_field _submit _email_auth_request_form email_auth
|
45
|
+
],
|
46
|
+
verify_account: %w[
|
47
|
+
_field _field_error _login_hidden_field _login_field _submit
|
48
|
+
verify_account_resend verify_account
|
49
|
+
],
|
50
|
+
lockout: %w[
|
51
|
+
_login_hidden_field _submit unlock_account_request unlock_account
|
52
|
+
],
|
53
|
+
active_sessions: %w[
|
54
|
+
_global_logout_field
|
55
|
+
],
|
56
|
+
two_factor_base: %w[
|
57
|
+
_field _field_error _password_field _submit
|
58
|
+
two_factor_manage two_factor_auth two_factor_disable
|
59
|
+
],
|
60
|
+
otp: %w[
|
61
|
+
_field _field_error _otp_auth_code_field _password_field _submit
|
62
|
+
otp_setup otp_auth otp_disable
|
63
|
+
],
|
64
|
+
sms_codes: %w[
|
65
|
+
_field _field_error _sms_code_field _sms_phone_field
|
66
|
+
_password_field _submit
|
67
|
+
sms_setup sms_confirm sms_auth sms_request sms_disable
|
68
|
+
],
|
69
|
+
recovery_codes: %w[
|
70
|
+
_field _field_error _recovery_code_field _recovery_codes_form
|
71
|
+
recovery_codes add_recovery_codes recovery_auth
|
72
|
+
],
|
73
|
+
webauthn: %w[
|
74
|
+
_field _field_error _login_hidden_field _password_field _submit
|
75
|
+
webauthn_setup webauthn_auth webauthn_remove
|
76
|
+
]
|
77
|
+
}
|
78
|
+
|
79
|
+
DEPENDENCIES = {
|
80
|
+
active_sessions: :logout,
|
81
|
+
otp: :two_factor_base,
|
82
|
+
sms_codes: :two_factor_base,
|
83
|
+
recovery_codes: :two_factor_base,
|
84
|
+
webauthn: :two_factor_base,
|
85
|
+
}
|
86
|
+
|
87
|
+
class_option :features, type: :array,
|
88
|
+
desc: "Rodauth features to generate views for (login, create_account, reset_password, verify_account etc.)",
|
89
|
+
default: %w[login logout create_account verify_account reset_password change_password change_login verify_login_change close_account]
|
90
|
+
|
91
|
+
class_option :all, aliases: "-a", type: :boolean,
|
92
|
+
desc: "Generates views for all Rodauth features",
|
93
|
+
default: false
|
94
|
+
|
95
|
+
class_option :directory, aliases: "-d", type: :string,
|
96
|
+
desc: "The directory under app/views/* into which to create views",
|
97
|
+
default: "rodauth"
|
98
|
+
|
99
|
+
def create_views
|
100
|
+
features = options[:all] ? VIEWS.keys : options[:features].map(&:to_sym)
|
101
|
+
|
102
|
+
views = features.inject([]) do |list, feature|
|
103
|
+
list |= VIEWS[feature] || []
|
104
|
+
list |= VIEWS[DEPENDENCIES[feature]] || []
|
105
|
+
end
|
106
|
+
|
107
|
+
if Rodauth::MAJOR == 1
|
108
|
+
views -= %w[
|
109
|
+
multi_phase_login _global_logout_field
|
110
|
+
two_factor_manage two_factor_auth two_factor_disable
|
111
|
+
webauthn_setup webauthn_auth webauthn_remove
|
112
|
+
]
|
113
|
+
end
|
114
|
+
|
115
|
+
views.each do |view|
|
116
|
+
template "app/views/rodauth/#{view}.html.erb",
|
117
|
+
"app/views/#{options[:directory].underscore}/#{view}.html.erb"
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
require "rodauth/rails/feature"
|
@@ -0,0 +1,50 @@
|
|
1
|
+
module Rodauth
|
2
|
+
module Rails
|
3
|
+
class App
|
4
|
+
# Sets up Rails' flash integration.
|
5
|
+
module Flash
|
6
|
+
def self.load_dependencies(app)
|
7
|
+
app.plugin :hooks
|
8
|
+
end
|
9
|
+
|
10
|
+
def self.configure(app)
|
11
|
+
app.before { request.flash } # load flash
|
12
|
+
app.after { request.commit_flash } # save flash
|
13
|
+
end
|
14
|
+
|
15
|
+
module InstanceMethods
|
16
|
+
def flash
|
17
|
+
request.flash
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
module RequestMethods
|
22
|
+
# If the redirect would bubble up outside of the Roda app, the after
|
23
|
+
# hook would never get called, so we make sure to commit the flash.
|
24
|
+
def redirect(*)
|
25
|
+
commit_flash
|
26
|
+
super
|
27
|
+
end
|
28
|
+
|
29
|
+
def flash
|
30
|
+
rails_request.flash
|
31
|
+
end
|
32
|
+
|
33
|
+
def commit_flash
|
34
|
+
if ActionPack.version >= Gem::Version.new("5.0.0")
|
35
|
+
rails_request.commit_flash
|
36
|
+
else
|
37
|
+
# ActionPack 4.2 automatically commits flash
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
private
|
42
|
+
|
43
|
+
def rails_request
|
44
|
+
ActionDispatch::Request.new(env)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
require "roda"
|
2
|
+
|
3
|
+
module Rodauth
|
4
|
+
module Rails
|
5
|
+
# The superclass for creating a Rodauth middleware.
|
6
|
+
class App < Roda
|
7
|
+
require "rodauth/rails/app/flash"
|
8
|
+
|
9
|
+
plugin :middleware
|
10
|
+
plugin :hooks
|
11
|
+
plugin :render, layout: false
|
12
|
+
|
13
|
+
plugin Flash
|
14
|
+
|
15
|
+
def self.configure(name = nil, **options, &block)
|
16
|
+
plugin :rodauth, name: name, csrf: false, flash: false, **options do
|
17
|
+
# load the Rails integration
|
18
|
+
enable :rails
|
19
|
+
|
20
|
+
# database functions are more complex to set up, so disable them by default
|
21
|
+
use_database_authentication_functions? false
|
22
|
+
|
23
|
+
# avoid having to set deadline values in column default values
|
24
|
+
set_deadline_values? true
|
25
|
+
|
26
|
+
# use HMACs for additional security
|
27
|
+
hmac_secret { ::Rails.application.secrets.secret_key_base }
|
28
|
+
|
29
|
+
# evaluate user configuration
|
30
|
+
instance_exec(&block)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
before do
|
35
|
+
(opts[:rodauths] || {}).each do |name, _|
|
36
|
+
if name
|
37
|
+
env["rodauth.#{name}"] = rodauth(name)
|
38
|
+
else
|
39
|
+
env["rodauth"] = rodauth
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|