passwordless 0.10.0 → 0.12.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: c45a41b4be30c959c37b50ef8013f4055c97ae516e4b8297b4f56607836cc09b
4
- data.tar.gz: 7b0c50e087c5be36e5e89476764a407767aee4851fcb38c0b744bd532be8e982
3
+ metadata.gz: b90e8f97825d92f0728154737c428d39cfecbedc9e02bbe6948d0861dd5e9c39
4
+ data.tar.gz: 2a5b288bf8c16004c6ec8fe7b8937e9f72496475e6e9af4e6a70c32a7a1d05dc
5
5
  SHA512:
6
- metadata.gz: b35ef690ecd6b37106d785ccb71693606387a8fcc48d5ea115b9d035211b8225d551291d3c64abdb89517cb0ceea17d31807d40ef6f168a9f5df742fd27b8d65
7
- data.tar.gz: 8d8ba39b3711905ea36f5f20c009a26b42bcea43ed1bd1185ac56c0053e7afdb6fdf786f123fa8c01b2c095ec3104637d5017791056960293869053ff0b248a3
6
+ metadata.gz: 2350958cc2cb4628a6242a6c86ef08b3962fef2ba12fd9ed5a1bf8727f9254fc61fb77e9fa946bb015ebfc98eb81563d1e56aeb1c40d1cbc2ef96e66af512de9
7
+ data.tar.gz: 5fed7a3d7541a302fa9d6fc802bd530002846ea8cc4dae2057d03fdd799d66263752c766578bd96a441ab584d539739fbe55a63f7e258c5a7e1b16fdecb9eb7a
data/README.md CHANGED
@@ -4,7 +4,7 @@
4
4
  <br />
5
5
  </p>
6
6
 
7
- [![Travis](https://travis-ci.org/mikker/passwordless.svg?branch=master)](https://travis-ci.org/mikker/passwordless) [![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) [![Ruby Style Guide](https://img.shields.io/badge/code_style-standard-brightgreen.svg)](https://github.com/testdouble/standard)
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
9
  Add authentication to your Rails app without all the icky-ness of passwords.
10
10
 
@@ -26,6 +26,8 @@ Add authentication to your Rails app without all the icky-ness of passwords.
26
26
  * [Token and Session Expiry](#token-and-session-expiry)
27
27
  * [Redirecting back after sign-in](#redirecting-back-after-sign-in)
28
28
  * [Claiming tokens](#claiming-tokens)
29
+ * [Supporting UUID primary keys](#supporting-uuid-primary-keys)
30
+ * [Testing helpers](#testing-helpers)
29
31
  * [E-mail security](#e-mail-security)
30
32
  * [License](#license)
31
33
 
@@ -48,7 +50,7 @@ $ bin/rails passwordless:install:migrations
48
50
 
49
51
  Passwordless creates a single model called `Passwordless::Session`. It doesn't come with its own `User` model, it expects you to create one:
50
52
 
51
- ```
53
+ ```sh
52
54
  $ bin/rails generate model User email
53
55
  ```
54
56
 
@@ -56,7 +58,10 @@ Then specify which field on your `User` record is the email field with:
56
58
 
57
59
  ```ruby
58
60
  class User < ApplicationRecord
59
- validates :email, presence: true, uniqueness: { case_sensitive: false }
61
+ validates :email,
62
+ presence: true,
63
+ uniqueness: { case_sensitive: false },
64
+ format: { with: URI::MailTo::EMAIL_REGEXP }
60
65
 
61
66
  passwordless_with :email # <-- here!
62
67
  end
@@ -111,7 +116,9 @@ end
111
116
 
112
117
  ### Providing your own templates
113
118
 
114
- Override `passwordless`' bundled views by adding your own. `passwordless` has 2 action views and 1 mailer view:
119
+ Override `passwordless`' bundled views by adding your own. You can manually copy the specific views that you need or copy them to your application with `rails generate passwordless:views`.
120
+
121
+ `passwordless` has 2 action views and 1 mailer view:
115
122
 
116
123
  ```sh
117
124
  # the form where the user inputs their email address
@@ -131,6 +138,8 @@ If you'd like to let the user know whether or not a record was found, `@resource
131
138
  <% end %>
132
139
  ```
133
140
 
141
+ Please note that, from a security standpoint, this is a **bad practice** because you'd be giving information about which users are registered on your system. It is recommended to use a single message similar to the default one: "If we found you in the system, we've sent you an email". The **best practice** is to never expose which emails are registered on your system.
142
+
134
143
  See [the bundled views](https://github.com/mikker/passwordless/tree/master/app/views/passwordless).
135
144
 
136
145
  ### Registering new users
@@ -177,7 +186,7 @@ By default, magic link will send by email. You can customize this method. For ex
177
186
 
178
187
  config/initializers/passwordless.rb
179
188
 
180
- ```
189
+ ```ruby
181
190
  Passwordless.after_session_save = lambda do |session, request|
182
191
  # Default behavior is
183
192
  # Passwordless::Mailer.magic_link(session).deliver_now
@@ -195,7 +204,7 @@ Currently there is not an officially supported way to generate your own magic li
195
204
 
196
205
  However, you can accomplish this with the following snippet of code.
197
206
 
198
- ```
207
+ ```ruby
199
208
  session = Passwordless::Session.new({
200
209
  authenticatable: @manager,
201
210
  user_agent: 'Command Line',
@@ -244,6 +253,9 @@ Passwordless.redirect_back_after_sign_in = true # When enabled the user will be
244
253
  Passwordless.expires_at = lambda { 1.year.from_now } # How long until a passwordless session expires.
245
254
  Passwordless.timeout_at = lambda { 1.hour.from_now } # How long until a magic link expires.
246
255
 
256
+ # redirection session behavior
257
+ Passwordless.redirect_to_response_options = {} # any allowed response_options for redirect_to can go in here
258
+
247
259
  # Default redirection paths
248
260
  Passwordless.success_redirect_path = '/' # When a user succeeds in logging in.
249
261
  Passwordless.failure_redirect_path = '/' # When a a login is failed for any reason.
@@ -319,7 +331,7 @@ config/initializers/passwordless.rb
319
331
  Passwordless.restrict_token_reuse = true
320
332
  ```
321
333
 
322
- #### Upgrading an existing Rails app
334
+ #### Upgrading an existing Rails app to use claim token
323
335
 
324
336
  The simplest way to update your sessions table is with a single migration:
325
337
 
@@ -340,11 +352,55 @@ end
340
352
  ```
341
353
  </details>
342
354
 
355
+ ### Supporting UUID primary keys
356
+
357
+ If your `users` table uses UUIDs for its primary keys, you will need to add a migration
358
+ to change the type of `passwordless`' `authenticatable_id` field to match your primary key type (this will also involve dropping and recreating associated indices).
359
+
360
+ Here is an example migration you can use:
361
+ ```ruby
362
+ class SupportUuidInPasswordlessSessions < ActiveRecord::Migration[6.0]
363
+ def change
364
+ remove_index :passwordless_sessions, column: [:authenticatable_type, :authenticatable_id] if index_exists? :authenticatable_type, :authenticatable_id
365
+ remove_column :passwordless_sessions, :authenticatable_id
366
+ add_column :passwordless_sessions, :authenticatable_id, :uuid
367
+ add_index :passwordless_sessions, [:authenticatable_type, :authenticatable_id], name: 'authenticatable'
368
+ end
369
+ end
370
+ ```
371
+
372
+ Alternatively, you can use `add_reference` with `type: :uuid` in your migration (see docs [here](https://api.rubyonrails.org/classes/ActiveRecord/ConnectionAdapters/SchemaStatements.html#method-i-add_reference)).
373
+
374
+ ## Testing helpers
375
+
376
+ To help with testing, a set of test helpers are provided.
377
+
378
+ If you are using RSpec, add the following line to your `spec/rails_helper.rb` or
379
+ `spec/spec_helper.rb` if `rails_helper.rb` does not exist:
380
+
381
+ ```ruby
382
+ require "passwordless/test_helpers"
383
+ ```
384
+
385
+ If you are using TestUnit, add this line to your `test/test_helper.rb`:
386
+
387
+ ```ruby
388
+ require "passwordless/test_helpers"
389
+ ```
390
+
391
+
392
+ Then in your controller, request, and system tests/specs, you can utilize the following methods:
393
+
394
+ ```ruby
395
+ passwordless_sign_in(user) # signs you in as a user
396
+ passwordless_sign_out # signs out user
397
+ ```
398
+
343
399
  ## E-mail security
344
400
 
345
401
  There's no reason that this approach should be less secure than the usual username/password combo. In fact this is most often a more secure option, as users don't get to choose the weak passwords they still use. In a way this is just the same as having each user go through "Forgot password" on every login.
346
402
 
347
- But be aware that when everyone authenticates via emails you send, the way you send those mails becomes a weak spot. Email services usually provide a log of all the mails you send so if your app's account is compromised, every user in the system is as well. (This is the same for "Forgot password".) [Reddit was compromised](https://thenextweb.com/hardfork/2018/01/05/reddit-bitcoin-cash-hack/) using this method.
403
+ But be aware that when everyone authenticates via emails you send, the way you send those mails becomes a weak spot. Email services usually provide a log of all the mails you send so if your app's account is compromised, every user in the system is as well. (This is the same for "Forgot password".) [Reddit was compromised](https://thenextweb.com/hardfork/2018/01/05/reddit-bitcoin-cash-stolen-hack/) using this method.
348
404
 
349
405
  Ideally you should set up your email provider to not log these mails. And be sure to turn on 2-factor auth if your provider supports it.
350
406
 
@@ -17,7 +17,7 @@ module Passwordless
17
17
 
18
18
  # post '/sign_in'
19
19
  # Creates a new Session record then sends the magic link
20
- # renders sessions/create.html.erb.
20
+ # redirects to sign in page with generic flash message.
21
21
  # @see Mailer#magic_link Mailer#magic_link
22
22
  def create
23
23
  @resource = find_authenticatable
@@ -31,7 +31,8 @@ module Passwordless
31
31
  end
32
32
  end
33
33
 
34
- render
34
+ flash[:notice] = I18n.t('passwordless.sessions.create.email_sent_if_record_found')
35
+ redirect_to(sign_in_path)
35
36
  end
36
37
 
37
38
  # get '/sign_in/:token'
@@ -42,24 +43,25 @@ module Passwordless
42
43
  # @see ControllerHelpers#save_passwordless_redirect_location!
43
44
  def show
44
45
  # Make it "slow" on purpose to make brute-force attacks more of a hassle
46
+ redirect_to_options = Passwordless.redirect_to_response_options.dup
45
47
  BCrypt::Password.create(params[:token])
46
- sign_in passwordless_session
48
+ sign_in(passwordless_session)
47
49
 
48
- redirect_to passwordless_success_redirect_path
50
+ redirect_to(passwordless_success_redirect_path, redirect_to_options)
49
51
  rescue Errors::TokenAlreadyClaimedError
50
52
  flash[:error] = I18n.t(".passwordless.sessions.create.token_claimed")
51
- redirect_to passwordless_failure_redirect_path
53
+ redirect_to(passwordless_failure_redirect_path, redirect_to_options)
52
54
  rescue Errors::SessionTimedOutError
53
55
  flash[:error] = I18n.t(".passwordless.sessions.create.session_expired")
54
- redirect_to passwordless_failure_redirect_path
56
+ redirect_to(passwordless_failure_redirect_path, redirect_to_options)
55
57
  end
56
58
 
57
59
  # match '/sign_out', via: %i[get delete].
58
60
  # Signs user out. Redirects to root_path
59
61
  # @see ControllerHelpers#sign_out
60
62
  def destroy
61
- sign_out authenticatable_class
62
- redirect_to passwordless_sign_out_redirect_path
63
+ sign_out(authenticatable_class)
64
+ redirect_to(passwordless_sign_out_redirect_path, Passwordless.redirect_to_response_options.dup)
63
65
  end
64
66
 
65
67
  protected
@@ -10,8 +10,7 @@ module Passwordless
10
10
  def magic_link(session)
11
11
  @session = session
12
12
 
13
- @magic_link = send(Passwordless.mounted_as)
14
- .token_sign_in_url(session.token)
13
+ @magic_link = send(Passwordless.mounted_as).token_sign_in_url(session.token)
15
14
 
16
15
  email_field = @session.authenticatable.class.passwordless_email_field
17
16
  mail(
@@ -4,10 +4,13 @@ module Passwordless
4
4
  # The session responsible for holding the connection between the record
5
5
  # trying to log in and the unique tokens.
6
6
  class Session < ApplicationRecord
7
- belongs_to :authenticatable,
8
- polymorphic: true, inverse_of: :passwordless_sessions
7
+ belongs_to(
8
+ :authenticatable,
9
+ polymorphic: true,
10
+ inverse_of: :passwordless_sessions
11
+ )
9
12
 
10
- validates \
13
+ validates(
11
14
  :authenticatable,
12
15
  :timeout_at,
13
16
  :expires_at,
@@ -15,16 +18,19 @@ module Passwordless
15
18
  :remote_addr,
16
19
  :token,
17
20
  presence: true
21
+ )
18
22
 
19
23
  before_validation :set_defaults
20
24
 
21
- scope :available, lambda {
22
- where("expires_at > ?", Time.current)
23
- }
25
+ scope(
26
+ :available,
27
+ lambda { where("expires_at > ?", Time.current) }
28
+ )
24
29
 
25
30
  def self.valid
26
31
  available
27
32
  end
33
+
28
34
  class << self
29
35
  deprecate :valid, deprecator: SessionValidDeprecation
30
36
  end
@@ -1,5 +1,5 @@
1
- <%= form_for @session, url: send(Passwordless.mounted_as).sign_in_path do |f| %>
1
+ <%= form_with model: @session, url: send(Passwordless.mounted_as).sign_in_path, data: { turbo: 'false' } do |f| %>
2
2
  <% email_field_name = :"passwordless[#{@email_field}]" %>
3
- <%= text_field_tag email_field_name, params.fetch(email_field_name, nil) %>
3
+ <%= text_field_tag email_field_name, params.fetch(email_field_name, nil), required: true %>
4
4
  <%= f.submit I18n.t('passwordless.sessions.new.submit') %>
5
5
  <% end %>
data/config/routes.rb CHANGED
@@ -1,8 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  Passwordless::Engine.routes.draw do
4
- get "/sign_in", to: "sessions#new", as: :sign_in
5
- post "/sign_in", to: "sessions#create"
6
- get "/sign_in/:token", to: "sessions#show", as: :token_sign_in
7
- match "/sign_out", to: "sessions#destroy", via: %i[get delete], as: :sign_out
4
+ get("/sign_in", to: "sessions#new", as: :sign_in)
5
+ post("/sign_in", to: "sessions#create")
6
+ get("/sign_in/:token", to: "sessions#show", as: :token_sign_in)
7
+ match("/sign_out", to: "sessions#destroy", via: %i[get delete], as: :sign_out)
8
8
  end
@@ -2,18 +2,19 @@
2
2
 
3
3
  class CreatePasswordlessSessions < ActiveRecord::Migration[5.1]
4
4
  def change
5
- create_table :passwordless_sessions do |t|
5
+ create_table(:passwordless_sessions) do |t|
6
6
  t.belongs_to(
7
7
  :authenticatable,
8
8
  polymorphic: true,
9
9
  index: {name: "authenticatable"}
10
10
  )
11
- t.datetime :timeout_at, null: false
12
- t.datetime :expires_at, null: false
13
- t.datetime :claimed_at
14
- t.text :user_agent, null: false
15
- t.string :remote_addr, null: false
16
- t.string :token, null: false
11
+
12
+ t.datetime(:timeout_at, null: false)
13
+ t.datetime(:expires_at, null: false)
14
+ t.datetime(:claimed_at)
15
+ t.text(:user_agent, null: false)
16
+ t.string(:remote_addr, null: false)
17
+ t.string(:token, null: false)
17
18
 
18
19
  t.timestamps
19
20
  end
@@ -0,0 +1,15 @@
1
+ require 'rails/generators'
2
+
3
+ module Passwordless
4
+ module Generators
5
+ class ViewsGenerator < Rails::Generators::Base
6
+ source_root File.expand_path('../../../app/views/passwordless', __dir__)
7
+
8
+ def install
9
+ copy_file 'mailer/magic_link.text.erb', 'app/views/passwordless/mailer/magic_link.text.erb'
10
+ copy_file 'sessions/new.html.erb', 'app/views/passwordless/sessions/new.html.erb'
11
+ copy_file 'sessions/create.html.erb', 'app/views/passwordless/sessions/create.html.erb'
12
+ end
13
+ end
14
+ end
15
+ end
@@ -39,6 +39,7 @@ module Passwordless
39
39
 
40
40
  authenticate_by_session(authenticatable_class)
41
41
  end
42
+
42
43
  deprecate :authenticate_by_cookie, deprecator: CookieDeprecation
43
44
 
44
45
  def upgrade_passwordless_cookie(authenticatable_class)
@@ -51,7 +52,7 @@ module Passwordless
51
52
  return unless (record = authenticatable_class.find_by(id: authenticatable_id))
52
53
  new_session = build_passwordless_session(record).tap { |s| s.save! }
53
54
 
54
- sign_in new_session
55
+ sign_in(new_session)
55
56
 
56
57
  new_session.authenticatable
57
58
  end
@@ -73,20 +74,25 @@ module Passwordless
73
74
  # to sign in
74
75
  # @return [ActiveRecord::Base] the record that is passed in.
75
76
  def sign_in(record)
76
- passwordless_session =
77
- if record.is_a?(Passwordless::Session)
78
- record
79
- else
80
- warn "Passwordless::ControllerHelpers#sign_in with authenticatable " \
77
+ passwordless_session = if record.is_a?(Passwordless::Session)
78
+ record
79
+ else
80
+ warn(
81
+ "Passwordless::ControllerHelpers#sign_in with authenticatable " \
81
82
  "(`#{record.class}') is deprecated. Falling back to creating a " \
82
83
  "new Passwordless::Session"
83
- build_passwordless_session(record).tap { |s| s.save! }
84
- end
84
+ )
85
+ build_passwordless_session(record).tap { |s| s.save! }
86
+ end
85
87
 
86
88
  passwordless_session.claim! if Passwordless.restrict_token_reuse
87
89
 
88
90
  raise Passwordless::Errors::SessionTimedOutError if passwordless_session.timed_out?
89
91
 
92
+ old_session = session.dup.to_hash
93
+ reset_session if defined?(reset_session) # allow usage outside controllers
94
+ old_session.each_pair { |k, v| session[k.to_sym] = v }
95
+
90
96
  key = session_key(passwordless_session.authenticatable_type)
91
97
  session[key] = passwordless_session.id
92
98
 
@@ -105,9 +111,9 @@ module Passwordless
105
111
  key = cookie_name(authenticatable_class)
106
112
  cookies.encrypted.permanent[key] = {value: nil}
107
113
  cookies.delete(key)
108
- # /deprecated
109
114
 
110
- reset_session
115
+ # /deprecated
116
+ reset_session if defined?(reset_session) # allow usage outside controllers
111
117
  true
112
118
  end
113
119
 
@@ -7,15 +7,17 @@ module Passwordless
7
7
 
8
8
  config.to_prepare do
9
9
  require "passwordless/router_helpers"
10
+
10
11
  ActionDispatch::Routing::Mapper.include RouterHelpers
11
12
  require "passwordless/model_helpers"
13
+
12
14
  ActiveRecord::Base.extend ModelHelpers
13
15
  require "passwordless/controller_helpers"
16
+
14
17
  end
15
18
 
16
19
  config.before_initialize do |app|
17
- app.config.i18n.load_path +=
18
- Dir[Engine.root.join("config", "locales", "*.yml")]
20
+ app.config.i18n.load_path += Dir[Engine.root.join("config", "locales", "*.yml")]
19
21
  end
20
22
  end
21
23
  end
@@ -3,9 +3,11 @@
3
3
  module Passwordless
4
4
  module Errors
5
5
  # Raise this exception when a session is expired.
6
- class SessionTimedOutError < StandardError; end
6
+ class SessionTimedOutError < StandardError
7
+ end
7
8
 
8
9
  # Raise this exception when the token has been previously claimed
9
- class TokenAlreadyClaimedError < StandardError; end
10
+ class TokenAlreadyClaimedError < StandardError
11
+ end
10
12
  end
11
13
  end
@@ -8,9 +8,11 @@ module Passwordless
8
8
  # field name (e.g. `:email`)
9
9
  # @param field [string] email submitted by user.
10
10
  def passwordless_with(field)
11
- has_many :passwordless_sessions,
11
+ has_many(
12
+ :passwordless_sessions,
12
13
  class_name: "Passwordless::Session",
13
14
  as: :authenticatable
15
+ )
14
16
 
15
17
  define_singleton_method(:passwordless_email_field) { field }
16
18
  end
@@ -20,8 +20,10 @@ module Passwordless
20
20
  mount_at = at || resource.to_s
21
21
  mount_as = as || resource.to_s
22
22
  mount(
23
- Passwordless::Engine, at: mount_at, as: mount_as,
24
- defaults: {authenticatable: resource.to_s.singularize}
23
+ Passwordless::Engine,
24
+ at: mount_at,
25
+ as: mount_as,
26
+ defaults: {authenticatable: resource.to_s.singularize}
25
27
  )
26
28
 
27
29
  Passwordless.mounted_as = mount_as
@@ -0,0 +1,43 @@
1
+ module Passwordless
2
+ module TestHelpers
3
+ module TestCase
4
+ def passwordless_sign_out
5
+ delete Passwordless::Engine.routes.url_helpers.sign_out_path
6
+ follow_redirect!
7
+ end
8
+
9
+ def passwordless_sign_in(resource)
10
+ session = Passwordless::Session.create!(authenticatable: resource, user_agent: "TestAgent", remote_addr: "unknown")
11
+ get Passwordless::Engine.routes.url_helpers.token_sign_in_path(session.token)
12
+ follow_redirect!
13
+ end
14
+ end
15
+
16
+ module SystemTestCase
17
+ def passwordless_sign_out
18
+ visit Passwordless::Engine.routes.url_helpers.sign_out_path
19
+ end
20
+
21
+ def passwordless_sign_in(resource)
22
+ session = Passwordless::Session.create!(authenticatable: resource, user_agent: "TestAgent", remote_addr: "unknown")
23
+ visit Passwordless::Engine.routes.url_helpers.token_sign_in_path(session.token)
24
+ end
25
+ end
26
+ end
27
+ end
28
+
29
+ if defined?(ActiveSupport::TestCase)
30
+ ActiveSupport::TestCase.send(:include, ::Passwordless::TestHelpers::TestCase)
31
+ end
32
+
33
+ if defined?(ActionDispatch::SystemTestCase)
34
+ ActionDispatch::SystemTestCase.send(:include, ::Passwordless::TestHelpers::SystemTestCase)
35
+ end
36
+
37
+ if defined?(RSpec)
38
+ RSpec.configure do |config|
39
+ config.include ::Passwordless::TestHelpers::TestCase, type: :request
40
+ config.include ::Passwordless::TestHelpers::TestCase, type: :controller
41
+ config.include ::Passwordless::TestHelpers::SystemTestCase, type: :system
42
+ end
43
+ end
@@ -1,5 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Passwordless
4
- VERSION = "0.10.0" # :nodoc:
4
+ # :nodoc:
5
+ VERSION = "0.12.0"
5
6
  end
data/lib/passwordless.rb CHANGED
@@ -16,6 +16,7 @@ module Passwordless
16
16
 
17
17
  mattr_accessor(:expires_at) { lambda { 1.year.from_now } }
18
18
  mattr_accessor(:timeout_at) { lambda { 1.hour.from_now } }
19
+ mattr_accessor(:redirect_to_response_options) { {} }
19
20
  mattr_accessor(:success_redirect_path) { "/" }
20
21
  mattr_accessor(:failure_redirect_path) { "/" }
21
22
  mattr_accessor(:sign_out_redirect_path) { "/" }
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.10.0
4
+ version: 0.12.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: 2020-10-07 00:00:00.000000000 Z
11
+ date: 2023-06-16 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
@@ -42,14 +42,14 @@ dependencies:
42
42
  name: sqlite3
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
- - - "~>"
45
+ - - ">="
46
46
  - !ruby/object:Gem::Version
47
47
  version: 1.4.1
48
48
  type: :development
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
- - - "~>"
52
+ - - ">="
53
53
  - !ruby/object:Gem::Version
54
54
  version: 1.4.1
55
55
  - !ruby/object:Gem::Dependency
@@ -96,17 +96,18 @@ files:
96
96
  - app/models/passwordless/application_record.rb
97
97
  - app/models/passwordless/session.rb
98
98
  - app/views/passwordless/mailer/magic_link.text.erb
99
- - app/views/passwordless/sessions/create.html.erb
100
99
  - app/views/passwordless/sessions/new.html.erb
101
100
  - config/locales/en.yml
102
101
  - config/routes.rb
103
102
  - db/migrate/20171104221735_create_passwordless_sessions.rb
103
+ - lib/generators/passwordless/views_generator.rb
104
104
  - lib/passwordless.rb
105
105
  - lib/passwordless/controller_helpers.rb
106
106
  - lib/passwordless/engine.rb
107
107
  - lib/passwordless/errors.rb
108
108
  - lib/passwordless/model_helpers.rb
109
109
  - lib/passwordless/router_helpers.rb
110
+ - lib/passwordless/test_helpers.rb
110
111
  - lib/passwordless/url_safe_base_64_generator.rb
111
112
  - lib/passwordless/version.rb
112
113
  homepage: https://github.com/mikker/passwordless
@@ -128,7 +129,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
128
129
  - !ruby/object:Gem::Version
129
130
  version: '0'
130
131
  requirements: []
131
- rubygems_version: 3.1.4
132
+ rubygems_version: 3.4.14
132
133
  signing_key:
133
134
  specification_version: 4
134
135
  summary: Add authentication to your app without all the ickyness of passwords.
@@ -1 +0,0 @@
1
- <p><%= I18n.t('passwordless.sessions.create.email_sent_if_record_found') %></p>