devise-passwordless 0.7.0 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +44 -0
- data/README.md +397 -42
- data/UPGRADING.md +143 -0
- data/{lib/generators/devise/passwordless/templates/magic_links_controller.rb.erb → app/controllers/devise/magic_links_controller.rb} +2 -5
- data/app/controllers/devise/passwordless/sessions_controller.rb +49 -0
- data/app/mailers/devise/passwordless/mailer.rb +15 -0
- data/lib/devise/hooks/magic_link_authenticatable.rb +10 -0
- data/lib/devise/models/magic_link_authenticatable.rb +79 -9
- data/lib/devise/monkeypatch.rb +82 -0
- data/lib/devise/passwordless/login_token.rb +7 -52
- data/lib/devise/passwordless/rails.rb +25 -0
- data/lib/devise/passwordless/routing.rb +11 -0
- data/lib/devise/passwordless/tokenizers/message_encryptor_tokenizer.rb +66 -0
- data/lib/devise/passwordless/tokenizers/signed_global_id_tokenizer.rb +20 -0
- data/lib/devise/passwordless/version.rb +3 -1
- data/lib/devise/passwordless.rb +24 -0
- data/lib/devise/strategies/magic_link_authenticatable.rb +5 -25
- data/lib/generators/devise/passwordless/install_generator.rb +8 -11
- metadata +46 -17
- data/.github/workflows/test.yml +0 -45
- data/.gitignore +0 -16
- data/.rspec +0 -4
- data/.travis.yml +0 -7
- data/Gemfile +0 -13
- data/Rakefile +0 -6
- data/bin/console +0 -14
- data/bin/setup +0 -8
- data/devise-passwordless.gemspec +0 -41
- data/lib/devise/passwordless/mailer.rb +0 -12
- data/lib/generators/devise/passwordless/templates/sessions_controller.rb.erb +0 -34
@@ -20,28 +20,19 @@ module Devise
|
|
20
20
|
end
|
21
21
|
|
22
22
|
def authenticate!
|
23
|
+
resource_class = mapping.to
|
24
|
+
|
23
25
|
begin
|
24
|
-
|
25
|
-
rescue Devise::Passwordless::
|
26
|
+
resource, extra = resource_class.decode_passwordless_token(token, resource_class)
|
27
|
+
rescue Devise::Passwordless::InvalidOrExpiredTokenError
|
26
28
|
fail!(:magic_link_invalid)
|
27
29
|
return
|
28
30
|
end
|
29
31
|
|
30
|
-
resource = mapping.to.find_by(id: data["data"]["resource"]["key"])
|
31
|
-
|
32
|
-
if resource && Devise.passwordless_expire_old_tokens_on_sign_in
|
33
|
-
if (last_login = resource.try(:current_sign_in_at))
|
34
|
-
token_created_at = ActiveSupport::TimeZone["UTC"].at(data["created_at"])
|
35
|
-
if token_created_at < last_login
|
36
|
-
fail!(:magic_link_invalid)
|
37
|
-
return
|
38
|
-
end
|
39
|
-
end
|
40
|
-
end
|
41
|
-
|
42
32
|
if validate(resource)
|
43
33
|
remember_me(resource)
|
44
34
|
resource.after_magic_link_authentication
|
35
|
+
env['warden.magic_link_extra'] = extra.fetch('data', {}).delete('extra')
|
45
36
|
success!(resource)
|
46
37
|
else
|
47
38
|
fail!(:magic_link_invalid)
|
@@ -50,10 +41,6 @@ module Devise
|
|
50
41
|
|
51
42
|
private
|
52
43
|
|
53
|
-
def decode_passwordless_token
|
54
|
-
Devise::Passwordless::LoginToken.decode(self.token)
|
55
|
-
end
|
56
|
-
|
57
44
|
# Sets the authentication hash and the token from params_auth_hash or http_auth_hash.
|
58
45
|
def with_authentication_hash(auth_type, auth_values)
|
59
46
|
self.authentication_hash, self.authentication_type = {}, auth_type
|
@@ -67,10 +54,3 @@ module Devise
|
|
67
54
|
end
|
68
55
|
|
69
56
|
Warden::Strategies.add(:magic_link_authenticatable, Devise::Strategies::MagicLinkAuthenticatable)
|
70
|
-
|
71
|
-
Devise.add_module(:magic_link_authenticatable, {
|
72
|
-
strategy: true,
|
73
|
-
controller: :sessions,
|
74
|
-
route: :session,
|
75
|
-
model: "devise/models/magic_link_authenticatable",
|
76
|
-
})
|
@@ -11,23 +11,19 @@ module Devise::Passwordless
|
|
11
11
|
File.dirname(__FILE__)
|
12
12
|
end
|
13
13
|
|
14
|
-
def create_sessions_controller
|
15
|
-
template "sessions_controller.rb.erb", "app/controllers/devise/passwordless/sessions_controller.rb"
|
16
|
-
end
|
17
|
-
|
18
|
-
def create_magic_links_controller
|
19
|
-
template "magic_links_controller.rb.erb", "app/controllers/devise/passwordless/magic_links_controller.rb"
|
20
|
-
end
|
21
|
-
|
22
14
|
def update_devise_initializer
|
23
15
|
inject_into_file 'config/initializers/devise.rb', before: /^end$/ do <<~'CONFIG'.indent(2)
|
24
16
|
|
25
17
|
# ==> Configuration for :magic_link_authenticatable
|
26
18
|
|
27
|
-
# Need to use a custom Devise mailer in order to send magic links
|
28
|
-
|
19
|
+
# Need to use a custom Devise mailer in order to send magic links.
|
20
|
+
# If you're already using a custom mailer just have it inherit from
|
21
|
+
# Devise::Passwordless::Mailer instead of Devise::Mailer
|
29
22
|
config.mailer = "Devise::Passwordless::Mailer"
|
30
23
|
|
24
|
+
# Which algorithm to use for tokenizing magic links. See README for descriptions
|
25
|
+
config.passwordless_tokenizer = "SignedGlobalIDTokenizer"
|
26
|
+
|
31
27
|
# Time period after a magic login link is sent out that it will be valid for.
|
32
28
|
# config.passwordless_login_within = 20.minutes
|
33
29
|
|
@@ -51,7 +47,7 @@ module Devise::Passwordless
|
|
51
47
|
|
52
48
|
<p>You can login using the link below:</p>
|
53
49
|
|
54
|
-
<p><%= link_to "Log in to my account",
|
50
|
+
<p><%= link_to "Log in to my account", magic_link_url(@resource, @scope_name => {email: @resource.email, token: @token, remember_me: @remember_me}) %></p>
|
55
51
|
|
56
52
|
<p>Note that the link will expire in <%= Devise.passwordless_login_within.inspect %>.</p>
|
57
53
|
FILE
|
@@ -75,6 +71,7 @@ module Devise::Passwordless
|
|
75
71
|
passwordless: {
|
76
72
|
not_found_in_database: "Could not find a user for that email address",
|
77
73
|
magic_link_sent: "A login link has been sent to your email address. Please follow the link to log in to your account.",
|
74
|
+
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.",
|
78
75
|
},
|
79
76
|
failure: {
|
80
77
|
magic_link_invalid: "Invalid or expired login link.",
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: devise-passwordless
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 1.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Abe Voelker
|
8
8
|
autorequire:
|
9
|
-
bindir:
|
9
|
+
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2023-09-15 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: devise
|
@@ -24,6 +24,34 @@ dependencies:
|
|
24
24
|
- - ">="
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: '0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: globalid
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: timecop
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
27
55
|
description:
|
28
56
|
email:
|
29
57
|
- _@abevoelker.com
|
@@ -31,33 +59,34 @@ executables: []
|
|
31
59
|
extensions: []
|
32
60
|
extra_rdoc_files: []
|
33
61
|
files:
|
34
|
-
-
|
35
|
-
- ".gitignore"
|
36
|
-
- ".rspec"
|
37
|
-
- ".travis.yml"
|
38
|
-
- Gemfile
|
62
|
+
- CHANGELOG.md
|
39
63
|
- LICENSE.txt
|
40
64
|
- README.md
|
41
|
-
-
|
42
|
-
-
|
43
|
-
-
|
44
|
-
- devise
|
65
|
+
- UPGRADING.md
|
66
|
+
- app/controllers/devise/magic_links_controller.rb
|
67
|
+
- app/controllers/devise/passwordless/sessions_controller.rb
|
68
|
+
- app/mailers/devise/passwordless/mailer.rb
|
69
|
+
- lib/devise/hooks/magic_link_authenticatable.rb
|
45
70
|
- lib/devise/models/magic_link_authenticatable.rb
|
71
|
+
- lib/devise/monkeypatch.rb
|
46
72
|
- lib/devise/passwordless.rb
|
47
73
|
- lib/devise/passwordless/login_token.rb
|
48
|
-
- lib/devise/passwordless/
|
74
|
+
- lib/devise/passwordless/rails.rb
|
75
|
+
- lib/devise/passwordless/routing.rb
|
76
|
+
- lib/devise/passwordless/tokenizers/message_encryptor_tokenizer.rb
|
77
|
+
- lib/devise/passwordless/tokenizers/signed_global_id_tokenizer.rb
|
49
78
|
- lib/devise/passwordless/version.rb
|
50
79
|
- lib/devise/strategies/magic_link_authenticatable.rb
|
51
80
|
- lib/generators/devise/passwordless/install_generator.rb
|
52
|
-
- lib/generators/devise/passwordless/templates/magic_links_controller.rb.erb
|
53
|
-
- lib/generators/devise/passwordless/templates/sessions_controller.rb.erb
|
54
81
|
homepage: https://github.com/abevoelker/devise-passwordless
|
55
82
|
licenses:
|
56
83
|
- MIT
|
57
84
|
metadata:
|
58
85
|
homepage_uri: https://github.com/abevoelker/devise-passwordless
|
59
86
|
source_code_uri: https://github.com/abevoelker/devise-passwordless
|
60
|
-
post_install_message:
|
87
|
+
post_install_message: "\n Devise Passwordless v1.0 introduces major, backwards-incompatible
|
88
|
+
changes!\n Please see https://github.com/abevoelker/devise-passwordless/blob/master/UPGRADING.md\n
|
89
|
+
\ for a guide on upgrading, or CHANGELOG.md for a list of changes.\n "
|
61
90
|
rdoc_options: []
|
62
91
|
require_paths:
|
63
92
|
- lib
|
@@ -72,7 +101,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
72
101
|
- !ruby/object:Gem::Version
|
73
102
|
version: '0'
|
74
103
|
requirements: []
|
75
|
-
rubygems_version: 3.
|
104
|
+
rubygems_version: 3.4.10
|
76
105
|
signing_key:
|
77
106
|
specification_version: 4
|
78
107
|
summary: Passwordless (email-only) login strategy for Devise
|
data/.github/workflows/test.yml
DELETED
@@ -1,45 +0,0 @@
|
|
1
|
-
name: test
|
2
|
-
|
3
|
-
on:
|
4
|
-
push:
|
5
|
-
branches: [ master ]
|
6
|
-
pull_request:
|
7
|
-
branches: [ master ]
|
8
|
-
|
9
|
-
jobs:
|
10
|
-
test:
|
11
|
-
runs-on: ubuntu-latest
|
12
|
-
strategy:
|
13
|
-
matrix:
|
14
|
-
ruby-version:
|
15
|
-
- 3.0
|
16
|
-
- 2.7
|
17
|
-
- 2.6
|
18
|
-
- 2.5
|
19
|
-
gemfile:
|
20
|
-
- Gemfile-rails-7
|
21
|
-
- Gemfile-rails-6.1
|
22
|
-
- Gemfile-rails-6.0
|
23
|
-
exclude:
|
24
|
-
# Rails 7 requires Ruby 2.7+
|
25
|
-
- ruby-version: 2.5
|
26
|
-
gemfile: Gemfile-rails-7
|
27
|
-
- ruby-version: 2.6
|
28
|
-
gemfile: Gemfile-rails-7
|
29
|
-
steps:
|
30
|
-
- uses: actions/checkout@v2
|
31
|
-
- name: Set up Ruby ${{ matrix.ruby-version }}
|
32
|
-
uses: ruby/setup-ruby@477b21f02be01bcb8030d50f37cfec92bfa615b6
|
33
|
-
with:
|
34
|
-
ruby-version: ${{ matrix.ruby-version }}
|
35
|
-
- name: Run gem tests
|
36
|
-
run: |
|
37
|
-
bundle
|
38
|
-
bundle exec rake
|
39
|
-
- name: Run Rails dummy app tests
|
40
|
-
working-directory: ./spec/dummy_app
|
41
|
-
env:
|
42
|
-
BUNDLE_GEMFILE: gemfiles/${{ matrix.gemfile }}
|
43
|
-
run: |
|
44
|
-
bundle
|
45
|
-
bundle exec rake
|
data/.gitignore
DELETED
data/.rspec
DELETED
data/.travis.yml
DELETED
data/Gemfile
DELETED
@@ -1,13 +0,0 @@
|
|
1
|
-
source "https://rubygems.org"
|
2
|
-
|
3
|
-
git_source(:github) {|repo_name| "https://github.com/#{repo_name}" }
|
4
|
-
|
5
|
-
# Specify your gem's dependencies in devise-passwordless.gemspec
|
6
|
-
gemspec
|
7
|
-
|
8
|
-
gem "rake", "~> 10.0"
|
9
|
-
|
10
|
-
group :test do
|
11
|
-
gem "rspec", "~> 3.0"
|
12
|
-
gem "generator_spec"
|
13
|
-
end
|
data/Rakefile
DELETED
data/bin/console
DELETED
@@ -1,14 +0,0 @@
|
|
1
|
-
#!/usr/bin/env ruby
|
2
|
-
|
3
|
-
require "bundler/setup"
|
4
|
-
require "devise/passwordless"
|
5
|
-
|
6
|
-
# You can add fixtures and/or initialization code here to make experimenting
|
7
|
-
# with your gem easier. You can also use a different console, if you like.
|
8
|
-
|
9
|
-
# (If you use this, don't forget to add pry to your Gemfile!)
|
10
|
-
# require "pry"
|
11
|
-
# Pry.start
|
12
|
-
|
13
|
-
require "irb"
|
14
|
-
IRB.start(__FILE__)
|
data/bin/setup
DELETED
data/devise-passwordless.gemspec
DELETED
@@ -1,41 +0,0 @@
|
|
1
|
-
|
2
|
-
lib = File.expand_path("../lib", __FILE__)
|
3
|
-
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
-
require "devise/passwordless/version"
|
5
|
-
|
6
|
-
Gem::Specification.new do |spec|
|
7
|
-
spec.name = "devise-passwordless"
|
8
|
-
spec.version = Devise::Passwordless::VERSION
|
9
|
-
spec.authors = ["Abe Voelker"]
|
10
|
-
spec.email = ["_@abevoelker.com"]
|
11
|
-
|
12
|
-
spec.summary = %q{Passwordless (email-only) login strategy for Devise}
|
13
|
-
#spec.description = %q{TODO: Write a longer description or delete this line.}
|
14
|
-
spec.homepage = "https://github.com/abevoelker/devise-passwordless"
|
15
|
-
spec.license = "MIT"
|
16
|
-
|
17
|
-
# Prevent pushing this gem to RubyGems.org. To allow pushes either set the 'allowed_push_host'
|
18
|
-
# to allow pushing to a single host or delete this section to allow pushing to any host.
|
19
|
-
if spec.respond_to?(:metadata)
|
20
|
-
#spec.metadata["allowed_push_host"] = "TODO: Set to 'http://mygemserver.com'"
|
21
|
-
|
22
|
-
spec.metadata["homepage_uri"] = spec.homepage
|
23
|
-
spec.metadata["source_code_uri"] = spec.homepage
|
24
|
-
#spec.metadata["changelog_uri"] = "TODO: Put your gem's CHANGELOG.md URL here."
|
25
|
-
else
|
26
|
-
raise "RubyGems 2.0 or newer is required to protect against " \
|
27
|
-
"public gem pushes."
|
28
|
-
end
|
29
|
-
|
30
|
-
# Specify which files should be added to the gem when it is released.
|
31
|
-
# The `git ls-files -z` loads the files in the RubyGem that have been added into git.
|
32
|
-
spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
|
33
|
-
`git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
34
|
-
end
|
35
|
-
spec.bindir = "exe"
|
36
|
-
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
37
|
-
spec.require_paths = ["lib"]
|
38
|
-
spec.required_ruby_version = ">= 2.1.0"
|
39
|
-
|
40
|
-
spec.add_dependency "devise"
|
41
|
-
end
|
@@ -1,12 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
require "devise/mailer"
|
3
|
-
|
4
|
-
module Devise::Passwordless
|
5
|
-
class Mailer < Devise::Mailer
|
6
|
-
def magic_link(record, token, remember_me, opts = {})
|
7
|
-
@token = token
|
8
|
-
@remember_me = remember_me
|
9
|
-
devise_mail(record, :magic_link, opts)
|
10
|
-
end
|
11
|
-
end
|
12
|
-
end
|
@@ -1,34 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
<% module_namespacing do -%>
|
4
|
-
class Devise::Passwordless::SessionsController < Devise::SessionsController
|
5
|
-
def create
|
6
|
-
self.resource = resource_class.find_by(email: create_params[:email])
|
7
|
-
if self.resource
|
8
|
-
resource.send_magic_link(create_params[:remember_me])
|
9
|
-
set_flash_message(:notice, :magic_link_sent, now: true)
|
10
|
-
else
|
11
|
-
set_flash_message(:alert, :not_found_in_database, now: true)
|
12
|
-
end
|
13
|
-
|
14
|
-
self.resource = resource_class.new(create_params)
|
15
|
-
render :new
|
16
|
-
end
|
17
|
-
|
18
|
-
protected
|
19
|
-
|
20
|
-
def translation_scope
|
21
|
-
if action_name == "create"
|
22
|
-
"devise.passwordless"
|
23
|
-
else
|
24
|
-
super
|
25
|
-
end
|
26
|
-
end
|
27
|
-
|
28
|
-
private
|
29
|
-
|
30
|
-
def create_params
|
31
|
-
resource_params.permit(:email, :remember_me)
|
32
|
-
end
|
33
|
-
end
|
34
|
-
<% end -%>
|