rails_simple_auth 1.0.1 → 1.0.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 +4 -4
- data/CHANGELOG.md +43 -0
- data/README.md +271 -14
- data/app/controllers/rails_simple_auth/confirmations_controller.rb +25 -17
- data/app/controllers/rails_simple_auth/omniauth_callbacks_controller.rb +6 -4
- data/app/controllers/rails_simple_auth/passwords_controller.rb +13 -12
- data/app/controllers/rails_simple_auth/registrations_controller.rb +6 -4
- data/app/controllers/rails_simple_auth/sessions_controller.rb +28 -17
- data/app/mailers/rails_simple_auth/auth_mailer.rb +13 -7
- data/app/views/rails_simple_auth/confirmations/new.html.erb +2 -2
- data/app/views/rails_simple_auth/passwords/new.html.erb +2 -2
- data/app/views/rails_simple_auth/registrations/new.html.erb +5 -5
- data/app/views/rails_simple_auth/sessions/magic_link_form.html.erb +2 -2
- data/app/views/rails_simple_auth/sessions/new.html.erb +2 -2
- data/lib/generators/rails_simple_auth/css/css_generator.rb +20 -20
- data/lib/generators/rails_simple_auth/install/install_generator.rb +32 -32
- data/lib/generators/rails_simple_auth/install/templates/initializer.rb +3 -3
- data/lib/generators/rails_simple_auth/install/templates/migration.rb +2 -2
- data/lib/generators/rails_simple_auth/temporary_users/USAGE +21 -0
- data/lib/generators/rails_simple_auth/temporary_users/templates/add_temporary_to_users.rb.erb +8 -0
- data/lib/generators/rails_simple_auth/temporary_users/temporary_users_generator.rb +40 -0
- data/lib/generators/rails_simple_auth/views/views_generator.rb +8 -8
- data/lib/rails_simple_auth/configuration.rb +21 -7
- data/lib/rails_simple_auth/controllers/concerns/authentication.rb +17 -18
- data/lib/rails_simple_auth/controllers/concerns/session_management.rb +24 -0
- data/lib/rails_simple_auth/engine.rb +1 -1
- data/lib/rails_simple_auth/models/concerns/authenticatable.rb +13 -5
- data/lib/rails_simple_auth/models/concerns/confirmable.rb +42 -3
- data/lib/rails_simple_auth/models/concerns/oauth_connectable.rb +5 -5
- data/lib/rails_simple_auth/models/concerns/temporary_user.rb +114 -0
- data/lib/rails_simple_auth/models/session.rb +2 -4
- data/lib/rails_simple_auth/routes.rb +15 -15
- data/lib/rails_simple_auth/version.rb +1 -1
- data/lib/rails_simple_auth.rb +14 -12
- metadata +20 -13
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 5fb876e2f8ec9c1f40ed2dbb8d97fdd984e7e5927e11c56be6a2ac4b2aa593a4
|
|
4
|
+
data.tar.gz: 29a914c7c8f77a85199d6f7188ce77ab24460554ca90421b22b38646f15464f5
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 8a7d0926e4e1e3a8c7da6ec9ab4de80768ae98a1316a32b6d9bf6aa790f266fc494598344b9a47444bfac1241ab55ea6d11c4c89a56bb2d270cff816a0bb3178
|
|
7
|
+
data.tar.gz: b9ea5fa54ad39f51e86dae6852df477760bfb8c28a3c002cae421c40d44e5d3fb74e0ecfaa6ab6d65705cb3ba579d72e4c47061aa2b06d848d5f4639ca9f1eaf
|
data/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,49 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [1.0.3] - 2025-01-19
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
|
|
14
|
+
- **Temporary Users Support** - Allow users to try the app without signing up, then convert to permanent accounts
|
|
15
|
+
- `TemporaryUser` concern with `temporary?` and `permanent?` methods
|
|
16
|
+
- Scopes: `temporary`, `permanent`, `temporary_expired`
|
|
17
|
+
- `convert_to_permanent!(email:, password:)` method for account conversion
|
|
18
|
+
- Generator: `rails g rails_simple_auth:temporary_users` for migration
|
|
19
|
+
- Configuration options: `temporary_users_enabled`, `temporary_user_cleanup_days`
|
|
20
|
+
- Automatic cleanup of expired temporary users via `User.cleanup_expired_temporary!`
|
|
21
|
+
- Session invalidation on account conversion
|
|
22
|
+
- Automatic destruction of temporary user when signing in with different account
|
|
23
|
+
- **Email Reconfirmation Flow** - Support for users changing their email address
|
|
24
|
+
- `unconfirmed_email` column support for pending email changes
|
|
25
|
+
- `reconfirming?` and `unconfirmed_or_reconfirming?` helper methods
|
|
26
|
+
- `confirmable_email` helper returns the email needing confirmation
|
|
27
|
+
- Confirmation emails sent to new email address during reconfirmation
|
|
28
|
+
- Comprehensive test suite (126 tests, 247 assertions)
|
|
29
|
+
|
|
30
|
+
### Fixed
|
|
31
|
+
|
|
32
|
+
- `confirm!` now uses `has_attribute?(:temporary)` instead of `respond_to?(:temporary?)` to prevent errors when `Authenticatable` is included without the temporary database column
|
|
33
|
+
- `confirm!` properly handles race conditions with `RecordNotUnique` rescue during reconfirmation
|
|
34
|
+
- `convert_to_permanent!` validates password presence to prevent users being left without credentials
|
|
35
|
+
- `convert_to_permanent!` reloads after transaction to check actual database state (not stale in-memory state)
|
|
36
|
+
- `convert_to_permanent!` resets `confirmed_at` to require email verification for new address
|
|
37
|
+
- `cleanup_expired_temporary!` now returns accurate count (only increments when destroy succeeds)
|
|
38
|
+
- `magic_link_login` checks `confirm!` return value and shows error if confirmation fails
|
|
39
|
+
- `confirmations_controller#show` checks `confirm!` return value and displays appropriate error message
|
|
40
|
+
- `destroy_temporary_user_session` skips destruction when user is re-authenticating as themselves
|
|
41
|
+
- `AuthMailer#confirmation` sends to `confirmable_email` for correct recipient during reconfirmation
|
|
42
|
+
|
|
43
|
+
### Changed
|
|
44
|
+
|
|
45
|
+
- Confirmation token purpose changed from `:email_confirmation` to `:confirm_email` (**Breaking**: existing confirmation tokens will be invalidated)
|
|
46
|
+
|
|
47
|
+
## [1.0.2] - 2025-01-18
|
|
48
|
+
|
|
49
|
+
### Fixed
|
|
50
|
+
|
|
51
|
+
- Session invalidation and batch cleanup for temporary users
|
|
52
|
+
|
|
10
53
|
## [1.0.0] - 2025-01-18
|
|
11
54
|
|
|
12
55
|
### Added
|
data/README.md
CHANGED
|
@@ -4,15 +4,16 @@ Simple, secure authentication for Rails 8+ applications. Built on Rails primitiv
|
|
|
4
4
|
|
|
5
5
|
## Features
|
|
6
6
|
|
|
7
|
-
- **Email/Password authentication**
|
|
8
|
-
- **Magic link**
|
|
9
|
-
- **Email confirmation**
|
|
10
|
-
- **Password reset**
|
|
11
|
-
- **OAuth support**
|
|
12
|
-
- **
|
|
13
|
-
- **
|
|
14
|
-
- **
|
|
15
|
-
- **
|
|
7
|
+
- [**Email/Password authentication**](#installation) - secure session-based auth
|
|
8
|
+
- [**Magic link authentication**](#routes) - passwordless sign-in via email
|
|
9
|
+
- [**Email confirmation**](#routes) - verify user email addresses
|
|
10
|
+
- [**Password reset**](#routes) - secure password recovery flow
|
|
11
|
+
- [**OAuth support**](#oauth-setup) - Google, GitHub, and more
|
|
12
|
+
- [**Temporary users**](#temporary-users-guest-accounts) - guest accounts that convert to permanent
|
|
13
|
+
- [**Rate limiting**](#rate-limiting) - built-in protection on all endpoints
|
|
14
|
+
- [**Session tracking**](#session-management) - IP and user agent logging
|
|
15
|
+
- [**Customizable styling**](#styling) - CSS variables for easy theming
|
|
16
|
+
- [**Custom mailers**](#mailer) - use your own branded email templates
|
|
16
17
|
|
|
17
18
|
## Installation
|
|
18
19
|
|
|
@@ -67,7 +68,7 @@ class CreateUsers < ActiveRecord::Migration[8.0]
|
|
|
67
68
|
def change
|
|
68
69
|
create_table :users do |t|
|
|
69
70
|
# Required by gem
|
|
70
|
-
t.string :
|
|
71
|
+
t.string :email, null: false
|
|
71
72
|
t.string :password_digest, null: false
|
|
72
73
|
t.datetime :confirmed_at # if using Confirmable
|
|
73
74
|
|
|
@@ -81,7 +82,7 @@ class CreateUsers < ActiveRecord::Migration[8.0]
|
|
|
81
82
|
t.timestamps
|
|
82
83
|
end
|
|
83
84
|
|
|
84
|
-
add_index :users, :
|
|
85
|
+
add_index :users, :email, unique: true
|
|
85
86
|
end
|
|
86
87
|
end
|
|
87
88
|
```
|
|
@@ -203,6 +204,156 @@ class User < ApplicationRecord
|
|
|
203
204
|
end
|
|
204
205
|
```
|
|
205
206
|
|
|
207
|
+
## Temporary Users (Guest Accounts)
|
|
208
|
+
|
|
209
|
+
Temporary users allow visitors to try your app without creating an account. They get a real user record with full functionality, then can convert to a permanent account later by providing email and password.
|
|
210
|
+
|
|
211
|
+
### Why Use Temporary Users?
|
|
212
|
+
|
|
213
|
+
**Reduce friction**: Let users experience your app's value before asking them to sign up. This is especially useful for:
|
|
214
|
+
|
|
215
|
+
- **E-commerce**: Users can add items to cart, save preferences, then checkout as guest or create account
|
|
216
|
+
- **Productivity apps**: Users can create documents, try features, then save their work by signing up
|
|
217
|
+
- **Games**: Users can start playing immediately, then create account to save progress
|
|
218
|
+
- **Collaboration tools**: Users can join a shared workspace via link, then register to keep access
|
|
219
|
+
|
|
220
|
+
**Preserve data**: Unlike anonymous sessions, temporary users have real database records. When they convert, all their data (orders, documents, settings) stays linked to their account.
|
|
221
|
+
|
|
222
|
+
### Setup
|
|
223
|
+
|
|
224
|
+
1. Generate the migration:
|
|
225
|
+
|
|
226
|
+
```bash
|
|
227
|
+
rails generate rails_simple_auth:temporary_users
|
|
228
|
+
rails db:migrate
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
2. Add the concern to your User model:
|
|
232
|
+
|
|
233
|
+
```ruby
|
|
234
|
+
class User < ApplicationRecord
|
|
235
|
+
include RailsSimpleAuth::Models::Concerns::Authenticatable
|
|
236
|
+
include RailsSimpleAuth::Models::Concerns::TemporaryUser # Add this
|
|
237
|
+
end
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
3. Enable in configuration:
|
|
241
|
+
|
|
242
|
+
```ruby
|
|
243
|
+
RailsSimpleAuth.configure do |config|
|
|
244
|
+
config.temporary_users_enabled = true
|
|
245
|
+
config.temporary_user_cleanup_days = 7 # Auto-cleanup after 7 days
|
|
246
|
+
end
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
### Creating Temporary Users
|
|
250
|
+
|
|
251
|
+
Create a temporary user when someone needs to use your app without signing up:
|
|
252
|
+
|
|
253
|
+
```ruby
|
|
254
|
+
# In your controller
|
|
255
|
+
def try_without_account
|
|
256
|
+
user = User.create!(
|
|
257
|
+
email: "temp_#{SecureRandom.hex(8)}@temporary.local",
|
|
258
|
+
password: SecureRandom.hex(32),
|
|
259
|
+
temporary: true
|
|
260
|
+
)
|
|
261
|
+
|
|
262
|
+
# Sign them in
|
|
263
|
+
create_session_for(user)
|
|
264
|
+
redirect_to dashboard_path
|
|
265
|
+
end
|
|
266
|
+
```
|
|
267
|
+
|
|
268
|
+
Or create via an invite link:
|
|
269
|
+
|
|
270
|
+
```ruby
|
|
271
|
+
def accept_invite
|
|
272
|
+
# Create temporary user to access shared content
|
|
273
|
+
user = User.create!(temporary: true, ...)
|
|
274
|
+
create_session_for(user)
|
|
275
|
+
redirect_to shared_workspace_path(params[:workspace_id])
|
|
276
|
+
end
|
|
277
|
+
```
|
|
278
|
+
|
|
279
|
+
### Converting to Permanent Account
|
|
280
|
+
|
|
281
|
+
When a temporary user is ready to create a real account:
|
|
282
|
+
|
|
283
|
+
```ruby
|
|
284
|
+
# In your controller
|
|
285
|
+
def convert_account
|
|
286
|
+
if current_user.convert_to_permanent!(
|
|
287
|
+
email: params[:email],
|
|
288
|
+
password: params[:password]
|
|
289
|
+
)
|
|
290
|
+
redirect_to dashboard_path, notice: "Account created! Please check your email to confirm."
|
|
291
|
+
else
|
|
292
|
+
# Validation failed (email taken, password blank, etc.)
|
|
293
|
+
render :convert_form, status: :unprocessable_entity
|
|
294
|
+
end
|
|
295
|
+
end
|
|
296
|
+
```
|
|
297
|
+
|
|
298
|
+
The conversion:
|
|
299
|
+
- Updates email and password
|
|
300
|
+
- Sets `temporary: false`
|
|
301
|
+
- Resets `confirmed_at` (requires email confirmation for new address)
|
|
302
|
+
- Invalidates all existing sessions (security measure)
|
|
303
|
+
- Sends confirmation email automatically
|
|
304
|
+
|
|
305
|
+
### What Happens on Sign In?
|
|
306
|
+
|
|
307
|
+
When a temporary user signs in with a different account (or signs up), the temporary user is automatically destroyed:
|
|
308
|
+
|
|
309
|
+
```
|
|
310
|
+
Temporary User (browsing) → Signs in with existing account → Temp user deleted
|
|
311
|
+
Temporary User (browsing) → Creates new account → Temp user deleted
|
|
312
|
+
Temporary User (browsing) → Converts their temp account → Keeps same user record
|
|
313
|
+
```
|
|
314
|
+
|
|
315
|
+
This prevents orphaned temporary records and ensures clean data.
|
|
316
|
+
|
|
317
|
+
### Querying Users
|
|
318
|
+
|
|
319
|
+
```ruby
|
|
320
|
+
User.temporary # All temporary users
|
|
321
|
+
User.permanent # All permanent users
|
|
322
|
+
User.temporary_expired # Temporary users older than cleanup_days
|
|
323
|
+
|
|
324
|
+
current_user.temporary? # Is this a guest?
|
|
325
|
+
current_user.permanent? # Is this a real account?
|
|
326
|
+
```
|
|
327
|
+
|
|
328
|
+
### Cleanup
|
|
329
|
+
|
|
330
|
+
Temporary users are automatically eligible for cleanup after `temporary_user_cleanup_days`. Run cleanup manually or via scheduled job:
|
|
331
|
+
|
|
332
|
+
```ruby
|
|
333
|
+
# In a rake task or background job
|
|
334
|
+
User.cleanup_expired_temporary!
|
|
335
|
+
|
|
336
|
+
# With custom retention period
|
|
337
|
+
User.cleanup_expired_temporary!(days: 14)
|
|
338
|
+
```
|
|
339
|
+
|
|
340
|
+
Add to your scheduler (e.g., `config/recurring.yml` for Solid Queue):
|
|
341
|
+
|
|
342
|
+
```yaml
|
|
343
|
+
cleanup_temporary_users:
|
|
344
|
+
schedule: every day at 3am
|
|
345
|
+
class: CleanupTemporaryUsersJob
|
|
346
|
+
```
|
|
347
|
+
|
|
348
|
+
```ruby
|
|
349
|
+
class CleanupTemporaryUsersJob < ApplicationJob
|
|
350
|
+
def perform
|
|
351
|
+
count = User.cleanup_expired_temporary!
|
|
352
|
+
Rails.logger.info "Cleaned up #{count} expired temporary users"
|
|
353
|
+
end
|
|
354
|
+
end
|
|
355
|
+
```
|
|
356
|
+
|
|
206
357
|
## Controller Customization
|
|
207
358
|
|
|
208
359
|
Subclass controllers for custom behavior:
|
|
@@ -266,19 +417,19 @@ class UserMailer < ApplicationMailer
|
|
|
266
417
|
def confirmation(user, token)
|
|
267
418
|
@user = user
|
|
268
419
|
@confirmation_url = edit_confirmation_url(token: token)
|
|
269
|
-
mail(to: user.
|
|
420
|
+
mail(to: user.email, subject: "Confirm your email")
|
|
270
421
|
end
|
|
271
422
|
|
|
272
423
|
def magic_link(user, token)
|
|
273
424
|
@user = user
|
|
274
425
|
@magic_link_url = magic_link_login_url(token: token)
|
|
275
|
-
mail(to: user.
|
|
426
|
+
mail(to: user.email, subject: "Your sign-in link")
|
|
276
427
|
end
|
|
277
428
|
|
|
278
429
|
def password_reset(user, token)
|
|
279
430
|
@user = user
|
|
280
431
|
@reset_url = edit_password_url(token: token)
|
|
281
|
-
mail(to: user.
|
|
432
|
+
mail(to: user.email, subject: "Reset your password")
|
|
282
433
|
end
|
|
283
434
|
end
|
|
284
435
|
```
|
|
@@ -330,6 +481,112 @@ The gem adds these routes:
|
|
|
330
481
|
| POST | `/request_magic_link` | Send magic link |
|
|
331
482
|
| GET | `/magic_link` | Login via magic link |
|
|
332
483
|
|
|
484
|
+
## Rate Limiting
|
|
485
|
+
|
|
486
|
+
All authentication endpoints are rate limited using Rails 8's `rate_limit` DSL to prevent brute force attacks.
|
|
487
|
+
|
|
488
|
+
### Default Limits
|
|
489
|
+
|
|
490
|
+
| Action | Limit | Period | Scope |
|
|
491
|
+
|--------|-------|--------|-------|
|
|
492
|
+
| Sign in | 5 requests | 15 minutes | per IP |
|
|
493
|
+
| Sign up | 5 requests | 1 hour | per IP |
|
|
494
|
+
| Magic link request | 3 requests | 10 minutes | per email |
|
|
495
|
+
| Password reset | 3 requests | 1 hour | per IP |
|
|
496
|
+
| Email confirmation | 3 requests | 1 hour | per IP |
|
|
497
|
+
|
|
498
|
+
### Customizing Limits
|
|
499
|
+
|
|
500
|
+
```ruby
|
|
501
|
+
RailsSimpleAuth.configure do |config|
|
|
502
|
+
config.rate_limits = {
|
|
503
|
+
sign_in: { limit: 10, period: 30.minutes },
|
|
504
|
+
sign_up: { limit: 3, period: 1.hour },
|
|
505
|
+
magic_link: { limit: 5, period: 15.minutes },
|
|
506
|
+
password_reset: { limit: 5, period: 1.hour },
|
|
507
|
+
confirmation: { limit: 5, period: 1.hour }
|
|
508
|
+
}
|
|
509
|
+
end
|
|
510
|
+
```
|
|
511
|
+
|
|
512
|
+
### Disabling Rate Limiting
|
|
513
|
+
|
|
514
|
+
To disable rate limiting for a specific action, set it to `nil`:
|
|
515
|
+
|
|
516
|
+
```ruby
|
|
517
|
+
config.rate_limits = {
|
|
518
|
+
sign_in: nil, # No rate limiting on sign in
|
|
519
|
+
sign_up: { limit: 5, period: 1.hour }
|
|
520
|
+
}
|
|
521
|
+
```
|
|
522
|
+
|
|
523
|
+
When rate limited, users see a "Too many requests" error and must wait for the period to expire.
|
|
524
|
+
|
|
525
|
+
## Session Management
|
|
526
|
+
|
|
527
|
+
Sessions track user authentication state with IP address and user agent for security auditing.
|
|
528
|
+
|
|
529
|
+
### What's Tracked
|
|
530
|
+
|
|
531
|
+
Each session stores:
|
|
532
|
+
- **user_id** - The authenticated user
|
|
533
|
+
- **ip_address** - Client IP at sign-in time
|
|
534
|
+
- **user_agent** - Browser/device information
|
|
535
|
+
- **created_at** - When the session was created
|
|
536
|
+
|
|
537
|
+
### Session Expiration
|
|
538
|
+
|
|
539
|
+
Sessions expire after 30 days by default:
|
|
540
|
+
|
|
541
|
+
```ruby
|
|
542
|
+
RailsSimpleAuth.configure do |config|
|
|
543
|
+
config.session_expiry = 30.days # Default
|
|
544
|
+
# config.session_expiry = 7.days # Shorter sessions
|
|
545
|
+
end
|
|
546
|
+
```
|
|
547
|
+
|
|
548
|
+
### Querying Sessions
|
|
549
|
+
|
|
550
|
+
```ruby
|
|
551
|
+
# All sessions for a user
|
|
552
|
+
current_user.sessions
|
|
553
|
+
|
|
554
|
+
# Recent sessions first
|
|
555
|
+
current_user.sessions.recent
|
|
556
|
+
|
|
557
|
+
# Active sessions (not expired)
|
|
558
|
+
current_user.sessions.active
|
|
559
|
+
|
|
560
|
+
# Expired sessions
|
|
561
|
+
current_user.sessions.expired
|
|
562
|
+
```
|
|
563
|
+
|
|
564
|
+
### Session Cleanup
|
|
565
|
+
|
|
566
|
+
Expired sessions can be cleaned up manually or via scheduled job:
|
|
567
|
+
|
|
568
|
+
```ruby
|
|
569
|
+
# Clean up all expired sessions
|
|
570
|
+
RailsSimpleAuth::Session.cleanup_expired!
|
|
571
|
+
```
|
|
572
|
+
|
|
573
|
+
Add to your scheduler:
|
|
574
|
+
|
|
575
|
+
```ruby
|
|
576
|
+
class CleanupExpiredSessionsJob < ApplicationJob
|
|
577
|
+
def perform
|
|
578
|
+
count = RailsSimpleAuth::Session.cleanup_expired!
|
|
579
|
+
Rails.logger.info "Cleaned up #{count} expired sessions"
|
|
580
|
+
end
|
|
581
|
+
end
|
|
582
|
+
```
|
|
583
|
+
|
|
584
|
+
### Security Behaviors
|
|
585
|
+
|
|
586
|
+
- **Password change**: All sessions are invalidated when a user changes their password
|
|
587
|
+
- **Account conversion**: All sessions are invalidated when a temporary user converts to permanent
|
|
588
|
+
- **Sign out**: Only the current session is destroyed (other devices stay signed in)
|
|
589
|
+
|
|
333
590
|
## Security Features
|
|
334
591
|
|
|
335
592
|
- **BCrypt password hashing** with salts
|
|
@@ -6,33 +6,41 @@ module RailsSimpleAuth
|
|
|
6
6
|
|
|
7
7
|
unless Rails.env.local?
|
|
8
8
|
rate_limit to: 3, within: 1.hour, by: -> { client_ip }, only: :create,
|
|
9
|
-
with:
|
|
9
|
+
with: lambda {
|
|
10
|
+
redirect_to new_confirmation_path, alert: 'Too many confirmation requests. Please try again later.'
|
|
11
|
+
}
|
|
10
12
|
end
|
|
11
13
|
|
|
12
|
-
def
|
|
14
|
+
def show
|
|
15
|
+
user = user_class.find_signed(params[:token], purpose: :confirm_email)
|
|
16
|
+
|
|
17
|
+
if user
|
|
18
|
+
confirmed = user.respond_to?(:confirm!) ? user.confirm! : true
|
|
19
|
+
|
|
20
|
+
if confirmed
|
|
21
|
+
run_after_confirmation_callback(user)
|
|
22
|
+
redirect_to resolve_path(:after_confirmation_path), notice: 'Email confirmed! You can now sign in.'
|
|
23
|
+
else
|
|
24
|
+
error_message = user.errors.full_messages.first || 'Could not confirm email.'
|
|
25
|
+
redirect_to new_confirmation_path, alert: error_message
|
|
26
|
+
end
|
|
27
|
+
else
|
|
28
|
+
redirect_to new_confirmation_path, alert: 'Invalid or expired confirmation link.'
|
|
29
|
+
end
|
|
13
30
|
end
|
|
14
31
|
|
|
32
|
+
def new; end
|
|
33
|
+
|
|
15
34
|
def create
|
|
16
|
-
user = user_class.
|
|
35
|
+
user = user_class.find_by(email: params[:email])
|
|
17
36
|
|
|
18
|
-
if user
|
|
37
|
+
if user.respond_to?(:unconfirmed_or_reconfirming?) && user.unconfirmed_or_reconfirming?
|
|
19
38
|
token = user.generate_confirmation_token
|
|
20
39
|
RailsSimpleAuth.configuration.mailer.confirmation(user, token).deliver_later
|
|
21
40
|
end
|
|
22
41
|
|
|
23
|
-
redirect_to new_session_path,
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
def show
|
|
27
|
-
user = user_class.find_signed(params[:token], purpose: :email_confirmation)
|
|
28
|
-
|
|
29
|
-
if user
|
|
30
|
-
user.confirm! if user.respond_to?(:confirm!)
|
|
31
|
-
run_after_confirmation_callback(user)
|
|
32
|
-
redirect_to resolve_path(:after_confirmation_path), notice: "Email confirmed! You can now sign in."
|
|
33
|
-
else
|
|
34
|
-
redirect_to new_confirmation_path, alert: "Invalid or expired confirmation link."
|
|
35
|
-
end
|
|
42
|
+
redirect_to new_session_path,
|
|
43
|
+
notice: 'If an unconfirmed account exists with that email, confirmation instructions have been sent.'
|
|
36
44
|
end
|
|
37
45
|
|
|
38
46
|
private
|
|
@@ -6,27 +6,29 @@ module RailsSimpleAuth
|
|
|
6
6
|
skip_before_action :verify_authenticity_token, only: :create
|
|
7
7
|
|
|
8
8
|
def create
|
|
9
|
-
auth_hash = request.env[
|
|
9
|
+
auth_hash = request.env['omniauth.auth']
|
|
10
10
|
provider = params[:provider]
|
|
11
11
|
|
|
12
12
|
unless RailsSimpleAuth.configuration.oauth_provider_enabled?(provider)
|
|
13
|
-
redirect_to new_session_path, alert:
|
|
13
|
+
redirect_to new_session_path, alert: 'OAuth provider not enabled.'
|
|
14
14
|
return
|
|
15
15
|
end
|
|
16
16
|
|
|
17
17
|
user = user_class.from_oauth(auth_hash)
|
|
18
18
|
|
|
19
19
|
if user&.persisted?
|
|
20
|
+
destroy_temporary_user_session(user)
|
|
20
21
|
create_session_for(user)
|
|
21
22
|
run_after_sign_in_callback(user)
|
|
22
|
-
redirect_to resolve_path(:after_sign_in_path),
|
|
23
|
+
redirect_to resolve_path(:after_sign_in_path),
|
|
24
|
+
notice: "Signed in successfully with #{provider.to_s.capitalize}."
|
|
23
25
|
else
|
|
24
26
|
redirect_to new_session_path, alert: "Could not authenticate with #{provider.to_s.capitalize}."
|
|
25
27
|
end
|
|
26
28
|
end
|
|
27
29
|
|
|
28
30
|
def failure
|
|
29
|
-
redirect_to new_session_path, alert:
|
|
31
|
+
redirect_to new_session_path, alert: 'Authentication failed. Please try again.'
|
|
30
32
|
end
|
|
31
33
|
end
|
|
32
34
|
end
|
|
@@ -7,31 +7,32 @@ module RailsSimpleAuth
|
|
|
7
7
|
|
|
8
8
|
unless Rails.env.local?
|
|
9
9
|
rate_limit to: 3, within: 1.hour, by: -> { client_ip }, only: :create,
|
|
10
|
-
with:
|
|
10
|
+
with: lambda {
|
|
11
|
+
redirect_to new_password_path, alert: 'Too many password reset requests. Please try again later.'
|
|
12
|
+
}
|
|
11
13
|
end
|
|
12
14
|
|
|
13
|
-
def new
|
|
14
|
-
|
|
15
|
+
def new; end
|
|
16
|
+
|
|
17
|
+
def edit; end
|
|
15
18
|
|
|
16
19
|
def create
|
|
17
|
-
user = user_class.
|
|
20
|
+
user = user_class.find_by(email: params[:email])
|
|
18
21
|
|
|
19
22
|
if user && can_reset_password?(user)
|
|
20
23
|
token = user.generate_password_reset_token
|
|
21
24
|
RailsSimpleAuth.configuration.mailer.password_reset(user, token).deliver_later
|
|
22
25
|
end
|
|
23
26
|
|
|
24
|
-
redirect_to new_session_path,
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
def edit
|
|
27
|
+
redirect_to new_session_path,
|
|
28
|
+
notice: 'If an account exists with that email, password reset instructions have been sent.'
|
|
28
29
|
end
|
|
29
30
|
|
|
30
31
|
def update
|
|
31
32
|
ActiveRecord::Base.transaction do
|
|
32
33
|
if @user.update(password_params)
|
|
33
34
|
@user.invalidate_all_sessions!
|
|
34
|
-
redirect_to new_session_path, notice:
|
|
35
|
+
redirect_to new_session_path, notice: 'Password has been reset. Please sign in with your new password.'
|
|
35
36
|
else
|
|
36
37
|
render :edit, status: :unprocessable_content
|
|
37
38
|
raise ActiveRecord::Rollback
|
|
@@ -42,14 +43,14 @@ module RailsSimpleAuth
|
|
|
42
43
|
"[RailsSimpleAuth] Session invalidation failed after password reset for user #{@user.id}: #{e.message}"
|
|
43
44
|
)
|
|
44
45
|
# Password was rolled back due to transaction, redirect with error
|
|
45
|
-
redirect_to new_password_path, alert:
|
|
46
|
+
redirect_to new_password_path, alert: 'Password reset failed. Please try again.'
|
|
46
47
|
end
|
|
47
48
|
|
|
48
49
|
private
|
|
49
50
|
|
|
50
51
|
def set_user_from_token
|
|
51
52
|
@user = user_class.find_signed(params[:token], purpose: :password_reset)
|
|
52
|
-
redirect_to new_password_path, alert:
|
|
53
|
+
redirect_to new_password_path, alert: 'Invalid or expired password reset link.' unless @user
|
|
53
54
|
end
|
|
54
55
|
|
|
55
56
|
def can_reset_password?(user)
|
|
@@ -60,7 +61,7 @@ module RailsSimpleAuth
|
|
|
60
61
|
end
|
|
61
62
|
|
|
62
63
|
def password_params
|
|
63
|
-
params.
|
|
64
|
+
params.expect(user: %i[password password_confirmation])
|
|
64
65
|
end
|
|
65
66
|
end
|
|
66
67
|
end
|
|
@@ -6,7 +6,7 @@ module RailsSimpleAuth
|
|
|
6
6
|
|
|
7
7
|
unless Rails.env.local?
|
|
8
8
|
rate_limit to: 5, within: 1.hour, by: -> { client_ip }, only: :create,
|
|
9
|
-
with: -> { redirect_to sign_up_path, alert:
|
|
9
|
+
with: -> { redirect_to sign_up_path, alert: 'Too many sign up attempts. Please try again later.' }
|
|
10
10
|
end
|
|
11
11
|
|
|
12
12
|
def new
|
|
@@ -27,18 +27,20 @@ module RailsSimpleAuth
|
|
|
27
27
|
private
|
|
28
28
|
|
|
29
29
|
def registration_params
|
|
30
|
-
params.
|
|
30
|
+
params.expect(user: %i[email password])
|
|
31
31
|
end
|
|
32
32
|
|
|
33
33
|
def after_successful_registration
|
|
34
|
+
destroy_temporary_user_session(@user)
|
|
35
|
+
|
|
34
36
|
if RailsSimpleAuth.configuration.email_confirmation_enabled
|
|
35
37
|
send_confirmation_email(@user)
|
|
36
38
|
run_after_sign_up_callback(@user)
|
|
37
|
-
redirect_to new_session_path, notice:
|
|
39
|
+
redirect_to new_session_path, notice: 'Account created! Please check your email to confirm your account.'
|
|
38
40
|
else
|
|
39
41
|
create_session_for(@user)
|
|
40
42
|
run_after_sign_up_callback(@user)
|
|
41
|
-
redirect_to resolve_path(:after_sign_up_path), notice:
|
|
43
|
+
redirect_to resolve_path(:after_sign_up_path), notice: 'Account created successfully!'
|
|
42
44
|
end
|
|
43
45
|
end
|
|
44
46
|
|