passwordless 0.6.0 → 0.7.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 00fe76a0b0247e700ff5868fcabf1dc82b1bffddd63437f21d5ec5c4dce83479
4
- data.tar.gz: ff56c5859f448221da83458c17dd30623bd335942fe77e44bede19144a7dd49e
3
+ metadata.gz: eb17c0cc08c9dd0062b47d67a470adeee2d0e7dc618e48967180eea61796f47a
4
+ data.tar.gz: 870dd7a03e131344f20bdee24ab614e1ef66ff3fe8faf9d4bd05bb08adce032d
5
5
  SHA512:
6
- metadata.gz: 2e3281f7a60b04f82796a00759a6aea284aeeafb237670c10f458a629ea02b0d55607f155b4efa257209f580aeb394b0bf33c69c5bce250ec3e179e01eecaf89
7
- data.tar.gz: 81ddaae8d5120e6e1867a8992bc9c0b0f596933ba163dac63a1b3ad39b2b4ba40d84c6b69bb1764283ea9eac39eba199f1fbced0a91f1f93f16f10f01e56bf38
6
+ metadata.gz: e43144bae67ad300ae753fe131ec6b09fcf997c975e2fcb9a819d457fb0178797d03b4e7278c3c92c4cc18664c54c5231de428be7f6fc63c05a878516e628f7a
7
+ data.tar.gz: 5aeca84a612458d6e2dce0b0e9335d80a9f4e4af730540a148c3ef0ed6056417a33b444bfc17c19adf06744a7a2fa38dccb82189206bf2c86354352540b41e7e
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)
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)
8
8
 
9
9
  Add authentication to your Rails app without all the icky-ness of passwords.
10
10
 
@@ -22,6 +22,7 @@ Add authentication to your Rails app without all the icky-ness of passwords.
22
22
  * [Token and Session Expiry](#token-and-session-expiry)
23
23
  * [Redirecting back after sign-in](#redirecting-back-after-sign-in)
24
24
  * [URLs and links](#urls-and-links)
25
+ * [Customize the way to send magic link](#customize-the-way-to-send-magic-link)
25
26
  * [E-mail security](#e-mail-security)
26
27
  * [License](#license)
27
28
 
@@ -232,6 +233,26 @@ passwordless_for :users, at: '/', as: :auth
232
233
 
233
234
  Also be sure to [specify ActionMailer's `default_url_options.host`](http://guides.rubyonrails.org/action_mailer_basics.html#generating-urls-in-action-mailer-views).
234
235
 
236
+
237
+ ### Customize the way to send magic link
238
+
239
+ By default, magic link will send by email. You can customize this method. For example, you can send magic link via SMS.
240
+
241
+ config/initializers/passwordless.rb
242
+
243
+ ```
244
+ Passwordless.after_session_save = lambda do |session|
245
+ # Default behavior is
246
+ # Mailer.magic_link(session).deliver_now
247
+
248
+ # You can change behavior to do something with session model. For example,
249
+ # session.authenticatable.send_sms
250
+ end
251
+ ```
252
+
253
+ You can access user model through authenticatable.
254
+
255
+
235
256
  ### E-mail security
236
257
 
237
258
  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.
data/Rakefile CHANGED
@@ -1,27 +1,29 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  begin
4
- require 'bundler/setup'
4
+ require "bundler/setup"
5
5
  rescue LoadError
6
- puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
6
+ puts "You must `gem install bundler` and `bundle install` to run rake tasks"
7
7
  end
8
8
 
9
- require 'yard'
9
+ require "yard"
10
10
  YARD::Rake::YardocTask.new
11
11
  task docs: :yard
12
12
 
13
- APP_RAKEFILE = File.expand_path('../test/dummy/Rakefile', __FILE__)
14
- load 'rails/tasks/engine.rake'
15
- load 'rails/tasks/statistics.rake'
13
+ APP_RAKEFILE = File.expand_path("../test/dummy/Rakefile", __FILE__)
14
+ load "rails/tasks/engine.rake"
15
+ load "rails/tasks/statistics.rake"
16
16
 
17
- require 'bundler/gem_tasks'
17
+ require "bundler/gem_tasks"
18
18
 
19
- require 'rake/testtask'
19
+ require "rake/testtask"
20
20
 
21
21
  Rake::TestTask.new(:test) do |t|
22
- t.libs << 'test'
23
- t.pattern = 'test/**/*_test.rb'
22
+ t.libs << "test"
23
+ t.pattern = "test/**/*_test.rb"
24
24
  t.verbose = false
25
25
  end
26
26
 
27
27
  task default: :test
28
+
29
+ require "standard/rake"
@@ -1,12 +1,12 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'bcrypt'
3
+ require "bcrypt"
4
4
 
5
5
  module Passwordless
6
6
  # Controller for managing Passwordless sessions
7
7
  class SessionsController < ApplicationController
8
8
  # Raise this exception when a session is expired.
9
- class ExpiredSessionError < StandardError; end
9
+ class SessionTimedOutError < StandardError; end
10
10
 
11
11
  include ControllerHelpers
12
12
 
@@ -26,14 +26,12 @@ module Passwordless
26
26
  session = build_passwordless_session(find_authenticatable)
27
27
 
28
28
  if session.save
29
- Mailer.magic_link(session).deliver_now
29
+ Passwordless.after_session_save.call(session)
30
30
  end
31
31
 
32
32
  render
33
33
  end
34
34
 
35
- # rubocop:disable Metrics/MethodLength, Metrics/AbcSize
36
-
37
35
  # get '/sign_in/:token'
38
36
  # Looks up session record by provided token. Signs in user if a match
39
37
  # is found. Redirects to either the user's original destination
@@ -45,7 +43,7 @@ module Passwordless
45
43
  BCrypt::Password.create(params[:token])
46
44
 
47
45
  session = find_session
48
- raise ExpiredSessionError if session.expired?
46
+ raise SessionTimedOutError if session.timed_out?
49
47
 
50
48
  sign_in session.authenticatable
51
49
 
@@ -57,11 +55,10 @@ module Passwordless
57
55
  else
58
56
  redirect_to main_app.root_path
59
57
  end
60
- rescue ExpiredSessionError
61
- flash[:error] = I18n.t('.passwordless.sessions.create.session_expired')
58
+ rescue SessionTimedOutError
59
+ flash[:error] = I18n.t(".passwordless.sessions.create.session_expired")
62
60
  redirect_to main_app.root_path
63
61
  end
64
- # rubocop:enable Metrics/MethodLength, Metrics/AbcSize
65
62
 
66
63
  # match '/sign_out', via: %i[get delete].
67
64
  # Signs user out. Redirects to root_path
@@ -102,7 +99,7 @@ module Passwordless
102
99
  end
103
100
 
104
101
  def find_session
105
- Session.valid.find_by!(
102
+ Session.find_by!(
106
103
  authenticatable_type: authenticatable_classname,
107
104
  token: params[:token]
108
105
  )
@@ -11,12 +11,12 @@ module Passwordless
11
11
  @session = session
12
12
 
13
13
  @magic_link = send(Passwordless.mounted_as)
14
- .token_sign_in_url(session.token)
14
+ .token_sign_in_url(session.token)
15
15
 
16
16
  email_field = @session.authenticatable.class.passwordless_email_field
17
17
  mail(
18
18
  to: @session.authenticatable.send(email_field),
19
- subject: I18n.t('passwordless.mailer.subject')
19
+ subject: I18n.t("passwordless.mailer.subject")
20
20
  )
21
21
  end
22
22
  end
@@ -19,22 +19,26 @@ module Passwordless
19
19
  before_validation :set_defaults
20
20
 
21
21
  scope :valid, lambda {
22
- where('timeout_at > ?', Time.current)
22
+ where("timeout_at > ?", Time.current)
23
23
  }
24
24
 
25
25
  def expired?
26
26
  expires_at <= Time.current
27
27
  end
28
28
 
29
+ def timed_out?
30
+ timeout_at <= Time.current
31
+ end
32
+
29
33
  private
30
34
 
31
35
  def set_defaults
32
36
  self.expires_at ||= Passwordless.expires_at.call
33
37
  self.timeout_at ||= Passwordless.timeout_at.call
34
- self.token ||= loop do
38
+ self.token ||= loop {
35
39
  token = Passwordless.token_generator.call(self)
36
40
  break token unless Session.find_by(token: token)
37
- end
41
+ }
38
42
  end
39
43
  end
40
44
  end
@@ -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
@@ -6,7 +6,7 @@ class CreatePasswordlessSessions < ActiveRecord::Migration[5.1]
6
6
  t.belongs_to(
7
7
  :authenticatable,
8
8
  polymorphic: true,
9
- index: { name: 'authenticatable' }
9
+ index: {name: "authenticatable"}
10
10
  )
11
11
  t.datetime :timeout_at, null: false
12
12
  t.datetime :expires_at, null: false
@@ -1,15 +1,17 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'passwordless/engine'
4
- require 'passwordless/url_safe_base_64_generator'
3
+ require "passwordless/engine"
4
+ require "passwordless/url_safe_base_64_generator"
5
5
 
6
6
  # The main Passwordless module
7
7
  module Passwordless
8
- mattr_accessor(:default_from_address) { 'CHANGE_ME@example.com' }
8
+ mattr_accessor(:default_from_address) { "CHANGE_ME@example.com" }
9
9
  mattr_accessor(:token_generator) { UrlSafeBase64Generator.new }
10
10
  mattr_accessor(:redirect_back_after_sign_in) { true }
11
11
  mattr_accessor(:mounted_as) { :configured_when_mounting_passwordless }
12
12
 
13
13
  mattr_accessor(:expires_at) { lambda { 1.year.from_now } }
14
14
  mattr_accessor(:timeout_at) { lambda { 1.hour.from_now } }
15
+
16
+ mattr_accessor(:after_session_save) { lambda { |session| Mailer.magic_link(session).deliver_now } }
15
17
  end
@@ -12,7 +12,7 @@ module Passwordless
12
12
  def build_passwordless_session(authenticatable)
13
13
  Session.new.tap do |us|
14
14
  us.remote_addr = request.remote_addr
15
- us.user_agent = request.env['HTTP_USER_AGENT']
15
+ us.user_agent = request.env["HTTP_USER_AGENT"]
16
16
  us.authenticatable = authenticatable
17
17
  end
18
18
  end
@@ -38,7 +38,7 @@ module Passwordless
38
38
  # @return [ActiveRecord::Base] the record that is passed in.
39
39
  def sign_in(authenticatable)
40
40
  key = cookie_name(authenticatable.class)
41
- cookies.encrypted.permanent[key] = { value: authenticatable.id }
41
+ cookies.encrypted.permanent[key] = {value: authenticatable.id}
42
42
  authenticatable
43
43
  end
44
44
 
@@ -47,7 +47,7 @@ module Passwordless
47
47
  # @return [boolean] Always true
48
48
  def sign_out(authenticatable_class)
49
49
  key = cookie_name(authenticatable_class)
50
- cookies.encrypted.permanent[key] = { value: nil }
50
+ cookies.encrypted.permanent[key] = {value: nil}
51
51
  cookies.delete(key)
52
52
  true
53
53
  end
@@ -6,16 +6,16 @@ module Passwordless
6
6
  isolate_namespace Passwordless
7
7
 
8
8
  config.to_prepare do
9
- require 'passwordless/router_helpers'
9
+ require "passwordless/router_helpers"
10
10
  ActionDispatch::Routing::Mapper.include RouterHelpers
11
- require 'passwordless/model_helpers'
11
+ require "passwordless/model_helpers"
12
12
  ActiveRecord::Base.extend ModelHelpers
13
- require 'passwordless/controller_helpers'
13
+ require "passwordless/controller_helpers"
14
14
  end
15
15
 
16
16
  config.before_initialize do |app|
17
17
  app.config.i18n.load_path +=
18
- Dir[Engine.root.join('config', 'locales', '*.yml')]
18
+ Dir[Engine.root.join("config", "locales", "*.yml")]
19
19
  end
20
20
  end
21
21
  end
@@ -9,7 +9,7 @@ module Passwordless
9
9
  # @param field [string] email submitted by user.
10
10
  def passwordless_with(field)
11
11
  has_many :passwordless_sessions,
12
- class_name: 'Passwordless::Session',
12
+ class_name: "Passwordless::Session",
13
13
  as: :authenticatable
14
14
 
15
15
  define_singleton_method(:passwordless_email_field) { field }
@@ -21,7 +21,7 @@ module Passwordless
21
21
  mount_as = as || resource.to_s
22
22
  mount(
23
23
  Passwordless::Engine, at: mount_at, as: mount_as,
24
- defaults: { authenticatable: resource.to_s.singularize }
24
+ defaults: {authenticatable: resource.to_s.singularize}
25
25
  )
26
26
 
27
27
  Passwordless.mounted_as = mount_as
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Passwordless
4
- VERSION = '0.6.0' # :nodoc:
4
+ VERSION = '0.7.0' # :nodoc:
5
5
  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.6.0
4
+ version: 0.7.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-01-29 00:00:00.000000000 Z
11
+ date: 2019-03-06 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
@@ -42,16 +42,16 @@ dependencies:
42
42
  name: sqlite3
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
- - - ">="
45
+ - - "~>"
46
46
  - !ruby/object:Gem::Version
47
- version: '0'
47
+ version: 1.3.6
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: '0'
54
+ version: 1.3.6
55
55
  - !ruby/object:Gem::Dependency
56
56
  name: yard
57
57
  requirement: !ruby/object:Gem::Requirement
@@ -67,7 +67,7 @@ dependencies:
67
67
  - !ruby/object:Gem::Version
68
68
  version: '0'
69
69
  - !ruby/object:Gem::Dependency
70
- name: rubocop
70
+ name: standard
71
71
  requirement: !ruby/object:Gem::Requirement
72
72
  requirements:
73
73
  - - ">="
@@ -127,7 +127,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
127
127
  - !ruby/object:Gem::Version
128
128
  version: '0'
129
129
  requirements: []
130
- rubygems_version: 3.0.2
130
+ rubygems_version: 3.0.1
131
131
  signing_key:
132
132
  specification_version: 4
133
133
  summary: Add authentication to your app without all the ickyness of passwords.