passwordless 0.7.0 → 0.8.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/README.md +62 -24
- data/app/controllers/passwordless/sessions_controller.rb +16 -18
- data/app/models/passwordless/session.rb +21 -1
- data/config/locales/en.yml +2 -1
- data/db/migrate/20171104221735_create_passwordless_sessions.rb +1 -0
- data/lib/passwordless.rb +9 -1
- data/lib/passwordless/controller_helpers.rb +89 -17
- data/lib/passwordless/errors.rb +11 -0
- data/lib/passwordless/version.rb +1 -1
- metadata +6 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5f6c0006a3a1aa712922ef4c48b3afc4b5f1b722d9f37f624b367cb2e66ea895
|
4
|
+
data.tar.gz: 2c06ad86a47e11757a978fd879b7ab23e888589ecc1e734740886f148d1abb5a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 1cecfce2bcc7a6427cd037123aa4733c034126f2f55d47445d8439144db325aa00796cadfa9da40daa429a54073a7fc5c4e61d6f088fd2c8feb8fc653cd593fb
|
7
|
+
data.tar.gz: 673f6c504efd94c5f01f2bd073c427012e91d4c6bacf1a113cdc851b1bcb083183a7634ded733ac22f307e9ef4ccf4fbd2a30919dddce5ce0683e3c61b04380e
|
data/README.md
CHANGED
@@ -16,6 +16,7 @@ Add authentication to your Rails app without all the icky-ness of passwords.
|
|
16
16
|
* [Usage](#usage)
|
17
17
|
* [Getting the current user, restricting access, the usual](#getting-the-current-user-restricting-access-the-usual)
|
18
18
|
* [Providing your own templates](#providing-your-own-templates)
|
19
|
+
* [Claming tokens](#claiming-tokens)
|
19
20
|
* [Overrides](#overrides)
|
20
21
|
* [Registering new users](#registering-new-users)
|
21
22
|
* [Generating tokens](#generating-tokens)
|
@@ -43,7 +44,7 @@ $ bin/rails passwordless:install:migrations
|
|
43
44
|
|
44
45
|
## Usage
|
45
46
|
|
46
|
-
Passwordless creates a single model called `Passwordless::Session`. It doesn't come with its own `User` model, it expects you to create one
|
47
|
+
Passwordless creates a single model called `Passwordless::Session`. It doesn't come with its own `User` model, it expects you to create one:
|
47
48
|
|
48
49
|
```
|
49
50
|
$ bin/rails generate model User email
|
@@ -71,7 +72,7 @@ end
|
|
71
72
|
|
72
73
|
### Getting the current user, restricting access, the usual
|
73
74
|
|
74
|
-
Passwordless doesn't give you `current_user` automatically
|
75
|
+
Passwordless doesn't give you `current_user` automatically. Here's how you could add it:
|
75
76
|
|
76
77
|
```ruby
|
77
78
|
class ApplicationController < ActionController::Base
|
@@ -84,7 +85,7 @@ class ApplicationController < ActionController::Base
|
|
84
85
|
private
|
85
86
|
|
86
87
|
def current_user
|
87
|
-
@current_user ||=
|
88
|
+
@current_user ||= authenticate_by_session(User)
|
88
89
|
end
|
89
90
|
|
90
91
|
def require_user!
|
@@ -121,36 +122,20 @@ app/views/passwordless/mailer/magic_link.text.erb
|
|
121
122
|
|
122
123
|
See [the bundled views](https://github.com/mikker/passwordless/tree/master/app/views/passwordless).
|
123
124
|
|
124
|
-
### Overrides
|
125
|
-
|
126
|
-
By default `passwordless` uses the `passwordless_with` column you specify in the model to case insensitively fetch the resource during authentication. You can override this and provide your own customer fetcher by defining a class method `fetch_resource_for_passwordless` in your passwordless model. The method will be supplied with the downcased email and should return an `ActiveRecord` instance of the model.
|
127
|
-
|
128
|
-
Example time:
|
129
|
-
|
130
|
-
Let's say we would like to fetch the record and if it doesn't exist, create automatically.
|
131
|
-
|
132
|
-
```ruby
|
133
|
-
class User < ApplicationRecord
|
134
|
-
def self.fetch_resource_for_passwordless(email)
|
135
|
-
find_or_create_by(email: email)
|
136
|
-
end
|
137
|
-
end
|
138
|
-
```
|
139
|
-
|
140
125
|
### Registering new users
|
141
126
|
|
142
|
-
Because your `User` record is like any other record, you create one like you normally would. Passwordless provides a helper method
|
127
|
+
Because your `User` record is like any other record, you create one like you normally would. Passwordless provides a helper method to sign in the created user after it is saved – like so:
|
143
128
|
|
144
129
|
```ruby
|
145
130
|
class UsersController < ApplicationController
|
146
131
|
include Passwordless::ControllerHelpers # <-- This!
|
147
|
-
#
|
132
|
+
# (unless you already have it in your ApplicationController)
|
148
133
|
|
149
134
|
def create
|
150
135
|
@user = User.new user_params
|
151
136
|
|
152
137
|
if @user.save
|
153
|
-
sign_in @user # <--
|
138
|
+
sign_in @user # <-- This!
|
154
139
|
redirect_to @user, flash: {notice: 'Welcome!'}
|
155
140
|
else
|
156
141
|
render :new
|
@@ -163,7 +148,7 @@ end
|
|
163
148
|
|
164
149
|
### Generating tokens
|
165
150
|
|
166
|
-
By default Passwordless generates tokens using
|
151
|
+
By default Passwordless generates tokens using `SecureRandom.urlsafe_base64` but you can change that by setting `Passwordless.token_generator` to something else that responds to `call(session)` eg.:
|
167
152
|
|
168
153
|
```ruby
|
169
154
|
Passwordless.token_generator = -> (session) {
|
@@ -241,7 +226,7 @@ By default, magic link will send by email. You can customize this method. For ex
|
|
241
226
|
config/initializers/passwordless.rb
|
242
227
|
|
243
228
|
```
|
244
|
-
Passwordless.after_session_save = lambda do |session|
|
229
|
+
Passwordless.after_session_save = lambda do |session, request|
|
245
230
|
# Default behavior is
|
246
231
|
# Mailer.magic_link(session).deliver_now
|
247
232
|
|
@@ -252,6 +237,55 @@ end
|
|
252
237
|
|
253
238
|
You can access user model through authenticatable.
|
254
239
|
|
240
|
+
### Claiming tokens
|
241
|
+
|
242
|
+
Opt-in for marking tokens as `claimed` so they can only be used once.
|
243
|
+
|
244
|
+
config/initializers/passwordless.rb
|
245
|
+
|
246
|
+
```ruby
|
247
|
+
# Default is `false`
|
248
|
+
Passwordless.restrict_token_reuse = true
|
249
|
+
```
|
250
|
+
|
251
|
+
#### Upgrading an existing Rails app
|
252
|
+
|
253
|
+
The simplest way to update your sessions table is with a single migration:
|
254
|
+
|
255
|
+
<details>
|
256
|
+
<summary>Example migration</summary>
|
257
|
+
|
258
|
+
```bash
|
259
|
+
bin/rails generate migration add_claimed_at_to_passwordless_sessions
|
260
|
+
```
|
261
|
+
|
262
|
+
```ruby
|
263
|
+
class AddClaimedAtToPasswordlessSessions < ActiveRecord::Migration[5.2]
|
264
|
+
def change
|
265
|
+
add_column :passwordless_sessions, :claimed_at, :datetime
|
266
|
+
end
|
267
|
+
end
|
268
|
+
|
269
|
+
```
|
270
|
+
</details>
|
271
|
+
|
272
|
+
### Overrides
|
273
|
+
|
274
|
+
By default `passwordless` uses the `passwordless_with` column to _case insensitively_ fetch the resource.
|
275
|
+
|
276
|
+
You can override this and provide your own customer fetcher by defining a class method `fetch_resource_for_passwordless` in your passwordless model. The method will be called with the downcased email and should return an `ActiveRecord` instance of the model.
|
277
|
+
|
278
|
+
Example time:
|
279
|
+
|
280
|
+
Let's say we would like to fetch the record and if it doesn't exist, create automatically.
|
281
|
+
|
282
|
+
```ruby
|
283
|
+
class User < ApplicationRecord
|
284
|
+
def self.fetch_resource_for_passwordless(email)
|
285
|
+
find_or_create_by(email: email)
|
286
|
+
end
|
287
|
+
end
|
288
|
+
```
|
255
289
|
|
256
290
|
### E-mail security
|
257
291
|
|
@@ -261,6 +295,10 @@ But be aware that when everyone authenticates via emails you send, the way you s
|
|
261
295
|
|
262
296
|
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.
|
263
297
|
|
298
|
+
# Alternatives
|
299
|
+
|
300
|
+
- [OTP JWT](https://github.com/stas/otp-jwt) -- Passwordless JSON Web Tokens
|
301
|
+
|
264
302
|
# License
|
265
303
|
|
266
304
|
MIT
|
@@ -5,9 +5,6 @@ require "bcrypt"
|
|
5
5
|
module Passwordless
|
6
6
|
# Controller for managing Passwordless sessions
|
7
7
|
class SessionsController < ApplicationController
|
8
|
-
# Raise this exception when a session is expired.
|
9
|
-
class SessionTimedOutError < StandardError; end
|
10
|
-
|
11
8
|
include ControllerHelpers
|
12
9
|
|
13
10
|
# get '/sign_in'
|
@@ -26,7 +23,11 @@ module Passwordless
|
|
26
23
|
session = build_passwordless_session(find_authenticatable)
|
27
24
|
|
28
25
|
if session.save
|
29
|
-
Passwordless.after_session_save.
|
26
|
+
if Passwordless.after_session_save.arity == 2
|
27
|
+
Passwordless.after_session_save.call(session, request)
|
28
|
+
else
|
29
|
+
Passwordless.after_session_save.call(session)
|
30
|
+
end
|
30
31
|
end
|
31
32
|
|
32
33
|
render
|
@@ -42,20 +43,17 @@ module Passwordless
|
|
42
43
|
# Make it "slow" on purpose to make brute-force attacks more of a hassle
|
43
44
|
BCrypt::Password.create(params[:token])
|
44
45
|
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
sign_in session.authenticatable
|
46
|
+
destination =
|
47
|
+
Passwordless.redirect_back_after_sign_in &&
|
48
|
+
reset_passwordless_redirect_location!(User)
|
49
49
|
|
50
|
-
|
51
|
-
destination = reset_passwordless_redirect_location!(User)
|
50
|
+
sign_in passwordless_session
|
52
51
|
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
rescue SessionTimedOutError
|
52
|
+
redirect_to destination || main_app.root_path
|
53
|
+
rescue Errors::TokenAlreadyClaimedError
|
54
|
+
flash[:error] = I18n.t(".passwordless.sessions.create.token_claimed")
|
55
|
+
redirect_to main_app.root_path
|
56
|
+
rescue Errors::SessionTimedOutError
|
59
57
|
flash[:error] = I18n.t(".passwordless.sessions.create.session_expired")
|
60
58
|
redirect_to main_app.root_path
|
61
59
|
end
|
@@ -98,8 +96,8 @@ module Passwordless
|
|
98
96
|
end
|
99
97
|
end
|
100
98
|
|
101
|
-
def
|
102
|
-
Session.find_by!(
|
99
|
+
def passwordless_session
|
100
|
+
@passwordless_session ||= Session.find_by!(
|
103
101
|
authenticatable_type: authenticatable_classname,
|
104
102
|
token: params[:token]
|
105
103
|
)
|
@@ -18,10 +18,17 @@ module Passwordless
|
|
18
18
|
|
19
19
|
before_validation :set_defaults
|
20
20
|
|
21
|
-
scope :
|
21
|
+
scope :available, lambda {
|
22
22
|
where("timeout_at > ?", Time.current)
|
23
23
|
}
|
24
24
|
|
25
|
+
def self.valid
|
26
|
+
available
|
27
|
+
end
|
28
|
+
class << self
|
29
|
+
deprecate :valid, deprecator: SessionValidDeprecation
|
30
|
+
end
|
31
|
+
|
25
32
|
def expired?
|
26
33
|
expires_at <= Time.current
|
27
34
|
end
|
@@ -30,6 +37,19 @@ module Passwordless
|
|
30
37
|
timeout_at <= Time.current
|
31
38
|
end
|
32
39
|
|
40
|
+
def claim!
|
41
|
+
raise Errors::TokenAlreadyClaimedError if claimed?
|
42
|
+
touch(:claimed_at)
|
43
|
+
end
|
44
|
+
|
45
|
+
def claimed?
|
46
|
+
!!claimed_at
|
47
|
+
end
|
48
|
+
|
49
|
+
def available?
|
50
|
+
!timed_out? && !expired?
|
51
|
+
end
|
52
|
+
|
33
53
|
private
|
34
54
|
|
35
55
|
def set_defaults
|
data/config/locales/en.yml
CHANGED
@@ -5,8 +5,9 @@ en:
|
|
5
5
|
create:
|
6
6
|
session_expired: 'Your session has expired, please sign in again.'
|
7
7
|
email_sent_if_record_found: "If we found you in the system, we've sent you an email."
|
8
|
+
token_claimed: "This link has already been used, try requesting the link again"
|
8
9
|
new:
|
9
10
|
submit: 'Send magic link'
|
10
11
|
mailer:
|
11
|
-
subject: "Your magic link ✨
|
12
|
+
subject: "Your magic link ✨"
|
12
13
|
magic_link: "Here's your link: %{link}"
|
@@ -10,6 +10,7 @@ class CreatePasswordlessSessions < ActiveRecord::Migration[5.1]
|
|
10
10
|
)
|
11
11
|
t.datetime :timeout_at, null: false
|
12
12
|
t.datetime :expires_at, null: false
|
13
|
+
t.datetime :claimed_at
|
13
14
|
t.text :user_agent, null: false
|
14
15
|
t.string :remote_addr, null: false
|
15
16
|
t.string :token, null: false
|
data/lib/passwordless.rb
CHANGED
@@ -1,5 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require "active_support"
|
4
|
+
require "passwordless/errors"
|
3
5
|
require "passwordless/engine"
|
4
6
|
require "passwordless/url_safe_base_64_generator"
|
5
7
|
|
@@ -7,11 +9,17 @@ require "passwordless/url_safe_base_64_generator"
|
|
7
9
|
module Passwordless
|
8
10
|
mattr_accessor(:default_from_address) { "CHANGE_ME@example.com" }
|
9
11
|
mattr_accessor(:token_generator) { UrlSafeBase64Generator.new }
|
12
|
+
mattr_accessor(:restrict_token_reuse) { false }
|
10
13
|
mattr_accessor(:redirect_back_after_sign_in) { true }
|
11
14
|
mattr_accessor(:mounted_as) { :configured_when_mounting_passwordless }
|
12
15
|
|
13
16
|
mattr_accessor(:expires_at) { lambda { 1.year.from_now } }
|
14
17
|
mattr_accessor(:timeout_at) { lambda { 1.hour.from_now } }
|
15
18
|
|
16
|
-
mattr_accessor(:after_session_save)
|
19
|
+
mattr_accessor(:after_session_save) do
|
20
|
+
lambda { |session, _request| Mailer.magic_link(session).deliver_now }
|
21
|
+
end
|
22
|
+
|
23
|
+
CookieDeprecation = ActiveSupport::Deprecation.new("0.9", "passwordless")
|
24
|
+
SessionValidDeprecation = ActiveSupport::Deprecation.new("0.9", "passwordless")
|
17
25
|
end
|
@@ -3,6 +3,12 @@
|
|
3
3
|
module Passwordless
|
4
4
|
# Helpers to work with Passwordless sessions from controllers
|
5
5
|
module ControllerHelpers
|
6
|
+
# Returns the {Passwordless::Session} (if set) from the session.
|
7
|
+
# @return [Session, nil]
|
8
|
+
def find_passwordless_session_for(authenticatable_class)
|
9
|
+
Passwordless::Session.find_by(id: session[session_key(authenticatable_class)])
|
10
|
+
end
|
11
|
+
|
6
12
|
# Build a new Passwordless::Session from an _authenticatable_ record.
|
7
13
|
# Set's `user_agent` and `remote_addr` from Rails' `request`.
|
8
14
|
# @param authenticatable [ActiveRecord::Base] Instance of an
|
@@ -17,6 +23,7 @@ module Passwordless
|
|
17
23
|
end
|
18
24
|
end
|
19
25
|
|
26
|
+
# @deprecated Use {ControllerHelpers#authenticate_by_session}
|
20
27
|
# Authenticate a record using cookies. Looks for a cookie corresponding to
|
21
28
|
# the _authenticatable_class_. If found try to find it in the database.
|
22
29
|
# @param authenticatable_class [ActiveRecord::Base] any Model connected to
|
@@ -27,54 +34,119 @@ module Passwordless
|
|
27
34
|
def authenticate_by_cookie(authenticatable_class)
|
28
35
|
key = cookie_name(authenticatable_class)
|
29
36
|
authenticatable_id = cookies.encrypted[key]
|
30
|
-
return unless authenticatable_id
|
31
37
|
|
32
|
-
authenticatable_class.find_by(id: authenticatable_id)
|
38
|
+
return authenticatable_class.find_by(id: authenticatable_id) if authenticatable_id
|
39
|
+
|
40
|
+
authenticate_by_session(authenticatable_class)
|
41
|
+
end
|
42
|
+
deprecate :authenticate_by_cookie, deprecator: CookieDeprecation
|
43
|
+
|
44
|
+
def upgrade_passwordless_cookie(authenticatable_class)
|
45
|
+
key = cookie_name(authenticatable_class)
|
46
|
+
|
47
|
+
return unless authenticatable_id = cookies.encrypted[key]
|
48
|
+
cookies.encrypted.permanent[key] = {value: nil}
|
49
|
+
cookies.delete(key)
|
50
|
+
|
51
|
+
return unless record = authenticatable_class.find_by(id: authenticatable_id)
|
52
|
+
new_session = build_passwordless_session(record).tap { |s| s.save! }
|
53
|
+
|
54
|
+
sign_in new_session
|
55
|
+
|
56
|
+
new_session.authenticatable
|
57
|
+
end
|
58
|
+
|
59
|
+
# Authenticate a record using the session. Looks for a session key corresponding to
|
60
|
+
# the _authenticatable_class_. If found try to find it in the database.
|
61
|
+
# @param authenticatable_class [ActiveRecord::Base] any Model connected to
|
62
|
+
# passwordless. (e.g - _User_ or _Admin_).
|
63
|
+
# @return [ActiveRecord::Base|nil] an instance of Model found by id stored
|
64
|
+
# in cookies.encrypted or nil if nothing is found.
|
65
|
+
# @see ModelHelpers#passwordless_with
|
66
|
+
def authenticate_by_session(authenticatable_class)
|
67
|
+
return unless find_passwordless_session_for(authenticatable_class)&.available?
|
68
|
+
find_passwordless_session_for(authenticatable_class).authenticatable
|
33
69
|
end
|
34
70
|
|
35
|
-
# Signs in
|
36
|
-
# @param authenticatable [
|
37
|
-
#
|
71
|
+
# Signs in session
|
72
|
+
# @param authenticatable [Passwordless::Session] Instance of {Passwordless::Session}
|
73
|
+
# to sign in
|
38
74
|
# @return [ActiveRecord::Base] the record that is passed in.
|
39
|
-
def sign_in(
|
40
|
-
|
41
|
-
|
42
|
-
|
75
|
+
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 " \
|
81
|
+
"(`#{record.class}') is deprecated. Falling back to creating a " \
|
82
|
+
"new Passwordless::Session"
|
83
|
+
build_passwordless_session(record).tap { |s| s.save! }
|
84
|
+
end
|
85
|
+
|
86
|
+
passwordless_session.claim! if Passwordless.restrict_token_reuse
|
87
|
+
|
88
|
+
raise Passwordless::Errors::SessionTimedOutError if passwordless_session.timed_out?
|
89
|
+
|
90
|
+
key = session_key(passwordless_session.authenticatable_type)
|
91
|
+
session[key] = passwordless_session.id
|
92
|
+
|
93
|
+
if record.is_a?(Passwordless::Session)
|
94
|
+
passwordless_session
|
95
|
+
else
|
96
|
+
passwordless_session.authenticatable
|
97
|
+
end
|
43
98
|
end
|
44
99
|
|
45
|
-
# Signs out user by deleting
|
46
|
-
# @param (see #
|
100
|
+
# Signs out user by deleting the session key.
|
101
|
+
# @param (see #authenticate_by_session)
|
47
102
|
# @return [boolean] Always true
|
48
103
|
def sign_out(authenticatable_class)
|
104
|
+
# Deprecated - cookies
|
49
105
|
key = cookie_name(authenticatable_class)
|
50
106
|
cookies.encrypted.permanent[key] = {value: nil}
|
51
107
|
cookies.delete(key)
|
108
|
+
# /deprecated
|
109
|
+
|
110
|
+
reset_session
|
52
111
|
true
|
53
112
|
end
|
54
113
|
|
55
114
|
# Saves request.original_url as the redirect location for a
|
56
115
|
# passwordless Model.
|
57
|
-
# @param (see #
|
116
|
+
# @param (see #authenticate_by_session)
|
58
117
|
# @return [String] the redirect url that was just saved.
|
59
118
|
def save_passwordless_redirect_location!(authenticatable_class)
|
60
|
-
session[
|
119
|
+
session[redirect_session_key(authenticatable_class)] = request.original_url
|
61
120
|
end
|
62
121
|
|
63
122
|
# Resets the redirect_location to root_path by deleting the redirect_url
|
64
123
|
# from session.
|
65
|
-
# @param (see #
|
124
|
+
# @param (see #authenticate_by_session)
|
66
125
|
# @return [String, nil] the redirect url that was just deleted,
|
67
126
|
# or nil if no url found for given Model.
|
68
127
|
def reset_passwordless_redirect_location!(authenticatable_class)
|
69
|
-
session.delete
|
128
|
+
session.delete(redirect_session_key(authenticatable_class))
|
129
|
+
end
|
130
|
+
|
131
|
+
def session_key(authenticatable_class)
|
132
|
+
:"passwordless_session_id--#{authenticatable_class_parameterized(authenticatable_class)}"
|
70
133
|
end
|
71
134
|
|
72
135
|
private
|
73
136
|
|
74
|
-
def
|
75
|
-
|
137
|
+
def authenticatable_class_parameterized(authenticatable_class)
|
138
|
+
if authenticatable_class.is_a?(String)
|
139
|
+
authenticatable_class = authenticatable_class.constantize
|
140
|
+
end
|
141
|
+
|
142
|
+
authenticatable_class.base_class.to_s.parameterize
|
143
|
+
end
|
144
|
+
|
145
|
+
def redirect_session_key(authenticatable_class)
|
146
|
+
:"passwordless_prev_location--#{authenticatable_class_parameterized(authenticatable_class)}"
|
76
147
|
end
|
77
148
|
|
149
|
+
# Deprecated
|
78
150
|
def cookie_name(authenticatable_class)
|
79
151
|
:"#{authenticatable_class.base_class.to_s.underscore}_id"
|
80
152
|
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Passwordless
|
4
|
+
module Errors
|
5
|
+
# Raise this exception when a session is expired.
|
6
|
+
class SessionTimedOutError < StandardError; end
|
7
|
+
|
8
|
+
# Raise this exception when the token has been previously claimed
|
9
|
+
class TokenAlreadyClaimedError < StandardError; end
|
10
|
+
end
|
11
|
+
end
|
data/lib/passwordless/version.rb
CHANGED
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: 0.8.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: 2019-
|
11
|
+
date: 2019-07-30 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|
@@ -44,14 +44,14 @@ dependencies:
|
|
44
44
|
requirements:
|
45
45
|
- - "~>"
|
46
46
|
- !ruby/object:Gem::Version
|
47
|
-
version: 1.
|
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
|
-
version: 1.
|
54
|
+
version: 1.4.1
|
55
55
|
- !ruby/object:Gem::Dependency
|
56
56
|
name: yard
|
57
57
|
requirement: !ruby/object:Gem::Requirement
|
@@ -104,6 +104,7 @@ files:
|
|
104
104
|
- lib/passwordless.rb
|
105
105
|
- lib/passwordless/controller_helpers.rb
|
106
106
|
- lib/passwordless/engine.rb
|
107
|
+
- lib/passwordless/errors.rb
|
107
108
|
- lib/passwordless/model_helpers.rb
|
108
109
|
- lib/passwordless/router_helpers.rb
|
109
110
|
- lib/passwordless/url_safe_base_64_generator.rb
|
@@ -127,7 +128,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
127
128
|
- !ruby/object:Gem::Version
|
128
129
|
version: '0'
|
129
130
|
requirements: []
|
130
|
-
rubygems_version: 3.0.
|
131
|
+
rubygems_version: 3.0.4
|
131
132
|
signing_key:
|
132
133
|
specification_version: 4
|
133
134
|
summary: Add authentication to your app without all the ickyness of passwords.
|