action_auth 0.1.1 → 0.1.3

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 45ce58405d5a45e6c9bf204378b2d187b468285401d889fe9e8323ce9649e345
4
- data.tar.gz: 1e94b9b8e23d211d93ce96f8ff1e4ea1f6b816ca0ed9de8144b72a03273a7de7
3
+ metadata.gz: d680d8d34330e5aec31d3ab30576b677f4b3320c9cb9383b0a2ea2d5369c4541
4
+ data.tar.gz: 6c5d816b40895ec52e7b6ec331127263e5e82a80b6e838a6fd1e047366de1ea5
5
5
  SHA512:
6
- metadata.gz: 889f0be20c9e05507bfa12035ce2c06254b751161191bf3e1ae99eaba39643bbbb7b995a94b74dc4ba6453350e8201ae5265f938caaf50a85a149eae975e9a30
7
- data.tar.gz: caecc465fce527d29225ab23ef7cc33c6cd992496864e5a224ab426a3a81378c2290a020b83dff6053c2f159d4bf9d8c579b9033ab48db8990b4796bacd024ab
6
+ metadata.gz: 19e8c186624ccf06148d16932b6026143560479594d07e2bed4298f4c18b83df65a17e1ee88149c7fc6a9b0a1b1afbebc4a95023cebee81d15d393bbe984f6c1
7
+ data.tar.gz: 27e0a47e5cc73e646bacb873610a514211fc0bbd471d38776da5af2f419a73d85da135998a452a041e0ae3871fb4cec983204297923b274b98b6cd80fa256c36
data/README.md CHANGED
@@ -1,5 +1,9 @@
1
1
  # ActionAuth
2
- This is a placeholder for the ActionAuth gem. It is not yet ready for use.
2
+ ActionAuth is a Rails engine that provides a simple authentication system for your Rails application.
3
+ It uses the latest methods for authentication and handling reset tokens from Rails 7.1.0.
4
+ It is designed to be simple and easy to use and allows you to focus on building your application.
5
+ The functionality of this gem relies on ActiveSupport::CurrentAttributes the methods are
6
+ designed to have a similar experience as Devise.
3
7
 
4
8
  ## Installation
5
9
  Add this line to your application's Gemfile:
@@ -8,6 +12,25 @@ Add this line to your application's Gemfile:
8
12
  bundle add action_auth
9
13
  bin/rails action_auth:install:migrations
10
14
  ```
15
+
16
+ Modify config/routes.rb to include the following:
17
+
18
+ ```ruby
19
+ mount ActionAuth::Engine => 'action_auth'
20
+ ```
21
+
22
+ In your view layout
23
+
24
+ ```ruby
25
+ <% if user_signed_in? %>
26
+ <li><%= link_to "Sessions", user_sessions_path %></li>
27
+ <li><%= button_to "Sign Out", user_session_path(current_session), method: :delete %></li>
28
+ <% else %>
29
+ <li><%= link_to "Sign In", new_user_session_path %></li>
30
+ <li><%= link_to "Sign Up", new_user_registration_path %></li>
31
+ <% end %>
32
+ ```
33
+
11
34
  ## Usage
12
35
 
13
36
  ### Routes
@@ -15,18 +38,19 @@ bin/rails action_auth:install:migrations
15
38
  Within your application, you'll have access to these routes. They have been styled to be consistent with Devise.
16
39
 
17
40
  Method Verb Params Description
18
- user_sessions_path GET Device session management
19
- user_session_path DELETE [:id] Log Out
20
- new_user_session_path GET Log in
21
- new_user_registration_path GET Sign Up
41
+ user_sessions_path GET Device session management
42
+ user_session_path DELETE [:id] Log Out
43
+ new_user_session_path GET Log in
44
+ new_user_registration_path GET Sign Up
45
+ edit_password_path GET Change Password
46
+ password_path PATCH Update Password
22
47
 
23
48
  ### Helper Methods
24
49
 
25
50
  Method Description
26
- current_user Returns the currently logged in user
51
+ current_user Returns the currently logged in user
27
52
  user_signed_in? Returns true if the user is logged in
28
- current_session Returns the current session
29
-
53
+ current_session Returns the current session
30
54
 
31
55
  ## License
32
56
  The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
@@ -1,15 +1,101 @@
1
- /*
2
- * This is a manifest file that'll be compiled into application.css, which will include all the files
3
- * listed below.
4
- *
5
- * Any CSS and SCSS file within this directory, lib/assets/stylesheets, vendor/assets/stylesheets,
6
- * or any plugin's vendor/assets/stylesheets directory can be referenced here using a relative path.
7
- *
8
- * You're free to add application-wide styles to this file and they'll appear at the bottom of the
9
- * compiled file so the styles you add here take precedence over styles defined in any other CSS/SCSS
10
- * files in this directory. Styles in this file should be added after the last require_* statement.
11
- * It is generally better to create a new file per style scope.
12
- *
13
- *= require_tree .
14
- *= require_self
15
- */
1
+ body {
2
+ box-sizing: border-box;
3
+ margin: 0;
4
+ font-family: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", "Noto Sans", "Liberation Sans", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
5
+ font-size: 1rem;
6
+ font-weight: 400;
7
+ line-height: 1.5;
8
+ color: #212529;
9
+ text-align: left;
10
+ /* Assuming default alignment should be left */
11
+ -webkit-text-size-adjust: 100%;
12
+ -webkit-tap-highlight-color: rgba(0, 0, 0, 0);
13
+ margin-top: 25px;
14
+ background-color: rgb(248, 249, 250) !important;
15
+ }
16
+
17
+ .container {
18
+ -webkit-text-size-adjust: 100%;
19
+ -webkit-tap-highlight-color: rgba(0, 0, 0, 0);
20
+ box-sizing: border-box;
21
+ width: 400px;
22
+ padding-right: 12px;
23
+ padding-left: 12px;
24
+ margin-right: auto;
25
+ margin-left: auto;
26
+ max-width: 1140px;
27
+ border: solid 1px rgb(222, 226, 230) !important;
28
+ padding-bottom: 1rem !important;
29
+ background-color: rgb(255, 255, 255) !important;
30
+ }
31
+
32
+ input[type="text"],
33
+ input[type="email"],
34
+ input[type="password"] {
35
+ -webkit-text-size-adjust: 100%;
36
+ -webkit-tap-highlight-color: rgba(0, 0, 0, 0);
37
+ box-sizing: border-box;
38
+ margin: 0;
39
+ font-family: inherit;
40
+ display: block;
41
+ width: 100%;
42
+ padding: 0.375rem 0.75rem;
43
+ font-size: 1rem;
44
+ font-weight: 400;
45
+ line-height: 1.5;
46
+ color: #212529;
47
+ appearance: none;
48
+ background-color: #fff;
49
+ background-clip: padding-box;
50
+ border: 1px solid #dee2e6;
51
+ border-radius: 0.375rem;
52
+ transition: border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out;
53
+ }
54
+
55
+ .mb-3 {
56
+ margin-bottom: 1rem !important;
57
+ }
58
+
59
+ .btn {
60
+ padding: 0.375rem 0.75rem;
61
+ font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
62
+ font-size: 1rem;
63
+ font-weight: 400;
64
+ line-height: 1.5;
65
+ color: #333;
66
+ text-align: center;
67
+ text-decoration: none;
68
+ vertical-align: middle;
69
+ user-select: none;
70
+ border: 1px solid #007bff;
71
+ border-radius: 0.25rem;
72
+ background-color: #007bff;
73
+ box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.15), 0 1px 1px rgba(0, 0, 0, 0.075);
74
+ transition: color 0.15s ease-in-out, background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out;
75
+ cursor: pointer;
76
+ }
77
+
78
+ .btn:hover {
79
+ color: #fff;
80
+ background-color: #0056b3;
81
+ border-color: #004085;
82
+ }
83
+
84
+ .btn:focus {
85
+ outline: 0;
86
+ box-shadow: 0 0 0 0.25rem rgba(49, 132, 253, .5);
87
+ }
88
+
89
+ .btn:disabled {
90
+ color: #fff;
91
+ background-color: #007bff;
92
+ border-color: #007bff;
93
+ opacity: 0.65;
94
+ pointer-events: none;
95
+ }
96
+
97
+ .btn-primary {
98
+ color: #fff;
99
+ background-color: #007bff;
100
+ border-color: #007bff;
101
+ }
@@ -0,0 +1,30 @@
1
+ module ActionAuth
2
+ module Identity
3
+ class EmailVerificationsController < ApplicationController
4
+ before_action :set_user, only: :show
5
+
6
+ def show
7
+ @user.update! verified: true
8
+ redirect_to main_app.root_path, notice: "Thank you for verifying your email address"
9
+ end
10
+
11
+ def create
12
+ send_email_verification
13
+ redirect_to main_app.root_path, notice: "We sent a verification email to your email address"
14
+ end
15
+
16
+ private
17
+
18
+ def set_user
19
+ @user = ActionAuth::User.find_by_token_for!(:email_verification, params[:sid])
20
+ rescue StandardError
21
+ redirect_to edit_identity_email_path, alert: "That email verification link is invalid"
22
+ end
23
+
24
+ def send_email_verification
25
+ return unless Current.user
26
+ UserMailer.with(user: Current.user).email_verification.deliver_later
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,41 @@
1
+ module ActionAuth
2
+ module Identity
3
+ class EmailsController < ApplicationController
4
+ before_action :set_user
5
+
6
+ def edit
7
+ end
8
+
9
+ def update
10
+ if @user.update(user_params)
11
+ redirect_to_root
12
+ else
13
+ render :edit, status: :unprocessable_entity
14
+ end
15
+ end
16
+
17
+ private
18
+
19
+ def set_user
20
+ @user = Current.user
21
+ end
22
+
23
+ def user_params
24
+ params.permit(:email, :password_challenge).with_defaults(password_challenge: "")
25
+ end
26
+
27
+ def redirect_to_root
28
+ if @user.email_previously_changed?
29
+ resend_email_verification
30
+ redirect_to main_app.root_path, notice: "Your email has been changed"
31
+ else
32
+ redirect_to main_app.root_path
33
+ end
34
+ end
35
+
36
+ def resend_email_verification
37
+ UserMailer.with(user: @user).email_verification.deliver_later
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,46 @@
1
+ module ActionAuth
2
+ module Identity
3
+ class PasswordResetsController < ApplicationController
4
+ before_action :set_user, only: %i[ edit update ]
5
+
6
+ def new
7
+ end
8
+
9
+ def edit
10
+ end
11
+
12
+ def create
13
+ if @user = ActionAuth::User.find_by(email: params[:email], verified: true)
14
+ send_password_reset_email
15
+ redirect_to sign_in_path, notice: "Check your email for reset instructions"
16
+ else
17
+ redirect_to new_identity_password_reset_path, alert: "You can't reset your password until you verify your email"
18
+ end
19
+ end
20
+
21
+ def update
22
+ if @user.update(user_params)
23
+ redirect_to sign_in_path, notice: "Your password was reset successfully. Please sign in"
24
+ else
25
+ render :edit, status: :unprocessable_entity
26
+ end
27
+ end
28
+
29
+ private
30
+
31
+ def set_user
32
+ @user = ActionAuth::User.find_by_token_for!(:password_reset, params[:sid])
33
+ rescue StandardError
34
+ redirect_to new_identity_password_reset_path, alert: "That password reset link is invalid"
35
+ end
36
+
37
+ def user_params
38
+ params.permit(:password, :password_confirmation)
39
+ end
40
+
41
+ def send_password_reset_email
42
+ UserMailer.with(user: @user).password_reset.deliver_later
43
+ end
44
+ end
45
+ end
46
+ end
@@ -7,7 +7,7 @@ module ActionAuth
7
7
 
8
8
  def update
9
9
  if @user.update(user_params)
10
- redirect_to root_path, notice: "Your password has been changed"
10
+ redirect_to main_app.root_path, notice: "Your password has been changed"
11
11
  else
12
12
  render :edit, status: :unprocessable_entity
13
13
  end
@@ -7,7 +7,7 @@ module ActionAuth
7
7
  def create
8
8
  @user = User.new(user_params)
9
9
 
10
- if @user.save!
10
+ if @user.save
11
11
  session_record = @user.action_auth_sessions.create!
12
12
  cookies.signed.permanent[:session_token] = { value: session_record.id, httponly: true }
13
13
 
@@ -1,6 +1,7 @@
1
1
  module ActionAuth
2
2
  class SessionsController < ApplicationController
3
3
  before_action :set_current_request_details
4
+
4
5
  def index
5
6
  @sessions = Current.user.action_auth_sessions.order(created_at: :desc)
6
7
  end
@@ -0,0 +1,46 @@
1
+
2
+ <% if user_signed_in? && Current.user.verified? %>
3
+ <% header_text = "Change Your Email" %>
4
+ <% label_text = "New email" %>
5
+ <% button_text = "Save changes" %>
6
+ <% else %>
7
+ <% header_text = "Verify Your Email" %>
8
+ <% label_text = "Email" %>
9
+ <% button_text = "Send verification email" %>
10
+ <% end %>
11
+ <h1><%= header_text %></h1>
12
+
13
+ <p style="color: red"><%= alert %></p>
14
+
15
+ <%= form_with(url: identity_email_path, method: :patch) do |form| %>
16
+ <% if @user&.errors&.any? %>
17
+ <div style="color: red">
18
+ <h2><%= pluralize(@user.errors.count, "error") %> prohibited this user from being saved:</h2>
19
+ <ul>
20
+ <% @user.errors.each do |error| %>
21
+ <li><%= error.full_message %></li>
22
+ <% end %>
23
+ </ul>
24
+ </div>
25
+ <% end %>
26
+
27
+ <div class="mb-3">
28
+ <%= form.label :email, label_text, style: "display: block" %>
29
+ <%= form.email_field :email, required: true, autofocus: true %>
30
+ </div>
31
+
32
+ <div class="mb-3">
33
+ <% if user_signed_in? && Current.user.verified? %>
34
+ <%= form.submit button_text, class: "btn btn-primary" %>
35
+ <% else %>
36
+ <%= button_to button_text, identity_email_verification_path, class: "btn btn-primary" %>
37
+ <% end %>
38
+
39
+ </div>
40
+ <% end %>
41
+
42
+ <div class="mb-3">
43
+ <%= link_to "Sign In", sign_in_path %> |
44
+ <%= link_to "Sign Up", sign_up_path %> |
45
+ <%= link_to "Reset Password", new_identity_password_reset_path %>
46
+ </div>
@@ -0,0 +1,32 @@
1
+ <h1>Reset your password</h1>
2
+
3
+ <%= form_with(url: identity_password_reset_path, method: :patch) do |form| %>
4
+ <% if @user.errors.any? %>
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 %>
15
+
16
+ <%= form.hidden_field :sid, value: params[:sid] %>
17
+
18
+ <div>
19
+ <%= form.label :password, "New password", style: "display: block" %>
20
+ <%= form.password_field :password, required: true, autofocus: true, autocomplete: "new-password" %>
21
+ <div>12 characters minimum.</div>
22
+ </div>
23
+
24
+ <div>
25
+ <%= form.label :password_confirmation, "Confirm new password", style: "display: block" %>
26
+ <%= form.password_field :password_confirmation, required: true, autocomplete: "new-password" %>
27
+ </div>
28
+
29
+ <div>
30
+ <%= form.submit "Save changes" %>
31
+ </div>
32
+ <% end %>
@@ -0,0 +1,19 @@
1
+ <h1>Forgot your password?</h1>
2
+ <p style="color: red"><%= alert %></p>
3
+
4
+ <%= form_with(url: identity_password_reset_path) do |form| %>
5
+ <div class="mb-3">
6
+ <%= form.label :email, style: "display: block" %>
7
+ <%= form.email_field :email, required: true, autofocus: true %>
8
+ </div>
9
+
10
+ <div class="mb-3">
11
+ <%= form.submit "Send password reset email", class: "btn btn-primary" %>
12
+ </div>
13
+ <% end %>
14
+
15
+ <div class="mb-3">
16
+ <%= link_to "Sign In", sign_in_path %> |
17
+ <%= link_to "Sign Up", sign_up_path %> |
18
+ <%= link_to "Verify Email", identity_email_verification_path %>
19
+ </div>
@@ -39,5 +39,5 @@
39
39
  <br>
40
40
 
41
41
  <div>
42
- <%= link_to "Back", root_path %>
42
+ <%= link_to "Back", main_app.root_path %>
43
43
  </div>
@@ -13,23 +13,29 @@
13
13
  </div>
14
14
  <% end %>
15
15
 
16
- <div>
16
+ <div class="mb-3">
17
17
  <%= form.label :email, style: "display: block" %>
18
18
  <%= form.email_field :email, value: @user.email, required: true, autofocus: true, autocomplete: "email" %>
19
19
  </div>
20
20
 
21
- <div>
21
+ <div class="mb-3">
22
22
  <%= form.label :password, style: "display: block" %>
23
23
  <%= form.password_field :password, required: true, autocomplete: "new-password" %>
24
24
  <div>12 characters minimum.</div>
25
25
  </div>
26
26
 
27
- <div>
27
+ <div class="mb-3">
28
28
  <%= form.label :password_confirmation, style: "display: block" %>
29
29
  <%= form.password_field :password_confirmation, required: true, autocomplete: "new-password" %>
30
30
  </div>
31
31
 
32
- <div>
33
- <%= form.submit "Sign up" %>
32
+ <div class="mb-3">
33
+ <%= form.submit "Sign up", class: "btn btn-primary" %>
34
34
  </div>
35
35
  <% end %>
36
+
37
+ <div class="mb-3">
38
+ <%= link_to "Sign In", sign_in_path %> |
39
+ <%= link_to "Reset Password", new_identity_password_reset_path %> |
40
+ <%= link_to "Verify Email", identity_email_verification_path %>
41
+ </div>
@@ -4,27 +4,23 @@
4
4
  <h1>Sign in</h1>
5
5
 
6
6
  <%= form_with(url: sign_in_path) do |form| %>
7
- <div>
7
+ <div class="mb-3">
8
8
  <%= form.label :email, style: "display: block" %>
9
9
  <%= form.email_field :email, value: params[:email_hint], required: true, autofocus: true, autocomplete: "email" %>
10
10
  </div>
11
11
 
12
- <div>
12
+ <div class="mb-3">
13
13
  <%= form.label :password, style: "display: block" %>
14
14
  <%= form.password_field :password, required: true, autocomplete: "current-password" %>
15
15
  </div>
16
16
 
17
- <div>
18
- <%= form.submit "Sign in" %>
17
+ <div class="mb-3">
18
+ <%= form.submit "Sign in", class: "btn btn-primary" %>
19
19
  </div>
20
20
  <% end %>
21
21
 
22
- <br>
23
-
24
-
25
- <br>
26
-
27
- <div>
28
- <%= link_to "Sign up", sign_up_path %> |
29
- <%# link_to "Forgot your password?", new_identity_password_reset_path %>
22
+ <div class="mb-3">
23
+ <%= link_to "Sign Up", sign_up_path %> |
24
+ <%= link_to "Reset Password", new_identity_password_reset_path %> |
25
+ <%= link_to "Verify Email", identity_email_verification_path %>
30
26
  </div>
@@ -7,9 +7,9 @@
7
7
 
8
8
  <%= stylesheet_link_tag "action_auth/application", media: "all" %>
9
9
  </head>
10
- <body>
11
-
12
- <%= yield %>
13
-
10
+ <body class="bg-light">
11
+ <div class="container bg-white border pb-3">
12
+ <%= yield %>
13
+ </div>
14
14
  </body>
15
15
  </html>
data/config/routes.rb CHANGED
@@ -5,4 +5,9 @@ ActionAuth::Engine.routes.draw do
5
5
  post "sign_up", to: "registrations#create"
6
6
  resources :sessions, only: [:index, :show, :destroy]
7
7
  resource :password, only: [:edit, :update]
8
+ namespace :identity do
9
+ resource :email, only: [:edit, :update]
10
+ resource :email_verification, only: [:show, :create]
11
+ resource :password_reset, only: [:new, :edit, :create, :update]
12
+ end
8
13
  end
@@ -14,7 +14,6 @@ module ActionAuth
14
14
 
15
15
  def user_signed_in?; Current.user.present?; end
16
16
  helper_method :user_signed_in?
17
-
18
17
  end
19
18
 
20
19
  private
@@ -14,6 +14,7 @@ module ActionAuth
14
14
  ActiveSupport.on_load :action_controller_base do
15
15
  helper_method :user_sessions_path, :user_session_path, :new_user_session_path
16
16
  helper_method :new_user_registration_path
17
+ helper_method :edit_user_password_path
17
18
  end
18
19
  end
19
20
  end
@@ -16,6 +16,14 @@ module ActionAuth
16
16
  def new_user_registration_path
17
17
  action_auth.sign_up_path
18
18
  end
19
+
20
+ def edit_password_path
21
+ action_auth.edit_password_path
22
+ end
23
+
24
+ def password_path
25
+ action_auth.password_path
26
+ end
19
27
  end
20
28
  end
21
29
  end
@@ -1,3 +1,3 @@
1
1
  module ActionAuth
2
- VERSION = "0.1.1"
2
+ VERSION = "0.1.3"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: action_auth
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.1.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Dave Kimura
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-11-08 00:00:00.000000000 Z
11
+ date: 2023-11-09 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
@@ -52,6 +52,9 @@ files:
52
52
  - app/assets/config/action_auth_manifest.js
53
53
  - app/assets/stylesheets/action_auth/application.css
54
54
  - app/controllers/action_auth/application_controller.rb
55
+ - app/controllers/action_auth/identity/email_verifications_controller.rb
56
+ - app/controllers/action_auth/identity/emails_controller.rb
57
+ - app/controllers/action_auth/identity/password_resets_controller.rb
55
58
  - app/controllers/action_auth/passwords_controller.rb
56
59
  - app/controllers/action_auth/registrations_controller.rb
57
60
  - app/controllers/action_auth/sessions_controller.rb
@@ -63,6 +66,9 @@ files:
63
66
  - app/models/action_auth/current.rb
64
67
  - app/models/action_auth/session.rb
65
68
  - app/models/action_auth/user.rb
69
+ - app/views/action_auth/identity/emails/edit.html.erb
70
+ - app/views/action_auth/identity/password_resets/edit.html.erb
71
+ - app/views/action_auth/identity/password_resets/new.html.erb
66
72
  - app/views/action_auth/passwords/edit.html.erb
67
73
  - app/views/action_auth/registrations/new.html.erb
68
74
  - app/views/action_auth/sessions/index.html.erb