action_auth 1.8.9 → 2.0.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 +102 -0
- data/README.md +485 -36
- data/Rakefile +0 -2
- data/app/assets/javascripts/action_auth/application.js +72 -71
- data/app/assets/stylesheets/action_auth/application.css +38 -1
- data/app/controllers/action_auth/application_controller.rb +122 -1
- data/app/controllers/action_auth/connected_accounts_controller.rb +16 -0
- data/app/controllers/action_auth/identity/email_verifications_controller.rb +36 -5
- data/app/controllers/action_auth/identity/emails_controller.rb +16 -4
- data/app/controllers/action_auth/identity/password_resets_controller.rb +20 -22
- data/app/controllers/action_auth/magics/requests_controller.rb +27 -6
- data/app/controllers/action_auth/magics/sign_ins_controller.rb +22 -7
- data/app/controllers/action_auth/passwords_controller.rb +7 -18
- data/app/controllers/action_auth/provider_callbacks_controller.rb +147 -0
- data/app/controllers/action_auth/registrations_controller.rb +7 -25
- data/app/controllers/action_auth/sessions/passkeys_controller.rb +17 -9
- data/app/controllers/action_auth/sessions_controller.rb +27 -25
- data/app/controllers/action_auth/sms_auths/requests_controller.rb +40 -14
- data/app/controllers/action_auth/sms_auths/sign_ins_controller.rb +40 -15
- data/app/controllers/action_auth/users_controller.rb +35 -1
- data/app/controllers/action_auth/webauthn_credential_authentications_controller.rb +36 -51
- data/app/controllers/action_auth/webauthn_credentials_controller.rb +63 -51
- data/app/helpers/action_auth/application_helper.rb +83 -0
- data/app/mailers/action_auth/application_mailer.rb +1 -1
- data/app/mailers/action_auth/user_mailer.rb +7 -0
- data/app/models/action_auth/connected_account.rb +18 -0
- data/app/models/action_auth/session.rb +9 -1
- data/app/models/action_auth/user.rb +197 -4
- data/app/models/action_auth/webauthn_credential.rb +2 -0
- data/app/views/action_auth/identity/email_verifications/show.html.erb +23 -0
- data/app/views/action_auth/identity/emails/edit.html.erb +41 -42
- data/app/views/action_auth/identity/password_resets/edit.html.erb +10 -11
- data/app/views/action_auth/identity/password_resets/new.html.erb +4 -9
- data/app/views/action_auth/magics/requests/new.html.erb +4 -14
- data/app/views/action_auth/magics/sign_ins/show.html.erb +18 -0
- data/app/views/action_auth/passwords/edit.html.erb +9 -21
- data/app/views/action_auth/registrations/new.html.erb +5 -27
- data/app/views/action_auth/sessions/_account.html.erb +30 -0
- data/app/views/action_auth/sessions/_connected_accounts.html.erb +32 -0
- data/app/views/action_auth/sessions/_security_keys.html.erb +32 -0
- data/app/views/action_auth/sessions/_sessions.html.erb +28 -0
- data/app/views/action_auth/sessions/index.html.erb +10 -62
- data/app/views/action_auth/sessions/new.html.erb +3 -21
- data/app/views/action_auth/sessions/passkeys/new.html.erb +10 -4
- data/app/views/action_auth/shared/_errors.html.erb +10 -0
- data/app/views/action_auth/shared/_flash.html.erb +11 -0
- data/app/views/action_auth/shared/_links.html.erb +3 -0
- data/app/views/action_auth/shared/_oauth_buttons.html.erb +5 -0
- data/app/views/action_auth/shared/_webauthn_error.html.erb +1 -0
- data/app/views/action_auth/sms_auths/requests/new.html.erb +4 -14
- data/app/views/action_auth/sms_auths/sign_ins/show.html.erb +6 -2
- data/app/views/action_auth/user_mailer/account_locked.html.erb +17 -0
- data/app/views/action_auth/user_mailer/account_locked.text.erb +12 -0
- data/app/views/action_auth/user_mailer/email_verification.html.erb +5 -0
- data/app/views/action_auth/user_mailer/email_verification.text.erb +3 -0
- data/app/views/action_auth/user_mailer/magic_link.html.erb +4 -0
- data/app/views/action_auth/user_mailer/magic_link.text.erb +5 -0
- data/app/views/action_auth/user_mailer/password_reset.text.erb +1 -1
- data/app/views/action_auth/webauthn_credential_authentications/new.html.erb +9 -3
- data/app/views/action_auth/webauthn_credentials/new.html.erb +10 -3
- data/app/views/layouts/action_auth/application.html.erb +2 -7
- data/config/routes.rb +13 -3
- data/db/migrate/20261105120000_add_magic_link_used_at_to_users.rb +5 -0
- data/db/migrate/20261105130000_add_account_lockout_and_suspension_to_users.rb +7 -0
- data/db/migrate/20261105130100_create_action_auth_connected_accounts.rb +19 -0
- data/lib/action_auth/configuration.rb +96 -0
- data/lib/action_auth/controllers/helpers.rb +44 -11
- data/lib/action_auth/engine.rb +27 -1
- data/lib/action_auth/routing/helpers.rb +8 -0
- data/lib/action_auth/version.rb +1 -1
- data/lib/generators/action_auth/views/USAGE +8 -0
- data/lib/generators/action_auth/views/views_generator.rb +59 -0
- data/lib/tasks/action_auth_tasks.rake +19 -1
- metadata +28 -5
|
@@ -1,17 +1,16 @@
|
|
|
1
|
+
<%= render "action_auth/shared/flash" %>
|
|
2
|
+
|
|
1
3
|
<h1>Reset your password</h1>
|
|
2
4
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
5
|
+
<% unless @user.verified? %>
|
|
6
|
+
<p>
|
|
7
|
+
This email address hasn't been verified yet, so resetting the password will also verify it and disconnect any
|
|
8
|
+
connected accounts.
|
|
9
|
+
</p>
|
|
10
|
+
<% end %>
|
|
7
11
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
<li><%= error.full_message %></li>
|
|
11
|
-
<% end %>
|
|
12
|
-
</ul>
|
|
13
|
-
</div>
|
|
14
|
-
<% end %>
|
|
12
|
+
<%= form_with(url: identity_password_reset_path, method: :patch) do |form| %>
|
|
13
|
+
<%= render "action_auth/shared/errors", record: @user %>
|
|
15
14
|
|
|
16
15
|
<%= form.hidden_field :sid, value: params[:sid] %>
|
|
17
16
|
|
|
@@ -1,10 +1,11 @@
|
|
|
1
|
+
<%= render "action_auth/shared/flash" %>
|
|
2
|
+
|
|
1
3
|
<h1>Forgot your password?</h1>
|
|
2
|
-
<p style="color: red"><%= alert %></p>
|
|
3
4
|
|
|
4
5
|
<%= form_with(url: identity_password_reset_path) do |form| %>
|
|
5
6
|
<div class="mb-3">
|
|
6
7
|
<%= form.label :email, style: "display: block" %>
|
|
7
|
-
<%= form.email_field :email, required: true, autofocus: true %>
|
|
8
|
+
<%= form.email_field :email, required: true, autofocus: true, autocomplete: "email" %>
|
|
8
9
|
</div>
|
|
9
10
|
|
|
10
11
|
<div class="mb-3">
|
|
@@ -12,10 +13,4 @@
|
|
|
12
13
|
</div>
|
|
13
14
|
<% end %>
|
|
14
15
|
|
|
15
|
-
|
|
16
|
-
<%= link_to "Sign In", sign_in_path %>
|
|
17
|
-
| <%= link_to "Sign Up", sign_up_path %>
|
|
18
|
-
<% if ActionAuth.configuration.verify_email_on_sign_in %>
|
|
19
|
-
| <%= link_to "Verify Email", identity_email_verification_path %>
|
|
20
|
-
<% end %>
|
|
21
|
-
</div>
|
|
16
|
+
<%= render "action_auth/shared/links" %>
|
|
@@ -1,26 +1,16 @@
|
|
|
1
|
+
<%= render "action_auth/shared/flash" %>
|
|
2
|
+
|
|
1
3
|
<h1>Request Magic Link</h1>
|
|
2
4
|
|
|
3
5
|
<%= form_with(url: magics_requests_path) do |form| %>
|
|
4
6
|
<div class="mb-3">
|
|
5
7
|
<%= form.label :email, style: "display: block" %>
|
|
6
|
-
<%= form.email_field :email, required: true, autofocus: true, autocomplete: "email" %>
|
|
8
|
+
<%= form.email_field :email, value: params[:email], required: true, autofocus: true, autocomplete: "email" %>
|
|
7
9
|
</div>
|
|
8
10
|
|
|
9
11
|
<div class="mb-3">
|
|
10
12
|
<%= form.submit "Request Magic Link", class: "btn btn-primary" %>
|
|
11
|
-
<span class="mx-3">or</span>
|
|
12
|
-
<%= link_to "Sign In", sign_in_path %>
|
|
13
|
-
<% if ActionAuth.configuration.passkey_only? %>
|
|
14
|
-
<span class="mx-3">or</span>
|
|
15
|
-
<%= link_to "Passkey", new_sessions_passkey_path %>
|
|
16
|
-
<% end %>
|
|
17
13
|
</div>
|
|
18
14
|
<% end %>
|
|
19
15
|
|
|
20
|
-
|
|
21
|
-
<%= link_to "Sign Up", sign_up_path %> |
|
|
22
|
-
<%= link_to "Reset Password", new_identity_password_reset_path %>
|
|
23
|
-
<% if ActionAuth.configuration.verify_email_on_sign_in %>
|
|
24
|
-
| <%= link_to "Verify Email", identity_email_verification_path %>
|
|
25
|
-
<% end %>
|
|
26
|
-
</div>
|
|
16
|
+
<%= render "action_auth/shared/links" %>
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
<%= render "action_auth/shared/flash" %>
|
|
2
|
+
|
|
3
|
+
<h1>Sign in</h1>
|
|
4
|
+
|
|
5
|
+
<p>You're signing in as <strong><%= @user.email %></strong>. This link only works once.</p>
|
|
6
|
+
|
|
7
|
+
<%# Worded for both people who see it, who look the same from here: someone who chose a
|
|
8
|
+
password before verifying, and someone who has never had one. It's said here rather
|
|
9
|
+
than after signing in, because the app's own page may not display flash messages. %>
|
|
10
|
+
<% unless @user.verified? %>
|
|
11
|
+
<p>
|
|
12
|
+
This email address hasn't been verified yet, so signing in will also replace any password set on this account,
|
|
13
|
+
sign out its other devices and disconnect any connected accounts. You can choose a new password afterwards with
|
|
14
|
+
Reset Password.
|
|
15
|
+
</p>
|
|
16
|
+
<% end %>
|
|
17
|
+
|
|
18
|
+
<%= button_to "Sign in", magics_sign_ins_path, params: { token: params[:token] }, class: "btn btn-primary" %>
|
|
@@ -1,43 +1,31 @@
|
|
|
1
|
-
|
|
1
|
+
<%= render "action_auth/shared/flash" %>
|
|
2
2
|
|
|
3
3
|
<h1>Change your password</h1>
|
|
4
4
|
|
|
5
5
|
<%= form_with(url: password_path, method: :patch) do |form| %>
|
|
6
|
-
|
|
7
|
-
<div style="color: red">
|
|
8
|
-
<h2><%= pluralize(@user.errors.count, "error") %> prohibited this user from being saved:</h2>
|
|
6
|
+
<%= render "action_auth/shared/errors", record: @user %>
|
|
9
7
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
<li><%= error.full_message %></li>
|
|
13
|
-
<% end %>
|
|
14
|
-
</ul>
|
|
15
|
-
</div>
|
|
16
|
-
<% end %>
|
|
17
|
-
|
|
18
|
-
<div>
|
|
19
|
-
<%= form.label :password_challenge, style: "display: block" %>
|
|
8
|
+
<div class="mb-3">
|
|
9
|
+
<%= form.label :password_challenge, "Current password", style: "display: block" %>
|
|
20
10
|
<%= form.password_field :password_challenge, required: true, autofocus: true, autocomplete: "current-password" %>
|
|
21
11
|
</div>
|
|
22
12
|
|
|
23
|
-
<div>
|
|
13
|
+
<div class="mb-3">
|
|
24
14
|
<%= form.label :password, "New password", style: "display: block" %>
|
|
25
15
|
<%= form.password_field :password, required: true, autocomplete: "new-password" %>
|
|
26
16
|
<div>12 characters minimum.</div>
|
|
27
17
|
</div>
|
|
28
18
|
|
|
29
|
-
<div>
|
|
19
|
+
<div class="mb-3">
|
|
30
20
|
<%= form.label :password_confirmation, "Confirm new password", style: "display: block" %>
|
|
31
21
|
<%= form.password_field :password_confirmation, required: true, autocomplete: "new-password" %>
|
|
32
22
|
</div>
|
|
33
23
|
|
|
34
|
-
<div>
|
|
35
|
-
<%= form.submit "Save changes" %>
|
|
24
|
+
<div class="mb-3">
|
|
25
|
+
<%= form.submit "Save changes", class: "btn btn-primary" %>
|
|
36
26
|
</div>
|
|
37
27
|
<% end %>
|
|
38
28
|
|
|
39
|
-
<br>
|
|
40
|
-
|
|
41
29
|
<div>
|
|
42
|
-
<%= link_to "Back",
|
|
30
|
+
<%= link_to "Back", sessions_path %>
|
|
43
31
|
</div>
|
|
@@ -1,17 +1,9 @@
|
|
|
1
|
+
<%= render "action_auth/shared/flash" %>
|
|
2
|
+
|
|
1
3
|
<h1>Sign up</h1>
|
|
2
4
|
|
|
3
5
|
<%= form_with(url: sign_up_path) do |form| %>
|
|
4
|
-
|
|
5
|
-
<div style="color: red">
|
|
6
|
-
<h2><%= pluralize(@user.errors.count, "error") %> prohibited this user from being saved:</h2>
|
|
7
|
-
|
|
8
|
-
<ul>
|
|
9
|
-
<% @user.errors.each do |error| %>
|
|
10
|
-
<li><%= error.full_message %></li>
|
|
11
|
-
<% end %>
|
|
12
|
-
</ul>
|
|
13
|
-
</div>
|
|
14
|
-
<% end %>
|
|
6
|
+
<%= render "action_auth/shared/errors", record: @user %>
|
|
15
7
|
|
|
16
8
|
<div class="mb-3">
|
|
17
9
|
<%= form.label :email, style: "display: block" %>
|
|
@@ -34,19 +26,5 @@
|
|
|
34
26
|
</div>
|
|
35
27
|
<% end %>
|
|
36
28
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
<% if ActionAuth.configuration.magic_link_enabled? %>
|
|
40
|
-
<%= link_to "Magic Link", new_magics_requests_path %> |
|
|
41
|
-
<% end %>
|
|
42
|
-
<% if ActionAuth.configuration.sms_auth_enabled? %>
|
|
43
|
-
<%= link_to "SMS Auth", new_sms_auths_requests_path %> |
|
|
44
|
-
<% end %>
|
|
45
|
-
<% if ActionAuth.configuration.passkey_only? %>
|
|
46
|
-
<%= link_to "Passkey", new_sessions_passkey_path %> |
|
|
47
|
-
<% end %>
|
|
48
|
-
<%= link_to "Reset Password", new_identity_password_reset_path %>
|
|
49
|
-
<% if ActionAuth.configuration.verify_email_on_sign_in %>
|
|
50
|
-
| <%= link_to "Verify Email", identity_email_verification_path %>
|
|
51
|
-
<% end %>
|
|
52
|
-
</div>
|
|
29
|
+
<%= render "action_auth/shared/oauth_buttons" %>
|
|
30
|
+
<%= render "action_auth/shared/links" %>
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
<h2>Account</h2>
|
|
2
|
+
<%# Both of these ask for the current password, which a placeholder account can't know. %>
|
|
3
|
+
<% if ActionAuth::Current.user.password_usable? %>
|
|
4
|
+
<div class="mb-3">
|
|
5
|
+
<%= link_to "Change email", edit_identity_email_path %> |
|
|
6
|
+
<%= link_to "Change password", edit_password_path %>
|
|
7
|
+
</div>
|
|
8
|
+
<% end %>
|
|
9
|
+
|
|
10
|
+
<% if ActionAuth.configuration.allow_user_deletion? %>
|
|
11
|
+
<details class="mb-3">
|
|
12
|
+
<summary>Delete account</summary>
|
|
13
|
+
<p>This permanently deletes your account and signs you out everywhere. It can't be undone.</p>
|
|
14
|
+
|
|
15
|
+
<% if ActionAuth::Current.user.password_usable? %>
|
|
16
|
+
<%= form_with(url: users_path, method: :delete) do |form| %>
|
|
17
|
+
<div class="mb-3">
|
|
18
|
+
<%= form.label :password_challenge, "Current password", style: "display: block" %>
|
|
19
|
+
<%= form.password_field :password_challenge, required: true, autocomplete: "current-password" %>
|
|
20
|
+
<div>Don't know your password? <%= link_to "Reset it", new_identity_password_reset_path %> first.</div>
|
|
21
|
+
</div>
|
|
22
|
+
|
|
23
|
+
<%= form.submit "Permanently delete my account", class: "btn btn-danger" %>
|
|
24
|
+
<% end %>
|
|
25
|
+
<% else %>
|
|
26
|
+
<p>To confirm it's you, this only works within 10 minutes of signing in with <%= ActionAuth::Current.user.fresh_sign_in_method %>.</p>
|
|
27
|
+
<%= button_to "Permanently delete my account", users_path, method: :delete, class: "btn btn-danger" %>
|
|
28
|
+
<% end %>
|
|
29
|
+
</details>
|
|
30
|
+
<% end %>
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
<% connected_accounts = current_user.connected_accounts.order(:created_at).to_a %>
|
|
2
|
+
|
|
3
|
+
<h2>Connected Accounts</h2>
|
|
4
|
+
|
|
5
|
+
<% if connected_accounts.any? %>
|
|
6
|
+
<table class="action-auth--table">
|
|
7
|
+
<thead>
|
|
8
|
+
<tr>
|
|
9
|
+
<th>Provider</th>
|
|
10
|
+
<th>Account</th>
|
|
11
|
+
<th nowrap>Connected On</th>
|
|
12
|
+
<th nowrap></th>
|
|
13
|
+
</tr>
|
|
14
|
+
</thead>
|
|
15
|
+
<tbody>
|
|
16
|
+
<% connected_accounts.each do |connected_account| %>
|
|
17
|
+
<%= content_tag :tr, id: dom_id(connected_account) do %>
|
|
18
|
+
<td><%= connected_account.provider_label %></td>
|
|
19
|
+
<td><%= connected_account.display_name %></td>
|
|
20
|
+
<td nowrap><%= connected_account.created_at.strftime('%B %d, %Y') %></td>
|
|
21
|
+
<td nowrap><%= button_to "Disconnect", connected_account_path(connected_account), method: :delete, class: "btn btn-primary" %></td>
|
|
22
|
+
<% end %>
|
|
23
|
+
<% end %>
|
|
24
|
+
</tbody>
|
|
25
|
+
</table>
|
|
26
|
+
<% end %>
|
|
27
|
+
|
|
28
|
+
<% ActionAuth.configuration.oauth_providers.reject { |oauth| connected_accounts.any? { |account| account.provider == oauth.key } }.each do |oauth| %>
|
|
29
|
+
<div class="mb-3">
|
|
30
|
+
<%= button_to "Connect #{oauth.label}", oauth_request_path(oauth.key), form: { data: { turbo: false } }, class: "btn btn-primary" %>
|
|
31
|
+
</div>
|
|
32
|
+
<% end %>
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
<% if current_user.second_factor_enabled? %>
|
|
2
|
+
<h2>Your Security Keys</h2>
|
|
3
|
+
<table class="action-auth--table">
|
|
4
|
+
<thead>
|
|
5
|
+
<tr>
|
|
6
|
+
<th>Key</th>
|
|
7
|
+
<th>Type</th>
|
|
8
|
+
<th nowrap>Registered On</th>
|
|
9
|
+
<th nowrap></th>
|
|
10
|
+
</tr>
|
|
11
|
+
</thead>
|
|
12
|
+
<tbody>
|
|
13
|
+
<% current_user.webauthn_credentials.each do |credential| %>
|
|
14
|
+
<%= content_tag :tr, id: dom_id(credential) do %>
|
|
15
|
+
<td><%= credential.nickname %></td>
|
|
16
|
+
<td><%= credential.key_type %></td>
|
|
17
|
+
<td nowrap><%= credential.created_at.strftime('%B %d, %Y') %></td>
|
|
18
|
+
<td nowrap><%= button_to "Delete", credential, method: :delete, class: "btn btn-primary" %></td>
|
|
19
|
+
<% end %>
|
|
20
|
+
<% end %>
|
|
21
|
+
</tbody>
|
|
22
|
+
</table>
|
|
23
|
+
|
|
24
|
+
<div class="mb-3">
|
|
25
|
+
<%= link_to "Register new Security Key", new_webauthn_credential_path, class: "btn btn-primary" %>
|
|
26
|
+
</div>
|
|
27
|
+
<% else %>
|
|
28
|
+
<h2>Enable Two-Factor Authentication</h2>
|
|
29
|
+
<div class="mb-3">
|
|
30
|
+
<%= link_to "Add a passkey", new_webauthn_credential_path, class: "btn btn-primary" %>
|
|
31
|
+
</div>
|
|
32
|
+
<% end %>
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
<h2>Sessions</h2>
|
|
2
|
+
<div id="sessions">
|
|
3
|
+
<table class="action-auth--table">
|
|
4
|
+
<thead>
|
|
5
|
+
<tr>
|
|
6
|
+
<th>User Agent</th>
|
|
7
|
+
<th nowrap>Ip Address</th>
|
|
8
|
+
<th nowrap>Created at</th>
|
|
9
|
+
<th nowrap></th>
|
|
10
|
+
</tr>
|
|
11
|
+
</thead>
|
|
12
|
+
<tbody>
|
|
13
|
+
<% sessions.each do |session| %>
|
|
14
|
+
<%= content_tag :tr, id: dom_id(session) do %>
|
|
15
|
+
<td>
|
|
16
|
+
<%= session.user_agent %>
|
|
17
|
+
<% if session == current_session %>
|
|
18
|
+
<strong>(this device)</strong>
|
|
19
|
+
<% end %>
|
|
20
|
+
</td>
|
|
21
|
+
<td nowrap><%= session.ip_address %></td>
|
|
22
|
+
<td><%= session.created_at %></td>
|
|
23
|
+
<td><%= button_to "Log out", session, method: :delete, class: "btn btn-primary" %></td>
|
|
24
|
+
<% end %>
|
|
25
|
+
<% end %>
|
|
26
|
+
</tbody>
|
|
27
|
+
</table>
|
|
28
|
+
</div>
|
|
@@ -1,68 +1,16 @@
|
|
|
1
|
-
|
|
1
|
+
<%= render "action_auth/shared/flash" %>
|
|
2
2
|
|
|
3
|
-
<h1>
|
|
4
|
-
|
|
5
|
-
</h1>
|
|
6
|
-
<small><%= link_to "back to app", main_app.root_path %></small>
|
|
3
|
+
<h1>Devices & Sessions</h1>
|
|
4
|
+
<small><%= link_to "back to app", after_sign_in_path %></small>
|
|
7
5
|
|
|
8
|
-
|
|
9
|
-
<div id="sessions">
|
|
10
|
-
<table class="action-auth--table">
|
|
11
|
-
<thead>
|
|
12
|
-
<tr>
|
|
13
|
-
<th>User Agent</th>
|
|
14
|
-
<th nowrap>Ip Address</th>
|
|
15
|
-
<th nowrap>Created at</th>
|
|
16
|
-
<th nowrap></th>
|
|
17
|
-
</tr>
|
|
18
|
-
</thead>
|
|
19
|
-
<tbody>
|
|
20
|
-
<% @sessions.each do |session| %>
|
|
21
|
-
<%= content_tag :tr, id: dom_id(session) do %>
|
|
22
|
-
<td><%= session.user_agent %></td>
|
|
23
|
-
<td nowrap><%= session.ip_address %></td>
|
|
24
|
-
<td><%= session.created_at %></td>
|
|
25
|
-
<td><%= button_to "Log out", session, method: :delete, class: "btn btn-primary" %></td>
|
|
26
|
-
<% end %>
|
|
27
|
-
<% end %>
|
|
28
|
-
</tbody>
|
|
29
|
-
</table>
|
|
30
|
-
</div>
|
|
6
|
+
<%= render "action_auth/sessions/sessions", sessions: @sessions %>
|
|
31
7
|
|
|
32
8
|
<% if ActionAuth.configuration.webauthn_enabled? %>
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
<table class="action-auth--table">
|
|
36
|
-
<thead>
|
|
37
|
-
<tr>
|
|
38
|
-
<th>Key</th>
|
|
39
|
-
<th>Type</th>
|
|
40
|
-
<th nowrap>Registered On</th>
|
|
41
|
-
<th nowrap></th>
|
|
42
|
-
</tr>
|
|
43
|
-
</thead>
|
|
44
|
-
<tbody>
|
|
45
|
-
<% current_user.webauthn_credentials.each do |credential| %>
|
|
46
|
-
<%= content_tag :tr, id: dom_id(credential) do %>
|
|
47
|
-
<td><%= credential.nickname %></td>
|
|
48
|
-
<td><%= credential.key_type %></td>
|
|
49
|
-
<td nowrap><%= credential.created_at.strftime('%B %d, %Y') %></td>
|
|
50
|
-
<td nowrap><%= button_to "Delete", credential, method: :delete, class: "btn btn-primary" %></td>
|
|
51
|
-
<% end %>
|
|
52
|
-
<% end %>
|
|
53
|
-
</tbody>
|
|
54
|
-
</table>
|
|
9
|
+
<%= render "action_auth/sessions/security_keys" %>
|
|
10
|
+
<% end %>
|
|
55
11
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
new_webauthn_credential_path,
|
|
59
|
-
method: :get,
|
|
60
|
-
class: "btn btn-primary") %>
|
|
61
|
-
</div>
|
|
62
|
-
<% else %>
|
|
63
|
-
<h2>Enable Two-Factor Authentication</h2>
|
|
64
|
-
<div class="">
|
|
65
|
-
<%= link_to "Add a passkey", new_webauthn_credential_path, class: "btn btn-primary" %>
|
|
66
|
-
</div>
|
|
67
|
-
<% end %>
|
|
12
|
+
<% if ActionAuth.configuration.oauth_enabled? && ActionAuth::ConnectedAccount.table_exists? %>
|
|
13
|
+
<%= render "action_auth/sessions/connected_accounts" %>
|
|
68
14
|
<% end %>
|
|
15
|
+
|
|
16
|
+
<%= render "action_auth/sessions/account" %>
|
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
<p style="color: red"><%= alert %></p>
|
|
1
|
+
<%= render "action_auth/shared/flash" %>
|
|
3
2
|
|
|
4
3
|
<h1>Sign in</h1>
|
|
5
4
|
|
|
@@ -16,25 +15,8 @@
|
|
|
16
15
|
|
|
17
16
|
<div class="mb-3">
|
|
18
17
|
<%= form.submit "Sign in", class: "btn btn-primary" %>
|
|
19
|
-
<% if ActionAuth.configuration.magic_link_enabled? %>
|
|
20
|
-
<span class="mx-3">or</span>
|
|
21
|
-
<%= link_to "Magic Link", new_magics_requests_path %>
|
|
22
|
-
<% end %>
|
|
23
|
-
<% if ActionAuth.configuration.sms_auth_enabled? %>
|
|
24
|
-
<span class="mx-3">or</span>
|
|
25
|
-
<%= link_to "SMS Auth", new_sms_auths_requests_path %> |
|
|
26
|
-
<% end %>
|
|
27
|
-
<% if ActionAuth.configuration.passkey_only? %>
|
|
28
|
-
<span class="mx-3">or</span>
|
|
29
|
-
<%= link_to "Passkey", new_sessions_passkey_path %>
|
|
30
|
-
<% end %>
|
|
31
18
|
</div>
|
|
32
19
|
<% end %>
|
|
33
20
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
<%= link_to "Reset Password", new_identity_password_reset_path %>
|
|
37
|
-
<% if ActionAuth.configuration.verify_email_on_sign_in %>
|
|
38
|
-
| <%= link_to "Verify Email", identity_email_verification_path %>
|
|
39
|
-
<% end %>
|
|
40
|
-
</div>
|
|
21
|
+
<%= render "action_auth/shared/oauth_buttons" %>
|
|
22
|
+
<%= render "action_auth/shared/links" %>
|
|
@@ -1,5 +1,11 @@
|
|
|
1
|
+
<%= render "action_auth/shared/flash" %>
|
|
2
|
+
|
|
3
|
+
<%= action_auth_webauthn_tags %>
|
|
4
|
+
<%= tag.meta name: "passkey_auth_url", content: sessions_passkeys_url %>
|
|
5
|
+
|
|
1
6
|
<h2 class="action-auth--text-center">Use a passkey to sign in</h2>
|
|
2
|
-
|
|
7
|
+
|
|
8
|
+
<%= render "action_auth/shared/webauthn_error" %>
|
|
3
9
|
|
|
4
10
|
<%= content_tag :div,
|
|
5
11
|
id: "webauthn_credential_form",
|
|
@@ -15,6 +21,6 @@
|
|
|
15
21
|
</div>
|
|
16
22
|
<% end %>
|
|
17
23
|
|
|
18
|
-
|
|
19
|
-
<%= link_to "Cancel",
|
|
20
|
-
|
|
24
|
+
<div class="action-auth--text-center">
|
|
25
|
+
<%= link_to "Cancel", sign_in_path %>
|
|
26
|
+
</div>
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
<% if record&.errors&.any? %>
|
|
2
|
+
<div class="action-auth--errors" role="alert">
|
|
3
|
+
<h2><%= pluralize(record.errors.count, "error") %> prohibited this user from being saved:</h2>
|
|
4
|
+
<ul>
|
|
5
|
+
<% record.errors.each do |error| %>
|
|
6
|
+
<li><%= error.full_message %></li>
|
|
7
|
+
<% end %>
|
|
8
|
+
</ul>
|
|
9
|
+
</div>
|
|
10
|
+
<% end %>
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
<%# Shown here rather than in the layout so that messages appear in any layout, and
|
|
2
|
+
removed once shown so that a layout which also displays flash doesn't repeat
|
|
3
|
+
them. To use your layout's own flash instead, make this partial empty. %>
|
|
4
|
+
<% if notice.present? %>
|
|
5
|
+
<p class="action-auth--notice" role="status"><%= notice %></p>
|
|
6
|
+
<% end %>
|
|
7
|
+
<% if alert.present? %>
|
|
8
|
+
<p class="action-auth--alert" role="alert"><%= alert %></p>
|
|
9
|
+
<% end %>
|
|
10
|
+
<% flash.delete(:notice) %>
|
|
11
|
+
<% flash.delete(:alert) %>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<p id="webauthn_error" class="action-auth--alert" role="alert" hidden></p>
|
|
@@ -1,26 +1,16 @@
|
|
|
1
|
+
<%= render "action_auth/shared/flash" %>
|
|
2
|
+
|
|
1
3
|
<h1>Request SMS Code</h1>
|
|
2
4
|
|
|
3
5
|
<%= form_with(url: sms_auths_requests_path) do |form| %>
|
|
4
6
|
<div class="mb-3">
|
|
5
7
|
<%= form.label :phone_number, style: "display: block" %>
|
|
6
|
-
<%= form.telephone_field :phone_number, required: true, autofocus: true, autocomplete: "
|
|
8
|
+
<%= form.telephone_field :phone_number, value: params[:phone_number], required: true, autofocus: true, autocomplete: "tel" %>
|
|
7
9
|
</div>
|
|
8
10
|
|
|
9
11
|
<div class="mb-3">
|
|
10
12
|
<%= form.submit "Request SMS Code", class: "btn btn-primary" %>
|
|
11
|
-
<span class="mx-3">or</span>
|
|
12
|
-
<%= link_to "Sign In", sign_in_path %>
|
|
13
|
-
<% if ActionAuth.configuration.passkey_only? %>
|
|
14
|
-
<span class="mx-3">or</span>
|
|
15
|
-
<%= link_to "Passkey", new_sessions_passkey_path %>
|
|
16
|
-
<% end %>
|
|
17
13
|
</div>
|
|
18
14
|
<% end %>
|
|
19
15
|
|
|
20
|
-
|
|
21
|
-
<%= link_to "Sign Up", sign_up_path %> |
|
|
22
|
-
<%= link_to "Reset Password", new_identity_password_reset_path %>
|
|
23
|
-
<% if ActionAuth.configuration.verify_email_on_sign_in %>
|
|
24
|
-
| <%= link_to "Verify Email", identity_email_verification_path %>
|
|
25
|
-
<% end %>
|
|
26
|
-
</div>
|
|
16
|
+
<%= render "action_auth/shared/links" %>
|
|
@@ -1,10 +1,11 @@
|
|
|
1
|
+
<%= render "action_auth/shared/flash" %>
|
|
2
|
+
|
|
1
3
|
<h1>Verify SMS Code</h1>
|
|
2
4
|
|
|
3
5
|
<%= form_with(url: sms_auths_sign_ins_path) do |form| %>
|
|
4
|
-
<%= form.hidden_field :phone_number, value: cookies.signed[:sms_auth_phone_number] %>
|
|
5
6
|
<div class="mb-3">
|
|
6
7
|
<%= form.label :sms_code, style: "display: block" %>
|
|
7
|
-
<%= form.
|
|
8
|
+
<%= form.text_field :sms_code, required: true, autofocus: true, autocomplete: "one-time-code", inputmode: "numeric" %>
|
|
8
9
|
</div>
|
|
9
10
|
|
|
10
11
|
<div class="mb-3">
|
|
@@ -12,3 +13,6 @@
|
|
|
12
13
|
</div>
|
|
13
14
|
<% end %>
|
|
14
15
|
|
|
16
|
+
<div>
|
|
17
|
+
<%= link_to "Send a new code", new_sms_auths_requests_path %>
|
|
18
|
+
</div>
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
<p>Hey there,</p>
|
|
2
|
+
|
|
3
|
+
<p>
|
|
4
|
+
There have been too many failed attempts to sign in to <strong><%= @user.email %></strong>,
|
|
5
|
+
so we've locked sign in with a password<% if @duration %> for the next <%= distance_of_time_in_words(@duration) %><% end %>.
|
|
6
|
+
</p>
|
|
7
|
+
|
|
8
|
+
<p>
|
|
9
|
+
If that was you, you can get back in now by
|
|
10
|
+
<%= link_to "resetting your password", new_identity_password_reset_url %>.
|
|
11
|
+
</p>
|
|
12
|
+
|
|
13
|
+
<p>
|
|
14
|
+
If it wasn't, someone may be trying to guess your password. Those attempts failed,
|
|
15
|
+
and devices you're already signed in on aren't affected. Consider changing
|
|
16
|
+
your password if you use it anywhere else.
|
|
17
|
+
</p>
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
Hey there,
|
|
2
|
+
|
|
3
|
+
There have been too many failed attempts to sign in to <%= @user.email %>,
|
|
4
|
+
so we've locked sign in with a password<% if @duration %> for the next <%= distance_of_time_in_words(@duration) %><% end %>.
|
|
5
|
+
|
|
6
|
+
If that was you, you can get back in now by resetting your password:
|
|
7
|
+
|
|
8
|
+
<%= new_identity_password_reset_url %>
|
|
9
|
+
|
|
10
|
+
If it wasn't, someone may be trying to guess your password. Those attempts failed,
|
|
11
|
+
and devices you're already signed in on aren't affected. Consider changing
|
|
12
|
+
your password if you use it anywhere else.
|
|
@@ -7,3 +7,6 @@ that's where we'll email a reset link.
|
|
|
7
7
|
You must click the link below to confirm that you received this email.
|
|
8
8
|
|
|
9
9
|
<%= identity_email_verification_url(sid: @signed_id) %>
|
|
10
|
+
|
|
11
|
+
You'll be asked for your password. If you didn't sign up, you can safely ignore
|
|
12
|
+
this email and nothing will change.
|