passwordless 1.0.0 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 24d02d4dc7676adee968e3f922097f744ee41c2a1826d7622ffac01f3aaf76b8
4
- data.tar.gz: 03624c6400113e2071eb038cd9406102870b3a56e1f8fa790bb9c190f17b95d5
3
+ metadata.gz: 4d3bfd49106dd713d65f26a575911bdcb1a903a62273d741f08f1c0b36ea9a77
4
+ data.tar.gz: 239fdcce54d30e39f39bb6eb2d7ffdd6c2f2f50e04fe38ec7f53bca000b449d6
5
5
  SHA512:
6
- metadata.gz: 34e67e3b5a2be5cc657ee7193fa0ea76fc27ae7aad32413c66c4534bd2ce91540d7fe3ccdb2a2816a9d46053fd06d2f9c840d69e14cb7e5c49a45b3933be418e
7
- data.tar.gz: ed550ba88a988109ad8192120fa25225c2c2fc161caff9beb9f51f5bd54baf72325c5baf02fb42da72a2a23ccb923687959aea517c2ce00879f580f82ab24559
6
+ metadata.gz: f7afa9aed4245ed2a3ab13bd7624ec8561d8c0e47db9435a1e415442f6c1d4e6e1770cd9d799095888a189a0485fc9bd5d3fa22e9e3145f2e351e8deee04277b
7
+ data.tar.gz: 5f4d8142044cdaff3f9746bad1d184d587b293241ab4f2d0344924fc452cb65590f91840b0db698d535588098cb72098c67f09c2243530177e45f395ab1466a9
data/README.md CHANGED
@@ -6,7 +6,7 @@
6
6
 
7
7
  [![CI](https://github.com/mikker/passwordless/actions/workflows/ci.yml/badge.svg)](https://github.com/mikker/passwordless/actions/workflows/ci.yml) [![Rubygems](https://img.shields.io/gem/v/passwordless.svg)](https://rubygems.org/gems/passwordless) [![codecov](https://codecov.io/gh/mikker/passwordless/branch/master/graph/badge.svg)](https://codecov.io/gh/mikker/passwordless)
8
8
 
9
- Add authentication to your Rails app without all the icky-ness of passwords.
9
+ Add authentication to your Rails app without all the icky-ness of passwords. _Magic link_ authentication, if you will. We call it _passwordless_.
10
10
 
11
11
  ---
12
12
 
@@ -16,7 +16,7 @@ Add to your bundle and copy over the migrations:
16
16
 
17
17
  ```sh
18
18
  $ bundle add passwordless
19
- $ bin/rails passwordless:install:migrations
19
+ $ bin/rails passwordless_engine:install:migrations
20
20
  ```
21
21
 
22
22
  ### Upgrading
@@ -37,7 +37,7 @@ module Passwordless
37
37
  end
38
38
 
39
39
  redirect_to(
40
- url_for(id: @session.id, action: "show"),
40
+ url_for(id: @session.identifier, action: "show"),
41
41
  flash: {notice: I18n.t("passwordless.sessions.create.email_sent")}
42
42
  )
43
43
  else
@@ -54,7 +54,7 @@ module Passwordless
54
54
  # Shows the form for confirming a Session record.
55
55
  # renders sessions/show.html.erb.
56
56
  def show
57
- @session = find_session
57
+ @session = passwordless_session
58
58
  end
59
59
 
60
60
  # patch "/:resource/sign_in/:id"
@@ -66,7 +66,7 @@ module Passwordless
66
66
  # @see ControllerHelpers#sign_in
67
67
  # @see ControllerHelpers#save_passwordless_redirect_location!
68
68
  def update
69
- @session = find_session
69
+ @session = passwordless_session
70
70
 
71
71
  artificially_slow_down_brute_force_attacks(passwordless_session_params[:token])
72
72
 
@@ -86,7 +86,7 @@ module Passwordless
86
86
  # safe. We don't want to sign in the user in that case.
87
87
  return head(:ok) if request.head?
88
88
 
89
- @session = find_session
89
+ @session = passwordless_session
90
90
 
91
91
  artificially_slow_down_brute_force_attacks(params[:token])
92
92
 
@@ -98,7 +98,12 @@ module Passwordless
98
98
  # @see ControllerHelpers#sign_out
99
99
  def destroy
100
100
  sign_out(authenticatable_class)
101
- redirect_to(passwordless_sign_out_redirect_path, Passwordless.config.redirect_to_response_options.dup)
101
+
102
+ redirect_to(
103
+ passwordless_sign_out_redirect_path,
104
+ notice: I18n.t("passwordless.sessions.destroy.signed_out"),
105
+ **redirect_to_options
106
+ )
102
107
  end
103
108
 
104
109
  protected
@@ -161,10 +166,6 @@ module Passwordless
161
166
  authenticatable_type.constantize
162
167
  end
163
168
 
164
- def find_session
165
- Session.find_by!(id: params[:id], authenticatable_type: authenticatable_type)
166
- end
167
-
168
169
  def find_authenticatable
169
170
  email = passwordless_session_params[email_field].downcase.strip
170
171
 
@@ -196,7 +197,7 @@ module Passwordless
196
197
 
197
198
  def passwordless_session
198
199
  @passwordless_session ||= Session.find_by!(
199
- id: params[:id],
200
+ identifier: params[:id],
200
201
  authenticatable_type: authenticatable_type
201
202
  )
202
203
  end
@@ -12,7 +12,16 @@ module Passwordless
12
12
  # is still in memory (optional)
13
13
  def sign_in(session, token = nil)
14
14
  @token = token || session.token
15
- @magic_link = send(:"confirm_#{session.authenticatable_type.tableize}_sign_in_url", session, token)
15
+ @magic_link = url_for(
16
+ {
17
+ controller: "passwordless/sessions",
18
+ action: "confirm",
19
+ id: session.identifier,
20
+ token: token,
21
+ authenticatable: "user",
22
+ resource: "users"
23
+ }
24
+ )
16
25
  email_field = session.authenticatable.class.passwordless_email_field
17
26
 
18
27
  mail(
@@ -61,6 +61,10 @@ module Passwordless
61
61
  !expired?
62
62
  end
63
63
 
64
+ def to_param
65
+ identifier
66
+ end
67
+
64
68
  private
65
69
 
66
70
  def token_digest_available?(token_digest)
@@ -68,6 +72,7 @@ module Passwordless
68
72
  end
69
73
 
70
74
  def set_defaults
75
+ self.identifier = SecureRandom.uuid
71
76
  self.expires_at ||= Passwordless.config.expires_at.call
72
77
  self.timeout_at ||= Passwordless.config.timeout_at.call
73
78
 
@@ -1,6 +1,8 @@
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
- <%= f.label email_field_name, t("passwordless.sessions.new.email.label") %>
3
+ <%= f.label email_field_name,
4
+ t("passwordless.sessions.new.email.label"),
5
+ for: "passwordless_#{email_field}" %>
4
6
  <%= text_field_tag email_field_name,
5
7
  params.fetch(email_field_name, nil),
6
8
  required: true,
@@ -1,5 +1,5 @@
1
1
  <%= form_with(model: @session, url: url_for(action: 'update'), scope: 'passwordless', method: 'patch', data: { turbo: false }) do |f| %>
2
- <%= f.label :token %>
2
+ <%= f.label :token, autocomplete: "off" %>
3
3
  <%= f.text_field :token %>
4
- <%= f.submit "Confirm" %>
4
+ <%= f.submit t(".confirm") %>
5
5
  <% end %>
@@ -11,10 +11,14 @@ en:
11
11
  email_sent: "We've sent you an email with a secret token"
12
12
  not_found: "We couldn't find a user with that email address"
13
13
  error: "An error occured"
14
+ show:
15
+ confirm: "Confirm"
14
16
  errors:
15
17
  invalid_token: "Token is invalid"
16
18
  session_expired: "Your session has expired, please sign in again."
17
19
  token_claimed: "This link has already been used, try requesting the link again"
20
+ destroy:
21
+ signed_out: "Signed out successfully"
18
22
  mailer:
19
23
  sign_in:
20
24
  subject: "Signing in ✨"
@@ -13,6 +13,7 @@ class CreatePasswordlessSessions < ActiveRecord::Migration[5.1]
13
13
  t.datetime(:expires_at, null: false)
14
14
  t.datetime(:claimed_at)
15
15
  t.string(:token_digest, null: false)
16
+ t.string(:identifier, null: false, index: {unique: true}, length: 36)
16
17
 
17
18
  t.timestamps
18
19
  end
@@ -23,14 +23,16 @@ module Passwordless
23
23
  # (Default: 'passwordless/sessions')
24
24
  def passwordless_for(resource, at: :na, as: :na, controller: "passwordless/sessions")
25
25
  at == :na && at = "/#{resource.to_s}"
26
- as == :na && as = "#{resource.to_s}_"
26
+ as == :na && as = resource.to_s
27
+
28
+ as = as.to_s + "_" unless !as || as.to_s.end_with?("_")
27
29
 
28
30
  plural = resource.to_s
29
31
  singular = plural.singularize
30
32
 
31
33
  defaults = {
32
34
  authenticatable: singular,
33
- resource: resource,
35
+ resource: resource
34
36
  }
35
37
 
36
38
  scope(defaults: defaults) do
@@ -1,17 +1,32 @@
1
1
  module Passwordless
2
2
  module TestHelpers
3
3
  module TestCase
4
- def passwordless_sign_out
5
- delete(Passwordless::Engine.routes.url_helpers.sign_out_path)
4
+ def passwordless_sign_out(cls = nil)
5
+ cls ||= "User".constantize
6
+ dest = url_for(
7
+ {
8
+ controller: "passwordless/sessions",
9
+ action: "destroy",
10
+ authenticatable: cls.model_name.singular,
11
+ resource: cls.model_name.to_s.tableize
12
+ }
13
+ )
14
+ delete(dest)
6
15
  follow_redirect!
7
16
  end
8
17
 
9
18
  def passwordless_sign_in(resource)
19
+ cls = resource.class
10
20
  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
21
+ magic_link = url_for(
22
+ {
23
+ controller: "passwordless/sessions",
24
+ action: "confirm",
25
+ id: session.id,
26
+ token: session.token,
27
+ authenticatable: cls.model_name.singular,
28
+ resource: cls.model_name.to_s.tableize
29
+ }
15
30
  )
16
31
  get(magic_link)
17
32
  follow_redirect!
@@ -19,16 +34,32 @@ module Passwordless
19
34
  end
20
35
 
21
36
  module SystemTestCase
22
- def passwordless_sign_out
23
- visit(Passwordless::Engine.routes.url_helpers.sign_out_path)
37
+ def passwordless_sign_out(cls = nil)
38
+ cls ||= "User".constantize
39
+ visit(
40
+ url_for(
41
+ {
42
+ controller: "passwordless/sessions",
43
+ action: "destroy",
44
+ authenticatable: cls.model_name.singular,
45
+ resource: cls.model_name.to_s.tableize
46
+ }
47
+ )
48
+ )
24
49
  end
25
50
 
26
51
  def passwordless_sign_in(resource)
52
+ cls = resource.class
27
53
  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
54
+ magic_link = url_for(
55
+ {
56
+ controller: "passwordless/sessions",
57
+ action: "confirm",
58
+ id: session.id,
59
+ token: session.token,
60
+ authenticatable: cls.model_name.singular,
61
+ resource: cls.model_name.to_s.tableize
62
+ }
32
63
  )
33
64
  visit(magic_link)
34
65
  end
@@ -2,5 +2,5 @@
2
2
 
3
3
  module Passwordless
4
4
  # :nodoc:
5
- VERSION = "1.0.0"
5
+ VERSION = "1.1.0"
6
6
  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: 1.0.0
4
+ version: 1.1.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: 2023-10-12 00:00:00.000000000 Z
11
+ date: 2023-11-07 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
@@ -90,7 +90,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
90
90
  - !ruby/object:Gem::Version
91
91
  version: '0'
92
92
  requirements: []
93
- rubygems_version: 3.4.20
93
+ rubygems_version: 3.4.21
94
94
  signing_key:
95
95
  specification_version: 4
96
96
  summary: Add authentication to your app without all the ickyness of passwords.