passwordless 0.12.0 → 1.0.0.beta1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +108 -191
- data/Rakefile +7 -7
- data/app/controllers/passwordless/sessions_controller.rb +121 -39
- data/app/mailers/passwordless/mailer.rb +13 -11
- data/app/models/passwordless/session.rb +25 -12
- data/app/views/passwordless/mailer/sign_in.text.erb +1 -0
- data/app/views/passwordless/sessions/new.html.erb +8 -4
- data/app/views/passwordless/sessions/show.html.erb +5 -0
- data/config/locales/en.yml +18 -6
- data/config/routes.rb +0 -4
- data/db/migrate/20171104221735_create_passwordless_sessions.rb +1 -3
- data/lib/generators/passwordless/views_generator.rb +5 -5
- data/lib/passwordless/config.rb +71 -0
- data/lib/passwordless/controller_helpers.rb +32 -70
- data/lib/passwordless/engine.rb +2 -6
- data/lib/passwordless/errors.rb +4 -0
- data/lib/passwordless/router_helpers.rb +24 -10
- data/lib/passwordless/short_token_generator.rb +9 -0
- data/lib/passwordless/test_helpers.rb +19 -9
- data/lib/passwordless/token_digest.rb +18 -0
- data/lib/passwordless/version.rb +1 -1
- data/lib/passwordless.rb +5 -19
- metadata +12 -51
- data/app/views/passwordless/mailer/magic_link.text.erb +0 -1
- data/lib/passwordless/url_safe_base_64_generator.rb +0 -15
data/lib/passwordless/engine.rb
CHANGED
@@ -3,17 +3,13 @@
|
|
3
3
|
module Passwordless
|
4
4
|
# Engine that runs the passwordless gem.
|
5
5
|
class Engine < ::Rails::Engine
|
6
|
-
isolate_namespace Passwordless
|
7
|
-
|
8
6
|
config.to_prepare do
|
9
7
|
require "passwordless/router_helpers"
|
10
|
-
|
11
|
-
ActionDispatch::Routing::Mapper.include RouterHelpers
|
12
8
|
require "passwordless/model_helpers"
|
13
|
-
|
14
|
-
ActiveRecord::Base.extend ModelHelpers
|
15
9
|
require "passwordless/controller_helpers"
|
16
10
|
|
11
|
+
ActionDispatch::Routing::Mapper.include RouterHelpers
|
12
|
+
ActiveRecord::Base.extend ModelHelpers
|
17
13
|
end
|
18
14
|
|
19
15
|
config.before_initialize do |app|
|
data/lib/passwordless/errors.rb
CHANGED
@@ -8,6 +8,8 @@ module Passwordless
|
|
8
8
|
# passwordless_for :users
|
9
9
|
# # or with options ...
|
10
10
|
# passwordless_for :users, at: 'session_stuff', as: :user_session_things
|
11
|
+
# # or with a custom controller ...
|
12
|
+
# passwordless_for :users, controller: 'my_custom_controller'
|
11
13
|
# @param resource [Symbol] the pluralized symbol of a Model (e.g - :users).
|
12
14
|
# @param at [String] Optional - provide custom path for the passwordless
|
13
15
|
# engine to get mounted at (using the above example your URLs end
|
@@ -16,17 +18,29 @@ module Passwordless
|
|
16
18
|
# helpers (using the above example in a view:
|
17
19
|
# <%= link_to 'Sign in', user_session_things.sign_in_path %>).
|
18
20
|
# (Default: resource.to_s)
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
as: mount_as,
|
26
|
-
defaults: {authenticatable: resource.to_s.singularize}
|
27
|
-
)
|
21
|
+
# @param controller [String] Optional - provide a custom controller for
|
22
|
+
# sessions to use (using the above example the controller called would be MyCustomController
|
23
|
+
# (Default: 'passwordless/sessions')
|
24
|
+
def passwordless_for(resource, at: :na, as: :na, controller: "passwordless/sessions")
|
25
|
+
at == :na && at = "/#{resource.to_s}"
|
26
|
+
as == :na && as = "#{resource.to_s}_"
|
28
27
|
|
29
|
-
|
28
|
+
plural = resource.to_s
|
29
|
+
singular = plural.singularize
|
30
|
+
|
31
|
+
defaults = {
|
32
|
+
authenticatable: singular,
|
33
|
+
resource: resource,
|
34
|
+
}
|
35
|
+
|
36
|
+
scope(defaults: defaults) do
|
37
|
+
get("#{at}/sign_in", to: "#{controller}#new", as: :"#{as}sign_in")
|
38
|
+
post("#{at}/sign_in", to: "#{controller}#create")
|
39
|
+
get("#{at}/sign_in/:id", to: "#{controller}#show", as: :"verify_#{as}sign_in")
|
40
|
+
get("#{at}/sign_in/:id/:token", to: "#{controller}#confirm", as: :"confirm_#{as}sign_in")
|
41
|
+
patch("#{at}/sign_in/:id", to: "#{controller}#update")
|
42
|
+
match("#{at}/sign_out", to: "#{controller}#destroy", via: %i[get delete], as: :"#{as}sign_out")
|
43
|
+
end
|
30
44
|
end
|
31
45
|
end
|
32
46
|
end
|
@@ -2,25 +2,35 @@ module Passwordless
|
|
2
2
|
module TestHelpers
|
3
3
|
module TestCase
|
4
4
|
def passwordless_sign_out
|
5
|
-
delete
|
5
|
+
delete(Passwordless::Engine.routes.url_helpers.sign_out_path)
|
6
6
|
follow_redirect!
|
7
7
|
end
|
8
8
|
|
9
9
|
def passwordless_sign_in(resource)
|
10
|
-
session = Passwordless::Session.create!(authenticatable: resource
|
11
|
-
|
10
|
+
session = Passwordless::Session.create!(authenticatable: resource)
|
11
|
+
magic_link = Passwordless::Engine.routes.url_helpers.send(
|
12
|
+
:"confirm_#{session.authenticatable_type.tableize}_sign_in_url",
|
13
|
+
session,
|
14
|
+
session.token
|
15
|
+
)
|
16
|
+
get(magic_link)
|
12
17
|
follow_redirect!
|
13
18
|
end
|
14
19
|
end
|
15
20
|
|
16
21
|
module SystemTestCase
|
17
22
|
def passwordless_sign_out
|
18
|
-
visit
|
23
|
+
visit(Passwordless::Engine.routes.url_helpers.sign_out_path)
|
19
24
|
end
|
20
25
|
|
21
26
|
def passwordless_sign_in(resource)
|
22
|
-
session = Passwordless::Session.create!(authenticatable: resource
|
23
|
-
|
27
|
+
session = Passwordless::Session.create!(authenticatable: resource)
|
28
|
+
magic_link = Passwordless::Engine.routes.url_helpers.send(
|
29
|
+
:"confirm_#{session.authenticatable_type.tableize}_sign_in_url",
|
30
|
+
session,
|
31
|
+
session.token
|
32
|
+
)
|
33
|
+
visit(magic_link)
|
24
34
|
end
|
25
35
|
end
|
26
36
|
end
|
@@ -36,8 +46,8 @@ end
|
|
36
46
|
|
37
47
|
if defined?(RSpec)
|
38
48
|
RSpec.configure do |config|
|
39
|
-
config.include
|
40
|
-
config.include
|
41
|
-
config.include
|
49
|
+
config.include(::Passwordless::TestHelpers::TestCase, type: :request)
|
50
|
+
config.include(::Passwordless::TestHelpers::TestCase, type: :controller)
|
51
|
+
config.include(::Passwordless::TestHelpers::SystemTestCase, type: :system)
|
42
52
|
end
|
43
53
|
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module Passwordless
|
2
|
+
class TokenDigest
|
3
|
+
ALGORITHM = "SHA256"
|
4
|
+
|
5
|
+
def initialize(str)
|
6
|
+
@str = str
|
7
|
+
end
|
8
|
+
|
9
|
+
def digest
|
10
|
+
key = self.class.key()
|
11
|
+
OpenSSL::HMAC.hexdigest(ALGORITHM, key, @str)
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.key
|
15
|
+
@key ||= ActiveSupport::KeyGenerator.new(Rails.application.secret_key_base).generate_key("passwordless")
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
data/lib/passwordless/version.rb
CHANGED
data/lib/passwordless.rb
CHANGED
@@ -1,30 +1,16 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require "active_support"
|
4
|
+
require "passwordless/config"
|
4
5
|
require "passwordless/errors"
|
5
6
|
require "passwordless/engine"
|
6
|
-
require "passwordless/
|
7
|
+
require "passwordless/token_digest"
|
7
8
|
|
8
9
|
# The main Passwordless module
|
9
10
|
module Passwordless
|
10
|
-
|
11
|
-
mattr_accessor(:default_from_address) { "CHANGE_ME@example.com" }
|
12
|
-
mattr_accessor(:token_generator) { UrlSafeBase64Generator.new }
|
13
|
-
mattr_accessor(:restrict_token_reuse) { false }
|
14
|
-
mattr_accessor(:redirect_back_after_sign_in) { true }
|
15
|
-
mattr_accessor(:mounted_as) { :configured_when_mounting_passwordless }
|
11
|
+
extend Configurable
|
16
12
|
|
17
|
-
|
18
|
-
|
19
|
-
mattr_accessor(:redirect_to_response_options) { {} }
|
20
|
-
mattr_accessor(:success_redirect_path) { "/" }
|
21
|
-
mattr_accessor(:failure_redirect_path) { "/" }
|
22
|
-
mattr_accessor(:sign_out_redirect_path) { "/" }
|
23
|
-
|
24
|
-
mattr_accessor(:after_session_save) do
|
25
|
-
lambda { |session, _request| Mailer.magic_link(session).deliver_now }
|
13
|
+
def self.digest(token)
|
14
|
+
TokenDigest.new(token).digest
|
26
15
|
end
|
27
|
-
|
28
|
-
CookieDeprecation = ActiveSupport::Deprecation.new("0.9", "passwordless")
|
29
|
-
SessionValidDeprecation = ActiveSupport::Deprecation.new("0.9", "passwordless")
|
30
16
|
end
|
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: 0.
|
4
|
+
version: 1.0.0.beta1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Mikkel Malmberg
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2023-
|
11
|
+
date: 2023-09-21 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|
@@ -28,58 +28,16 @@ dependencies:
|
|
28
28
|
name: bcrypt
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
|
-
- - "
|
31
|
+
- - ">="
|
32
32
|
- !ruby/object:Gem::Version
|
33
33
|
version: 3.1.11
|
34
34
|
type: :runtime
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
|
-
requirements:
|
38
|
-
- - "~>"
|
39
|
-
- !ruby/object:Gem::Version
|
40
|
-
version: 3.1.11
|
41
|
-
- !ruby/object:Gem::Dependency
|
42
|
-
name: sqlite3
|
43
|
-
requirement: !ruby/object:Gem::Requirement
|
44
|
-
requirements:
|
45
|
-
- - ">="
|
46
|
-
- !ruby/object:Gem::Version
|
47
|
-
version: 1.4.1
|
48
|
-
type: :development
|
49
|
-
prerelease: false
|
50
|
-
version_requirements: !ruby/object:Gem::Requirement
|
51
|
-
requirements:
|
52
|
-
- - ">="
|
53
|
-
- !ruby/object:Gem::Version
|
54
|
-
version: 1.4.1
|
55
|
-
- !ruby/object:Gem::Dependency
|
56
|
-
name: yard
|
57
|
-
requirement: !ruby/object:Gem::Requirement
|
58
|
-
requirements:
|
59
|
-
- - ">="
|
60
|
-
- !ruby/object:Gem::Version
|
61
|
-
version: '0'
|
62
|
-
type: :development
|
63
|
-
prerelease: false
|
64
|
-
version_requirements: !ruby/object:Gem::Requirement
|
65
|
-
requirements:
|
66
|
-
- - ">="
|
67
|
-
- !ruby/object:Gem::Version
|
68
|
-
version: '0'
|
69
|
-
- !ruby/object:Gem::Dependency
|
70
|
-
name: standard
|
71
|
-
requirement: !ruby/object:Gem::Requirement
|
72
37
|
requirements:
|
73
38
|
- - ">="
|
74
39
|
- !ruby/object:Gem::Version
|
75
|
-
version:
|
76
|
-
type: :development
|
77
|
-
prerelease: false
|
78
|
-
version_requirements: !ruby/object:Gem::Requirement
|
79
|
-
requirements:
|
80
|
-
- - ">="
|
81
|
-
- !ruby/object:Gem::Version
|
82
|
-
version: '0'
|
40
|
+
version: 3.1.11
|
83
41
|
description:
|
84
42
|
email:
|
85
43
|
- mikkel@brnbw.com
|
@@ -95,20 +53,23 @@ files:
|
|
95
53
|
- app/mailers/passwordless/mailer.rb
|
96
54
|
- app/models/passwordless/application_record.rb
|
97
55
|
- app/models/passwordless/session.rb
|
98
|
-
- app/views/passwordless/mailer/
|
56
|
+
- app/views/passwordless/mailer/sign_in.text.erb
|
99
57
|
- app/views/passwordless/sessions/new.html.erb
|
58
|
+
- app/views/passwordless/sessions/show.html.erb
|
100
59
|
- config/locales/en.yml
|
101
60
|
- config/routes.rb
|
102
61
|
- db/migrate/20171104221735_create_passwordless_sessions.rb
|
103
62
|
- lib/generators/passwordless/views_generator.rb
|
104
63
|
- lib/passwordless.rb
|
64
|
+
- lib/passwordless/config.rb
|
105
65
|
- lib/passwordless/controller_helpers.rb
|
106
66
|
- lib/passwordless/engine.rb
|
107
67
|
- lib/passwordless/errors.rb
|
108
68
|
- lib/passwordless/model_helpers.rb
|
109
69
|
- lib/passwordless/router_helpers.rb
|
70
|
+
- lib/passwordless/short_token_generator.rb
|
110
71
|
- lib/passwordless/test_helpers.rb
|
111
|
-
- lib/passwordless/
|
72
|
+
- lib/passwordless/token_digest.rb
|
112
73
|
- lib/passwordless/version.rb
|
113
74
|
homepage: https://github.com/mikker/passwordless
|
114
75
|
licenses:
|
@@ -125,11 +86,11 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
125
86
|
version: '0'
|
126
87
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
127
88
|
requirements:
|
128
|
-
- - "
|
89
|
+
- - ">"
|
129
90
|
- !ruby/object:Gem::Version
|
130
|
-
version:
|
91
|
+
version: 1.3.1
|
131
92
|
requirements: []
|
132
|
-
rubygems_version: 3.4.
|
93
|
+
rubygems_version: 3.4.19
|
133
94
|
signing_key:
|
134
95
|
specification_version: 4
|
135
96
|
summary: Add authentication to your app without all the ickyness of passwords.
|
@@ -1 +0,0 @@
|
|
1
|
-
<%= I18n.t('passwordless.mailer.magic_link', link: @magic_link) %>
|
@@ -1,15 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Passwordless
|
4
|
-
# Generates random numbers for Session records
|
5
|
-
class UrlSafeBase64Generator
|
6
|
-
# Passwordless' default random string strategy. Generates a url safe
|
7
|
-
# base64 random string.
|
8
|
-
# @param _session [Session] Optional - Passwordless passes the sesion Record
|
9
|
-
# to generators so you can (optionally) use it for generating your tokens.
|
10
|
-
# @return [String] 32 byte base64 string
|
11
|
-
def call(_session)
|
12
|
-
SecureRandom.urlsafe_base64(32)
|
13
|
-
end
|
14
|
-
end
|
15
|
-
end
|