passwordless 1.2.0 → 1.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +10 -24
- data/app/controllers/passwordless/sessions_controller.rb +33 -17
- data/app/mailers/passwordless/mailer.rb +3 -2
- data/app/views/passwordless/sessions/new.html.erb +6 -6
- data/app/views/passwordless/sessions/show.html.erb +5 -2
- data/lib/passwordless/config.rb +3 -0
- data/lib/passwordless/test_helpers.rb +5 -4
- data/lib/passwordless/version.rb +1 -1
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2242a4b95f1a99d5be1b889539dc6dd9f1eda711ce616f3b090f12dd68337254
|
4
|
+
data.tar.gz: afd9ea1fd2d3b3f15f10a4772d231c53adfd524e22de00d833a9183b34d69397
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9b2ceb4c68972744e10ac6dd56e2e863b5e229bb31053b7159a16c020a2cfa55ffe1affcbef92ca52ee03de79d4d675cb5b3f4340e1c888e064e9ab246f3e455
|
7
|
+
data.tar.gz: 7dd102d25dd4cbb60ab73d30732f78a6cd1d6757e345e3b304c9b1abe4394b6b1d883c1368bd7eaa12ecee986ecdfabf3d82cea081048694807388fc5a1bfd69
|
data/README.md
CHANGED
@@ -25,26 +25,21 @@ See [Upgrading to Passwordless 1.0](docs/upgrading_to_1_0.md) for more details.
|
|
25
25
|
|
26
26
|
## Usage
|
27
27
|
|
28
|
-
Passwordless creates a single model called `Passwordless::Session
|
28
|
+
Passwordless creates a single model called `Passwordless::Session`, so it doesn't come with its own user model. Instead, it expects you to provide one, with an email field in place. If you don't yet have a user model, check out the wiki on [creating the user model](https://github.com/mikker/passwordless/wiki/Creating-the-user-model).
|
29
29
|
|
30
|
-
|
31
|
-
$ bin/rails generate model User email
|
32
|
-
```
|
33
|
-
|
34
|
-
Then specify which field on your `User` record is the email field with:
|
30
|
+
Enable Passwordless on your user model by pointing it to the email field:
|
35
31
|
|
36
32
|
```ruby
|
37
33
|
class User < ApplicationRecord
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
format: { with: URI::MailTo::EMAIL_REGEXP }
|
34
|
+
# your other code..
|
35
|
+
|
36
|
+
passwordless_with :email # <-- here! this needs to be a column in `users` table
|
42
37
|
|
43
|
-
|
38
|
+
# more of your code..
|
44
39
|
end
|
45
40
|
```
|
46
41
|
|
47
|
-
|
42
|
+
Then mount the engine in your routes:
|
48
43
|
|
49
44
|
```ruby
|
50
45
|
Rails.application.routes.draw do
|
@@ -163,6 +158,7 @@ The default values are shown below. It's recommended to only include the ones th
|
|
163
158
|
```ruby
|
164
159
|
Passwordless.configure do |config|
|
165
160
|
config.default_from_address = "CHANGE_ME@example.com"
|
161
|
+
config.parent_controller = "ApplicationController"
|
166
162
|
config.parent_mailer = "ActionMailer::Base"
|
167
163
|
config.restrict_token_reuse = false # Can a token/link be used multiple times?
|
168
164
|
config.token_generator = Passwordless::ShortTokenGenerator.new # Used to generate magic link tokens.
|
@@ -175,6 +171,8 @@ Passwordless.configure do |config|
|
|
175
171
|
config.success_redirect_path = '/' # After a user successfully signs in
|
176
172
|
config.failure_redirect_path = '/' # After a sign in fails
|
177
173
|
config.sign_out_redirect_path = '/' # After a user signs out
|
174
|
+
|
175
|
+
config.paranoid = false # Display email sent notice even when the resource is not found.
|
178
176
|
end
|
179
177
|
```
|
180
178
|
|
@@ -260,18 +258,6 @@ class User < ApplicationRecord
|
|
260
258
|
end
|
261
259
|
```
|
262
260
|
|
263
|
-
### Claiming tokens
|
264
|
-
|
265
|
-
By default, a token/magic link **can** be used more than once.
|
266
|
-
|
267
|
-
To change, in `config/initializers/passwordless.rb`:
|
268
|
-
|
269
|
-
```ruby
|
270
|
-
Passwordless.configure do |config|
|
271
|
-
config.restrict_token_reuse = true
|
272
|
-
end
|
273
|
-
```
|
274
|
-
|
275
261
|
## Test helpers
|
276
262
|
|
277
263
|
To help with testing, a set of test helpers are provided.
|
@@ -4,7 +4,7 @@ require "bcrypt"
|
|
4
4
|
|
5
5
|
module Passwordless
|
6
6
|
# Controller for managing Passwordless sessions
|
7
|
-
class SessionsController <
|
7
|
+
class SessionsController < Passwordless.config.parent_controller.constantize
|
8
8
|
include ControllerHelpers
|
9
9
|
|
10
10
|
helper_method :email_field
|
@@ -20,21 +20,11 @@ module Passwordless
|
|
20
20
|
# Creates a new Session record then sends the magic link
|
21
21
|
# redirects to sign in page with generic flash message.
|
22
22
|
def create
|
23
|
-
unless @resource = find_authenticatable
|
24
|
-
raise(
|
25
|
-
ActiveRecord::RecordNotFound,
|
26
|
-
"Couldn't find #{authenticatable_type} with email #{passwordless_session_params[email_field]}"
|
27
|
-
)
|
28
|
-
end
|
29
|
-
|
23
|
+
handle_resource_not_found unless @resource = find_authenticatable
|
30
24
|
@session = build_passwordless_session(@resource)
|
31
25
|
|
32
26
|
if @session.save
|
33
|
-
|
34
|
-
Passwordless.config.after_session_save.call(@session, request)
|
35
|
-
else
|
36
|
-
Passwordless.config.after_session_save.call(@session)
|
37
|
-
end
|
27
|
+
call_after_session_save
|
38
28
|
|
39
29
|
redirect_to(
|
40
30
|
Passwordless.context.path_for(
|
@@ -50,6 +40,8 @@ module Passwordless
|
|
50
40
|
end
|
51
41
|
|
52
42
|
rescue ActiveRecord::RecordNotFound
|
43
|
+
@session = Session.new
|
44
|
+
|
53
45
|
flash[:error] = I18n.t("passwordless.sessions.create.not_found")
|
54
46
|
render(:new, status: :not_found)
|
55
47
|
end
|
@@ -173,12 +165,36 @@ module Passwordless
|
|
173
165
|
end
|
174
166
|
|
175
167
|
def find_authenticatable
|
176
|
-
email = passwordless_session_params[email_field].downcase.strip
|
177
|
-
|
178
168
|
if authenticatable_class.respond_to?(:fetch_resource_for_passwordless)
|
179
|
-
authenticatable_class.fetch_resource_for_passwordless(
|
169
|
+
authenticatable_class.fetch_resource_for_passwordless(normalized_email_param)
|
170
|
+
else
|
171
|
+
authenticatable_class.where("lower(#{email_field}) = ?", normalized_email_param).first
|
172
|
+
end
|
173
|
+
end
|
174
|
+
|
175
|
+
def normalized_email_param
|
176
|
+
passwordless_session_params[email_field].downcase.strip
|
177
|
+
end
|
178
|
+
|
179
|
+
def handle_resource_not_found
|
180
|
+
if Passwordless.config.paranoid
|
181
|
+
@resource = authenticatable_class.new(email: normalized_email_param)
|
182
|
+
@skip_after_session_save_callback = true
|
183
|
+
else
|
184
|
+
raise(
|
185
|
+
ActiveRecord::RecordNotFound,
|
186
|
+
"Couldn't find #{authenticatable_type} with email #{normalized_email_param}"
|
187
|
+
)
|
188
|
+
end
|
189
|
+
end
|
190
|
+
|
191
|
+
def call_after_session_save
|
192
|
+
return if @skip_after_session_save_callback
|
193
|
+
|
194
|
+
if Passwordless.config.after_session_save.arity == 2
|
195
|
+
Passwordless.config.after_session_save.call(@session, request)
|
180
196
|
else
|
181
|
-
|
197
|
+
Passwordless.config.after_session_save.call(@session)
|
182
198
|
end
|
183
199
|
end
|
184
200
|
|
@@ -3,7 +3,7 @@
|
|
3
3
|
module Passwordless
|
4
4
|
# The mailer responsible for sending Passwordless' mails.
|
5
5
|
class Mailer < Passwordless.config.parent_mailer.constantize
|
6
|
-
default
|
6
|
+
default(from: Passwordless.config.default_from_address) if Passwordless.config.default_from_address
|
7
7
|
|
8
8
|
# Sends a token and a magic link
|
9
9
|
#
|
@@ -17,7 +17,8 @@ module Passwordless
|
|
17
17
|
session,
|
18
18
|
action: "confirm",
|
19
19
|
id: session.to_param,
|
20
|
-
token: @token
|
20
|
+
token: @token,
|
21
|
+
**default_url_options
|
21
22
|
)
|
22
23
|
|
23
24
|
email_field = session.authenticatable.class.passwordless_email_field
|
@@ -1,12 +1,12 @@
|
|
1
1
|
<%= form_with(model: @session, url: url_for(action: 'new'), data: { turbo: 'false' }) do |f| %>
|
2
2
|
<% email_field_name = :"passwordless[#{email_field}]" %>
|
3
3
|
<%= f.label email_field_name,
|
4
|
-
|
5
|
-
|
4
|
+
t("passwordless.sessions.new.email.label"),
|
5
|
+
for: "passwordless_#{email_field}" %>
|
6
6
|
<%= email_field_tag email_field_name,
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
7
|
+
params.fetch(email_field_name, nil),
|
8
|
+
required: true,
|
9
|
+
autofocus: true,
|
10
|
+
placeholder: t("passwordless.sessions.new.email.placeholder") %>
|
11
11
|
<%= f.submit t("passwordless.sessions.new.submit") %>
|
12
12
|
<% end %>
|
@@ -1,5 +1,8 @@
|
|
1
1
|
<%= form_with(model: @session, url: url_for(action: 'update'), scope: 'passwordless', method: 'patch', data: { turbo: false }) do |f| %>
|
2
|
-
<%= f.label :token
|
3
|
-
<%= f.text_field :token
|
2
|
+
<%= f.label :token %>
|
3
|
+
<%= f.text_field :token,
|
4
|
+
required: true,
|
5
|
+
autofocus: true,
|
6
|
+
autocomplete: "one-time-code" %>
|
4
7
|
<%= f.submit t(".confirm") %>
|
5
8
|
<% end %>
|
data/lib/passwordless/config.rb
CHANGED
@@ -28,6 +28,7 @@ module Passwordless
|
|
28
28
|
include Options
|
29
29
|
|
30
30
|
option :default_from_address, default: "CHANGE_ME@example.com"
|
31
|
+
option :parent_controller, default: "ApplicationController"
|
31
32
|
option :parent_mailer, default: "ActionMailer::Base"
|
32
33
|
option :restrict_token_reuse, default: true
|
33
34
|
option :token_generator, default: ShortTokenGenerator.new
|
@@ -48,6 +49,8 @@ module Passwordless
|
|
48
49
|
end
|
49
50
|
)
|
50
51
|
|
52
|
+
option :paranoid, default: false
|
53
|
+
|
51
54
|
def initialize
|
52
55
|
set_defaults!
|
53
56
|
end
|
@@ -43,21 +43,22 @@ module Passwordless
|
|
43
43
|
end
|
44
44
|
|
45
45
|
module SystemTestCase
|
46
|
-
def passwordless_sign_out(cls = nil)
|
46
|
+
def passwordless_sign_out(cls = nil, only_path: false)
|
47
47
|
cls ||= "User".constantize
|
48
48
|
resource = cls.model_name.to_s.tableize
|
49
49
|
|
50
|
-
visit(Passwordless.context.url_for(resource, action: "destroy"))
|
50
|
+
visit(Passwordless.context.url_for(resource, action: "destroy", only_path: only_path))
|
51
51
|
end
|
52
52
|
|
53
|
-
def passwordless_sign_in(resource)
|
53
|
+
def passwordless_sign_in(resource, only_path: false)
|
54
54
|
session = Passwordless::Session.create!(authenticatable: resource)
|
55
55
|
|
56
56
|
magic_link = Passwordless.context.url_for(
|
57
57
|
session,
|
58
58
|
action: "confirm",
|
59
59
|
id: session.to_param,
|
60
|
-
token: session.token
|
60
|
+
token: session.token,
|
61
|
+
only_path: only_path
|
61
62
|
)
|
62
63
|
|
63
64
|
visit(magic_link)
|
data/lib/passwordless/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: passwordless
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Mikkel Malmberg
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2024-01-24 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|
@@ -91,7 +91,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
91
91
|
- !ruby/object:Gem::Version
|
92
92
|
version: '0'
|
93
93
|
requirements: []
|
94
|
-
rubygems_version: 3.
|
94
|
+
rubygems_version: 3.5.5
|
95
95
|
signing_key:
|
96
96
|
specification_version: 4
|
97
97
|
summary: Add authentication to your app without all the ickyness of passwords.
|