devise-passwordless 1.0.2 → 1.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 +4 -4
- data/CHANGELOG.md +9 -9
- data/README.md +76 -1
- data/UPGRADING.md +1 -1
- data/app/controllers/devise/magic_links_controller.rb +1 -1
- data/app/controllers/devise/passwordless/sessions_controller.rb +6 -2
- data/lib/devise/hooks/magic_link_authenticatable.rb +1 -1
- data/lib/devise/models/magic_link_authenticatable.rb +18 -15
- data/lib/devise/monkeypatch.rb +8 -7
- data/lib/devise/passwordless/rails.rb +2 -2
- data/lib/devise/passwordless/routing.rb +4 -5
- data/lib/devise/passwordless/tokenizers/message_encryptor_tokenizer.rb +3 -3
- data/lib/devise/passwordless/version.rb +1 -1
- data/lib/devise/passwordless.rb +8 -7
- data/lib/devise/strategies/magic_link_authenticatable.rb +4 -4
- data/lib/generators/devise/passwordless/install_generator.rb +47 -47
- metadata +26 -10
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 63d338fedbac04369b95c60ac414a5ef6f7e834b29248ea09e9952de209ac6be
|
4
|
+
data.tar.gz: 82001a3f59b41ad9465a544f3bab880fa2e3b9c980a483f85a3ae0dc88502527
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7ff30f11ad729c65cc41ad73a70ef699fdd88eb480bce105c3a0abd5739719090413569880684c2603606a66091e3ccaf71c68e6625a89846742b8cb93da8520
|
7
|
+
data.tar.gz: d757d7362960d665530dce2af126e80b05c0d447060d17832e61a8ff31c06cb7a70eadbd4985ee595e8fc7c477a1447555bd99280a4c7f86e82d66fe883344b7
|
data/CHANGELOG.md
CHANGED
@@ -41,12 +41,12 @@
|
|
41
41
|
[@thimo]: https://github.com/thimo
|
42
42
|
[@til]: https://github.com/til
|
43
43
|
|
44
|
-
[#13]: https://github.com/
|
45
|
-
[#19]: https://github.com/
|
46
|
-
[#21]: https://github.com/
|
47
|
-
[#22]: https://github.com/
|
48
|
-
[#23]: https://github.com/
|
49
|
-
[#27]: https://github.com/
|
50
|
-
[#33]: https://github.com/
|
51
|
-
[#36]: https://github.com/
|
52
|
-
[#39]: https://github.com/
|
44
|
+
[#13]: https://github.com/devise-passwordless/devise-passwordless/issues/13
|
45
|
+
[#19]: https://github.com/devise-passwordless/devise-passwordless/pull/19
|
46
|
+
[#21]: https://github.com/devise-passwordless/devise-passwordless/pull/21
|
47
|
+
[#22]: https://github.com/devise-passwordless/devise-passwordless/issues/22
|
48
|
+
[#23]: https://github.com/devise-passwordless/devise-passwordless/pull/23
|
49
|
+
[#27]: https://github.com/devise-passwordless/devise-passwordless/pull/27
|
50
|
+
[#33]: https://github.com/devise-passwordless/devise-passwordless/pull/33
|
51
|
+
[#36]: https://github.com/devise-passwordless/devise-passwordless/pull/36
|
52
|
+
[#39]: https://github.com/devise-passwordless/devise-passwordless/issues/39
|
data/README.md
CHANGED
@@ -18,7 +18,7 @@ A passwordless login strategy for [Devise] using emailed magic links
|
|
18
18
|
If you're upgrading from 0.x to 1.0, read [the upgrade guide][] for
|
19
19
|
a list of changes you'll need to make.
|
20
20
|
|
21
|
-
[the upgrade guide]: https://github.com/
|
21
|
+
[the upgrade guide]: https://github.com/devise-passwordless/devise-passwordless/blob/main/UPGRADING.md
|
22
22
|
|
23
23
|
## Installation
|
24
24
|
|
@@ -332,6 +332,52 @@ end
|
|
332
332
|
config.passwordless_tokenizer = "::LuckyUserTokenizer"
|
333
333
|
```
|
334
334
|
|
335
|
+
#### Single-use tokenizer
|
336
|
+
|
337
|
+
With Rails 7.1 and [generates_token_for](https://api.rubyonrails.org/classes/ActiveRecord/TokenFor/ClassMethods.html#method-i-generates_token_for) you can create a single-use tokenizer. For example:
|
338
|
+
|
339
|
+
```ruby
|
340
|
+
class SingleUseTokenizer
|
341
|
+
def self.decode(token, resource_class, *args)
|
342
|
+
resource = resource_class.find_by_token_for(:passwordless_login, token)
|
343
|
+
raise Devise::Passwordless::ExpiredTokenError unless resource
|
344
|
+
raise Devise::Passwordless::InvalidTokenError unless resource.is_a?(resource_class)
|
345
|
+
[resource, {}]
|
346
|
+
end
|
347
|
+
|
348
|
+
def self.encode(resource, *args)
|
349
|
+
resource.generate_token_for(:passwordless_login)
|
350
|
+
end
|
351
|
+
end
|
352
|
+
```
|
353
|
+
|
354
|
+
Then in your `User` model:
|
355
|
+
|
356
|
+
```ruby
|
357
|
+
generates_token_for :passwordless_login, expires_in: passwordless_login_within do
|
358
|
+
current_sign_in_at
|
359
|
+
end
|
360
|
+
```
|
361
|
+
|
362
|
+
It relies on the `current_sign_in_at` attribute changing on a user after a successful login.
|
363
|
+
Once it changes, the same token will always be invalid and cannot be reused.
|
364
|
+
|
365
|
+
Since the same link cannot be visited twice, you may need to ignore `HEAD` requests
|
366
|
+
to avoid some email clients (ex: Outlook) visiting links with a `HEAD` request before
|
367
|
+
the `GET` request with something like:
|
368
|
+
|
369
|
+
```ruby
|
370
|
+
module Users
|
371
|
+
class PasswordlessMagicLinksController < Devise::MagicLinksController
|
372
|
+
def show
|
373
|
+
return render(plain: '') if request.method == 'HEAD'
|
374
|
+
|
375
|
+
super
|
376
|
+
end
|
377
|
+
end
|
378
|
+
end
|
379
|
+
```
|
380
|
+
|
335
381
|
## Multiple user (resource) types
|
336
382
|
|
337
383
|
Devise supports multiple resource types, so we do too.
|
@@ -590,9 +636,38 @@ Other Ruby libraries that offer passwordless authentication:
|
|
590
636
|
* [passwordless](https://github.com/mikker/passwordless)
|
591
637
|
* [magic-link](https://github.com/dvanderbeek/magic-link)
|
592
638
|
|
639
|
+
## Gem development
|
640
|
+
|
641
|
+
### Running tests
|
642
|
+
|
643
|
+
To run the set of basic gem tests, do:
|
644
|
+
|
645
|
+
```
|
646
|
+
$ bundle
|
647
|
+
$ bundle exec rake
|
648
|
+
```
|
649
|
+
|
650
|
+
The more important and more thorough tests utilize a "dummy" Rails application.
|
651
|
+
|
652
|
+
To run this full suite of dummy app tests across all supported versions of Ruby and Rails,
|
653
|
+
you can use [nektos/act][] to run the same tests that run in our GitHub Workflow CI:
|
654
|
+
|
655
|
+
```
|
656
|
+
$ act -W .github/workflows/test.yml -P ubuntu-latest=ghcr.io/catthehacker/ubuntu:act-latest --no-cache-server
|
657
|
+
```
|
658
|
+
|
659
|
+
To run only against specific versions of Ruby or Rails, you can use the `--matrix` flag of `act`:
|
660
|
+
|
661
|
+
```
|
662
|
+
$ act -W .github/workflows/test.yml -P ubuntu-latest=ghcr.io/catthehacker/ubuntu:act-latest --no-cache-server --matrix ruby-version:3.2 --matrix rails-version:7 --matrix rails-version:6.1
|
663
|
+
```
|
664
|
+
|
665
|
+
The above example will only run the tests for Rails 7 and Rails 6.1 using Ruby 3.2.
|
666
|
+
|
593
667
|
## License
|
594
668
|
|
595
669
|
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
596
670
|
|
597
671
|
[Devise]: https://github.com/heartcombo/devise
|
598
672
|
[devise-i18n]: https://github.com/heartcombo/devise#i18n
|
673
|
+
[nektos/act]: https://github.com/nektos/act
|
data/UPGRADING.md
CHANGED
@@ -140,4 +140,4 @@ to have a successful upgrade:
|
|
140
140
|
re-rendering the sign-in form.
|
141
141
|
* [See the README][after-magic-link-sent-readme] for details on how to customize the redirect behavior
|
142
142
|
|
143
|
-
[after-magic-link-sent-readme]: https://github.com/
|
143
|
+
[after-magic-link-sent-readme]: https://github.com/devise-passwordless/devise-passwordless#redirecting-after-magic-link-is-sent
|
@@ -16,7 +16,7 @@ class Devise::MagicLinksController < DeviseController
|
|
16
16
|
|
17
17
|
def auth_options
|
18
18
|
mapping = Devise.mappings[resource_name]
|
19
|
-
{
|
19
|
+
{scope: resource_name, recall: "#{mapping.controllers[:sessions]}#new"}
|
20
20
|
end
|
21
21
|
|
22
22
|
def translation_scope
|
@@ -1,7 +1,7 @@
|
|
1
1
|
class Devise::Passwordless::SessionsController < Devise::SessionsController
|
2
2
|
def create
|
3
|
-
if (self.resource = resource_class.
|
4
|
-
|
3
|
+
if (self.resource = resource_class.find_for_authentication(email: create_params[:email]))
|
4
|
+
send_magic_link(resource)
|
5
5
|
if Devise.paranoid
|
6
6
|
set_flash_message!(:notice, :magic_link_sent_paranoid)
|
7
7
|
else
|
@@ -23,6 +23,10 @@ class Devise::Passwordless::SessionsController < Devise::SessionsController
|
|
23
23
|
|
24
24
|
protected
|
25
25
|
|
26
|
+
def send_magic_link(resource)
|
27
|
+
resource.send_magic_link(remember_me: create_params[:remember_me])
|
28
|
+
end
|
29
|
+
|
26
30
|
def translation_scope
|
27
31
|
if action_name == "create"
|
28
32
|
"devise.passwordless"
|
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
# Deny user access when magic link authentication is disabled
|
4
4
|
Warden::Manager.after_set_user do |record, warden, options|
|
5
|
-
if record
|
5
|
+
if record&.respond_to?(:active_for_magic_link_authentication?) && !record.active_for_magic_link_authentication? && warden.winning_strategy.is_a?(Devise::Strategies::MagicLinkAuthenticatable)
|
6
6
|
scope = options[:scope]
|
7
7
|
warden.logout(scope)
|
8
8
|
throw :warden, scope: scope, message: record.magic_link_inactive_message
|
@@ -1,5 +1,5 @@
|
|
1
|
-
require
|
2
|
-
require
|
1
|
+
require "devise/strategies/magic_link_authenticatable"
|
2
|
+
require "devise/hooks/magic_link_authenticatable"
|
3
3
|
|
4
4
|
module Devise
|
5
5
|
module Models
|
@@ -34,7 +34,7 @@ module Devise
|
|
34
34
|
end
|
35
35
|
|
36
36
|
def send_magic_link(remember_me: false, **kwargs)
|
37
|
-
token =
|
37
|
+
token = encode_passwordless_token
|
38
38
|
send_devise_notification(:magic_link, token, remember_me, **kwargs)
|
39
39
|
end
|
40
40
|
|
@@ -68,15 +68,19 @@ module Devise
|
|
68
68
|
|
69
69
|
module ClassMethods
|
70
70
|
def passwordless_tokenizer_class
|
71
|
-
@passwordless_tokenizer_class ||=
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
71
|
+
@passwordless_tokenizer_class ||= if passwordless_tokenizer.is_a?(Class)
|
72
|
+
|
73
|
+
passwordless_tokenizer
|
74
|
+
|
75
|
+
else
|
76
|
+
(
|
77
|
+
passwordless_tokenizer.start_with?("::") ? (
|
78
|
+
passwordless_tokenizer.constantize
|
79
|
+
) : (
|
80
|
+
"Devise::Passwordless::#{passwordless_tokenizer}".constantize
|
81
|
+
)
|
82
|
+
)
|
83
|
+
end
|
80
84
|
end
|
81
85
|
|
82
86
|
def decode_passwordless_token(*args, **kwargs)
|
@@ -94,9 +98,8 @@ module Devise
|
|
94
98
|
Devise::Models.config(self,
|
95
99
|
:passwordless_tokenizer,
|
96
100
|
:passwordless_login_within,
|
97
|
-
|
98
|
-
:passwordless_expire_old_tokens_on_sign_in
|
99
|
-
)
|
101
|
+
# :passwordless_secret_key,
|
102
|
+
:passwordless_expire_old_tokens_on_sign_in)
|
100
103
|
end
|
101
104
|
end
|
102
105
|
end
|
data/lib/devise/monkeypatch.rb
CHANGED
@@ -3,27 +3,28 @@
|
|
3
3
|
module Devise
|
4
4
|
class Mapping
|
5
5
|
def routes
|
6
|
-
@routes ||= ROUTES.values_at(*
|
6
|
+
@routes ||= ROUTES.values_at(*modules).compact.flatten.uniq
|
7
7
|
end
|
8
8
|
end
|
9
|
+
|
9
10
|
def self.add_module(module_name, options = {})
|
10
11
|
options.assert_valid_keys(:strategy, :model, :controller, :route, :no_input, :insert_at)
|
11
12
|
|
12
13
|
ALL.insert (options[:insert_at] || -1), module_name
|
13
14
|
|
14
|
-
if strategy = options[:strategy]
|
15
|
-
strategy = (strategy == true ? module_name : strategy)
|
15
|
+
if (strategy = options[:strategy])
|
16
|
+
strategy = ((strategy == true) ? module_name : strategy)
|
16
17
|
STRATEGIES[module_name] = strategy
|
17
18
|
end
|
18
19
|
|
19
|
-
if controller = options[:controller]
|
20
|
-
controller = (controller == true ? module_name : controller)
|
20
|
+
if (controller = options[:controller])
|
21
|
+
controller = ((controller == true) ? module_name : controller)
|
21
22
|
CONTROLLERS[module_name] = controller
|
22
23
|
end
|
23
24
|
|
24
25
|
NO_INPUT << strategy if options[:no_input]
|
25
26
|
|
26
|
-
if route = options[:route]
|
27
|
+
if (route = options[:route])
|
27
28
|
routes = {}
|
28
29
|
|
29
30
|
case route
|
@@ -51,7 +52,7 @@ module Devise
|
|
51
52
|
end
|
52
53
|
|
53
54
|
if options[:model]
|
54
|
-
path = (options[:model] == true ? "devise/models/#{module_name}" : options[:model])
|
55
|
+
path = ((options[:model] == true) ? "devise/models/#{module_name}" : options[:model])
|
55
56
|
camelized = ActiveSupport::Inflector.camelize(module_name.to_s)
|
56
57
|
Devise::Models.send(:autoload, camelized.to_sym, path)
|
57
58
|
end
|
@@ -6,8 +6,8 @@ module Devise::Passwordless
|
|
6
6
|
Devise.add_module(:magic_link_authenticatable, {
|
7
7
|
model: true,
|
8
8
|
strategy: true,
|
9
|
-
route: {
|
10
|
-
controller: :sessions
|
9
|
+
route: {magic_link: [nil, :show], session: [nil, :new, :destroy]},
|
10
|
+
controller: :sessions
|
11
11
|
})
|
12
12
|
end
|
13
13
|
|
@@ -1,11 +1,10 @@
|
|
1
1
|
module ActionDispatch::Routing
|
2
2
|
class Mapper
|
3
|
-
|
4
3
|
protected
|
5
4
|
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
5
|
+
def devise_magic_link(mapping, controllers) # :nodoc:
|
6
|
+
resource :magic_link, only: [:show],
|
7
|
+
path: mapping.path_names[:magic_link], controller: controllers[:magic_links]
|
8
|
+
end
|
10
9
|
end
|
11
10
|
end
|
@@ -10,10 +10,10 @@ module Devise::Passwordless
|
|
10
10
|
data: {
|
11
11
|
resource: {
|
12
12
|
key: resource.to_key,
|
13
|
-
email: resource.email
|
14
|
-
}
|
13
|
+
email: resource.email
|
14
|
+
}
|
15
15
|
},
|
16
|
-
created_at: now.to_f
|
16
|
+
created_at: now.to_f
|
17
17
|
}
|
18
18
|
data[:data][:extra] = extra if extra
|
19
19
|
data[:expires_at] = expires_at.to_f if expires_at
|
data/lib/devise/passwordless.rb
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
require "devise"
|
1
2
|
require "devise/passwordless/version"
|
2
3
|
require "devise/monkeypatch"
|
3
4
|
require "devise/passwordless/rails" if defined?(Rails::Engine)
|
@@ -9,7 +10,9 @@ require "devise/passwordless/tokenizers/signed_global_id_tokenizer"
|
|
9
10
|
module Devise
|
10
11
|
module Passwordless
|
11
12
|
class InvalidOrExpiredTokenError < StandardError; end
|
13
|
+
|
12
14
|
class InvalidTokenError < InvalidOrExpiredTokenError; end
|
15
|
+
|
13
16
|
class ExpiredTokenError < InvalidOrExpiredTokenError; end
|
14
17
|
|
15
18
|
def self.deprecator
|
@@ -30,14 +33,12 @@ module Devise
|
|
30
33
|
"leak out of your logs."
|
31
34
|
|
32
35
|
def self.check_filter_parameters(params)
|
33
|
-
|
34
|
-
|
35
|
-
warn FILTER_PARAMS_WARNING
|
36
|
-
end
|
37
|
-
# Cancel the check if filter_parameters contains regular expressions or other exotic values
|
38
|
-
rescue NoMethodError
|
39
|
-
return
|
36
|
+
unless params.find { |p| p.to_sym == :token }
|
37
|
+
warn FILTER_PARAMS_WARNING
|
40
38
|
end
|
39
|
+
# Cancel the check if filter_parameters contains regular expressions or other exotic values
|
40
|
+
rescue NoMethodError
|
41
|
+
nil
|
41
42
|
end
|
42
43
|
end
|
43
44
|
end
|
@@ -7,8 +7,8 @@ require "devise/passwordless/login_token"
|
|
7
7
|
module Devise
|
8
8
|
module Strategies
|
9
9
|
class MagicLinkAuthenticatable < Authenticatable
|
10
|
-
#undef :password
|
11
|
-
#undef :password=
|
10
|
+
# undef :password
|
11
|
+
# undef :password=
|
12
12
|
attr_accessor :token
|
13
13
|
|
14
14
|
def valid_for_http_auth?
|
@@ -32,7 +32,7 @@ module Devise
|
|
32
32
|
if validate(resource)
|
33
33
|
remember_me(resource)
|
34
34
|
resource.after_magic_link_authentication
|
35
|
-
env[
|
35
|
+
env["warden.magic_link_extra"] = extra.fetch("data", {}).delete("extra")
|
36
36
|
success!(resource)
|
37
37
|
else
|
38
38
|
fail!(:magic_link_invalid)
|
@@ -47,7 +47,7 @@ module Devise
|
|
47
47
|
self.token = auth_values[:token]
|
48
48
|
|
49
49
|
parse_authentication_key_values(auth_values, authentication_keys) &&
|
50
|
-
|
50
|
+
parse_authentication_key_values(request_values, request_keys)
|
51
51
|
end
|
52
52
|
end
|
53
53
|
end
|
@@ -12,46 +12,48 @@ module Devise::Passwordless
|
|
12
12
|
end
|
13
13
|
|
14
14
|
def update_devise_initializer
|
15
|
-
inject_into_file
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
15
|
+
inject_into_file "config/initializers/devise.rb", before: /^end$/ do
|
16
|
+
<<~CONFIG.indent(2)
|
17
|
+
|
18
|
+
# ==> Configuration for :magic_link_authenticatable
|
19
|
+
|
20
|
+
# Need to use a custom Devise mailer in order to send magic links.
|
21
|
+
# If you're already using a custom mailer just have it inherit from
|
22
|
+
# Devise::Passwordless::Mailer instead of Devise::Mailer
|
23
|
+
config.mailer = "Devise::Passwordless::Mailer"
|
24
|
+
|
25
|
+
# Which algorithm to use for tokenizing magic links. See README for descriptions
|
26
|
+
config.passwordless_tokenizer = "SignedGlobalIDTokenizer"
|
27
|
+
|
28
|
+
# Time period after a magic login link is sent out that it will be valid for.
|
29
|
+
# config.passwordless_login_within = 20.minutes
|
30
|
+
|
31
|
+
# The secret key used to generate passwordless login tokens. The default value
|
32
|
+
# is nil, which means defer to Devise's `secret_key` config value. Changing this
|
33
|
+
# key will render invalid all existing passwordless login tokens. You can
|
34
|
+
# generate your own secret value with e.g. `rake secret`
|
35
|
+
# config.passwordless_secret_key = nil
|
36
|
+
|
37
|
+
# When using the :trackable module and MessageEncryptorTokenizer, set to true to
|
38
|
+
# consider magic link tokens generated before the user's current sign in time to
|
39
|
+
# be expired. In other words, each time you sign in, all existing magic links
|
40
|
+
# will be considered invalid.
|
41
|
+
# config.passwordless_expire_old_tokens_on_sign_in = false
|
42
|
+
CONFIG
|
42
43
|
end
|
43
44
|
end
|
44
45
|
|
45
46
|
def add_mailer_view
|
46
|
-
create_file "app/views/devise/mailer/magic_link.html.erb" do
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
47
|
+
create_file "app/views/devise/mailer/magic_link.html.erb" do
|
48
|
+
<<~FILE
|
49
|
+
<p>Hello <%= @resource.email %>!</p>
|
50
|
+
|
51
|
+
<p>You can login using the link below:</p>
|
52
|
+
|
53
|
+
<p><%= link_to "Log in to my account", magic_link_url(@resource, @scope_name => {email: @resource.email, token: @token, remember_me: @remember_me}) %></p>
|
54
|
+
|
55
|
+
<p>Note that the link will expire in <%= Devise.passwordless_login_within.inspect %>.</p>
|
56
|
+
FILE
|
55
57
|
end
|
56
58
|
end
|
57
59
|
|
@@ -72,15 +74,15 @@ module Devise::Passwordless
|
|
72
74
|
passwordless: {
|
73
75
|
not_found_in_database: "Could not find a user for that email address",
|
74
76
|
magic_link_sent: "A login link has been sent to your email address. Please follow the link to log in to your account.",
|
75
|
-
magic_link_sent_paranoid: "If your account exists, you will receive an email with a login link. Please follow the link to log in to your account."
|
77
|
+
magic_link_sent_paranoid: "If your account exists, you will receive an email with a login link. Please follow the link to log in to your account."
|
76
78
|
},
|
77
79
|
failure: {
|
78
|
-
magic_link_invalid: "Invalid or expired login link."
|
80
|
+
magic_link_invalid: "Invalid or expired login link."
|
79
81
|
},
|
80
82
|
mailer: {
|
81
83
|
magic_link: {
|
82
|
-
subject: "Here's your magic login link ✨"
|
83
|
-
}
|
84
|
+
subject: "Here's your magic login link ✨"
|
85
|
+
}
|
84
86
|
}
|
85
87
|
}
|
86
88
|
}
|
@@ -90,9 +92,7 @@ module Devise::Passwordless
|
|
90
92
|
say_status :identical, devise_yaml, :blue
|
91
93
|
else
|
92
94
|
in_root do
|
93
|
-
File.
|
94
|
-
f.write(force_double_quote_yaml(merged_config.to_yaml))
|
95
|
-
end
|
95
|
+
File.write(devise_yaml, force_double_quote_yaml(merged_config.to_yaml))
|
96
96
|
end
|
97
97
|
say_status :insert, devise_yaml, :green
|
98
98
|
end
|
@@ -106,17 +106,17 @@ module Devise::Passwordless
|
|
106
106
|
|
107
107
|
# First pass, quote everything
|
108
108
|
ast.grep(Psych::Nodes::Scalar).each do |node|
|
109
|
-
node.plain
|
109
|
+
node.plain = false
|
110
110
|
node.quoted = true
|
111
|
-
node.style
|
111
|
+
node.style = Psych::Nodes::Scalar::DOUBLE_QUOTED
|
112
112
|
end
|
113
113
|
|
114
114
|
# Second pass, unquote keys
|
115
115
|
ast.grep(Psych::Nodes::Mapping).each do |node|
|
116
116
|
node.children.each_slice(2) do |k, _|
|
117
|
-
k.plain
|
117
|
+
k.plain = true
|
118
118
|
k.quoted = false
|
119
|
-
k.style
|
119
|
+
k.style = Psych::Nodes::Scalar::ANY
|
120
120
|
end
|
121
121
|
end
|
122
122
|
|
metadata
CHANGED
@@ -1,14 +1,15 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: devise-passwordless
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0
|
4
|
+
version: 1.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Abe Voelker
|
8
|
-
|
8
|
+
- Jennifer Konikowski
|
9
|
+
autorequire:
|
9
10
|
bindir: bin
|
10
11
|
cert_chain: []
|
11
|
-
date:
|
12
|
+
date: 2025-04-13 00:00:00.000000000 Z
|
12
13
|
dependencies:
|
13
14
|
- !ruby/object:Gem::Dependency
|
14
15
|
name: devise
|
@@ -38,6 +39,20 @@ dependencies:
|
|
38
39
|
- - ">="
|
39
40
|
- !ruby/object:Gem::Version
|
40
41
|
version: '0'
|
42
|
+
- !ruby/object:Gem::Dependency
|
43
|
+
name: standard
|
44
|
+
requirement: !ruby/object:Gem::Requirement
|
45
|
+
requirements:
|
46
|
+
- - ">="
|
47
|
+
- !ruby/object:Gem::Version
|
48
|
+
version: '0'
|
49
|
+
type: :development
|
50
|
+
prerelease: false
|
51
|
+
version_requirements: !ruby/object:Gem::Requirement
|
52
|
+
requirements:
|
53
|
+
- - ">="
|
54
|
+
- !ruby/object:Gem::Version
|
55
|
+
version: '0'
|
41
56
|
- !ruby/object:Gem::Dependency
|
42
57
|
name: timecop
|
43
58
|
requirement: !ruby/object:Gem::Requirement
|
@@ -52,9 +67,10 @@ dependencies:
|
|
52
67
|
- - ">="
|
53
68
|
- !ruby/object:Gem::Version
|
54
69
|
version: '0'
|
55
|
-
description:
|
70
|
+
description:
|
56
71
|
email:
|
57
72
|
- _@abevoelker.com
|
73
|
+
- passwordless@jmkoni.com
|
58
74
|
executables: []
|
59
75
|
extensions: []
|
60
76
|
extra_rdoc_files: []
|
@@ -78,14 +94,14 @@ files:
|
|
78
94
|
- lib/devise/passwordless/version.rb
|
79
95
|
- lib/devise/strategies/magic_link_authenticatable.rb
|
80
96
|
- lib/generators/devise/passwordless/install_generator.rb
|
81
|
-
homepage: https://github.com/
|
97
|
+
homepage: https://github.com/devise-passwordless/devise-passwordless
|
82
98
|
licenses:
|
83
99
|
- MIT
|
84
100
|
metadata:
|
85
|
-
homepage_uri: https://github.com/
|
86
|
-
source_code_uri: https://github.com/
|
101
|
+
homepage_uri: https://github.com/devise-passwordless/devise-passwordless
|
102
|
+
source_code_uri: https://github.com/devise-passwordless/devise-passwordless
|
87
103
|
post_install_message: "\n Devise Passwordless v1.0 introduces major, backwards-incompatible
|
88
|
-
changes!\n Please see https://github.com/
|
104
|
+
changes!\n Please see https://github.com/devise-passwordless/devise-passwordless/blob/main/UPGRADING.md\n
|
89
105
|
\ for a guide on upgrading, or CHANGELOG.md for a list of changes.\n "
|
90
106
|
rdoc_options: []
|
91
107
|
require_paths:
|
@@ -94,7 +110,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
94
110
|
requirements:
|
95
111
|
- - ">="
|
96
112
|
- !ruby/object:Gem::Version
|
97
|
-
version: 2.
|
113
|
+
version: 2.7.0
|
98
114
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
99
115
|
requirements:
|
100
116
|
- - ">="
|
@@ -102,7 +118,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
102
118
|
version: '0'
|
103
119
|
requirements: []
|
104
120
|
rubygems_version: 3.4.19
|
105
|
-
signing_key:
|
121
|
+
signing_key:
|
106
122
|
specification_version: 4
|
107
123
|
summary: Passwordless (email-only) login strategy for Devise
|
108
124
|
test_files: []
|