devise_token_auth 1.0.0 → 1.1.1
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.
Potentially problematic release.
This version of devise_token_auth might be problematic. Click here for more details.
- checksums.yaml +5 -5
- data/README.md +4 -2
- data/app/controllers/devise_token_auth/application_controller.rb +0 -1
- data/app/controllers/devise_token_auth/concerns/resource_finder.rb +11 -12
- data/app/controllers/devise_token_auth/concerns/set_user_by_token.rb +39 -55
- data/app/controllers/devise_token_auth/confirmations_controller.rb +62 -20
- data/app/controllers/devise_token_auth/omniauth_callbacks_controller.rb +51 -26
- data/app/controllers/devise_token_auth/passwords_controller.rb +19 -23
- data/app/controllers/devise_token_auth/registrations_controller.rb +32 -40
- data/app/controllers/devise_token_auth/sessions_controller.rb +5 -5
- data/app/controllers/devise_token_auth/unlocks_controller.rb +4 -4
- data/app/models/devise_token_auth/concerns/active_record_support.rb +16 -0
- data/app/models/devise_token_auth/concerns/mongoid_support.rb +19 -0
- data/app/models/devise_token_auth/concerns/tokens_serialization.rb +19 -0
- data/app/models/devise_token_auth/concerns/user.rb +44 -67
- data/app/models/devise_token_auth/concerns/user_omniauth_callbacks.rb +2 -2
- data/app/validators/{email_validator.rb → devise_token_auth_email_validator.rb} +1 -1
- data/config/locales/en.yml +5 -0
- data/config/locales/he.yml +50 -0
- data/config/locales/ja.yml +1 -1
- data/lib/devise_token_auth/blacklist.rb +2 -0
- data/lib/devise_token_auth/engine.rb +2 -0
- data/lib/devise_token_auth/rails/routes.rb +1 -1
- data/lib/devise_token_auth/token_factory.rb +126 -0
- data/lib/devise_token_auth/version.rb +1 -1
- data/lib/devise_token_auth.rb +6 -3
- data/lib/generators/devise_token_auth/install_generator.rb +3 -87
- data/lib/generators/devise_token_auth/install_generator_helpers.rb +98 -0
- data/lib/generators/devise_token_auth/install_mongoid_generator.rb +46 -0
- data/lib/generators/devise_token_auth/templates/devise_token_auth.rb +5 -0
- data/lib/generators/devise_token_auth/templates/devise_token_auth_create_users.rb.erb +0 -7
- data/lib/generators/devise_token_auth/templates/user_mongoid.rb.erb +56 -0
- data/test/controllers/custom/custom_confirmations_controller_test.rb +1 -1
- data/test/controllers/demo_user_controller_test.rb +2 -2
- data/test/controllers/devise_token_auth/confirmations_controller_test.rb +79 -19
- data/test/controllers/devise_token_auth/omniauth_callbacks_controller_test.rb +2 -0
- data/test/controllers/devise_token_auth/passwords_controller_test.rb +115 -94
- data/test/controllers/devise_token_auth/registrations_controller_test.rb +31 -4
- data/test/controllers/devise_token_auth/sessions_controller_test.rb +0 -38
- data/test/controllers/devise_token_auth/token_validations_controller_test.rb +2 -1
- data/test/dummy/app/{models → active_record}/scoped_user.rb +2 -2
- data/test/dummy/app/{models → active_record}/unconfirmable_user.rb +1 -2
- data/test/dummy/app/{models → active_record}/unregisterable_user.rb +3 -3
- data/test/dummy/app/active_record/user.rb +6 -0
- data/test/dummy/app/controllers/overrides/confirmations_controller.rb +3 -3
- data/test/dummy/app/controllers/overrides/passwords_controller.rb +3 -3
- data/test/dummy/app/controllers/overrides/registrations_controller.rb +1 -1
- data/test/dummy/app/controllers/overrides/sessions_controller.rb +2 -2
- data/test/dummy/app/models/{user.rb → concerns/favorite_color.rb} +7 -8
- data/test/dummy/app/mongoid/lockable_user.rb +38 -0
- data/test/dummy/app/mongoid/mang.rb +46 -0
- data/test/dummy/app/mongoid/only_email_user.rb +33 -0
- data/test/dummy/app/mongoid/scoped_user.rb +50 -0
- data/test/dummy/app/mongoid/unconfirmable_user.rb +44 -0
- data/test/dummy/app/mongoid/unregisterable_user.rb +47 -0
- data/test/dummy/app/mongoid/user.rb +49 -0
- data/test/dummy/config/application.rb +23 -1
- data/test/dummy/config/boot.rb +4 -0
- data/test/dummy/config/initializers/devise.rb +285 -0
- data/test/dummy/config/initializers/devise_token_auth.rb +35 -4
- data/test/dummy/db/migrate/20140715061447_devise_token_auth_create_users.rb +0 -7
- data/test/dummy/db/migrate/20140715061805_devise_token_auth_create_mangs.rb +0 -7
- data/test/dummy/db/migrate/20141222035835_devise_token_auth_create_only_email_users.rb +0 -7
- data/test/dummy/db/migrate/20141222053502_devise_token_auth_create_unregisterable_users.rb +0 -7
- data/test/dummy/db/migrate/20150708104536_devise_token_auth_create_unconfirmable_users.rb +0 -7
- data/test/dummy/db/migrate/20160103235141_devise_token_auth_create_scoped_users.rb +0 -7
- data/test/dummy/db/migrate/20160629184441_devise_token_auth_create_lockable_users.rb +0 -7
- data/test/dummy/db/schema.rb +1 -28
- data/test/factories/users.rb +1 -1
- data/test/lib/devise_token_auth/blacklist_test.rb +11 -0
- data/test/lib/devise_token_auth/token_factory_test.rb +191 -0
- data/test/lib/generators/devise_token_auth/install_generator_test.rb +51 -31
- data/test/lib/generators/devise_token_auth/install_generator_with_namespace_test.rb +51 -31
- data/test/models/concerns/mongoid_support_test.rb +31 -0
- data/test/models/concerns/tokens_serialization_test.rb +70 -0
- data/test/models/only_email_user_test.rb +0 -8
- data/test/models/user_test.rb +1 -33
- data/test/test_helper.rb +12 -2
- metadata +105 -25
- data/config/initializers/devise.rb +0 -198
- /data/test/dummy/app/{models → active_record}/lockable_user.rb +0 -0
- /data/test/dummy/app/{models → active_record}/mang.rb +0 -0
- /data/test/dummy/app/{models → active_record}/only_email_user.rb +0 -0
@@ -0,0 +1,126 @@
|
|
1
|
+
require 'bcrypt'
|
2
|
+
|
3
|
+
module DeviseTokenAuth
|
4
|
+
# A token management factory which allow generate token objects and check them.
|
5
|
+
module TokenFactory
|
6
|
+
# For BCrypt::Password class see:
|
7
|
+
# https://github.com/codahale/bcrypt-ruby/blob/master/lib/bcrypt/password.rb
|
8
|
+
|
9
|
+
# Creates a token instance. Takes an optional client, lifespan and cost options.
|
10
|
+
# Example:
|
11
|
+
# DeviseTokenAuth::TokenFactory.create
|
12
|
+
# => #<struct DeviseTokenAuth::TokenFactory::Token client="tElcgkdZ7f9XEa0unZhrYQ", token="rAMcWOs0-mGHFMnIgJD2cA", token_hash="$2a$10$wrsdlHVRGlYW11wfImxU..jr0Ux3bHo/qbXcSfgp8zmvVUNHosita", expiry=1518982690>
|
13
|
+
#
|
14
|
+
# DeviseTokenAuth::TokenFactory.create(lifespan: 10, cost: 4)
|
15
|
+
# => #<struct DeviseTokenAuth::TokenFactory::Token client="5qleT7_t9JPVcX9xmxkVYA", token="RBXX43u4xXNSO-fr2N_4pA", token_hash="$2a$04$9gpCaoFbu2dUKxU3qiTgluHX7jj9UzS.jq1QW0EkQmoaxARo1WxTy", expiry=1517773268>
|
16
|
+
def self.create(client: nil, lifespan: nil, cost: nil)
|
17
|
+
# obj_client = client.nil? ? client() : client
|
18
|
+
obj_client = client || client()
|
19
|
+
obj_token = token
|
20
|
+
obj_token_hash = token_hash(obj_token, cost)
|
21
|
+
obj_expiry = expiry(lifespan)
|
22
|
+
|
23
|
+
Token.new(obj_client, obj_token, obj_token_hash, obj_expiry)
|
24
|
+
end
|
25
|
+
|
26
|
+
# Generates a random URL-safe client.
|
27
|
+
# Example:
|
28
|
+
# DeviseTokenAuth::TokenFactory.client
|
29
|
+
# => "zNf0pNP5iGfuBItZJGCseQ"
|
30
|
+
def self.client
|
31
|
+
secure_string
|
32
|
+
end
|
33
|
+
|
34
|
+
# Generates a random URL-safe token.
|
35
|
+
# Example:
|
36
|
+
# DeviseTokenAuth::TokenFactory.token
|
37
|
+
# => "6Bqs4K9x8ChLmZogvruF3A"
|
38
|
+
def self.token
|
39
|
+
secure_string
|
40
|
+
end
|
41
|
+
|
42
|
+
# Returns token hash for a token with given cost. If no cost value is specified,
|
43
|
+
# the default value is used. The possible cost value is within range from 4 to 31.
|
44
|
+
# It is recommended to not use a value more than 10.
|
45
|
+
# Example:
|
46
|
+
# DeviseTokenAuth::TokenFactory.token_hash("_qxAxmc-biQLiYRHsmwd5Q")
|
47
|
+
# => "$2a$10$6/cTAtQ3CBLfpkeHW7dlt.PD2aVCbFRN5vDDJUUhGsZ6pzYFlh4Me"
|
48
|
+
#
|
49
|
+
# DeviseTokenAuth::TokenFactory.token_hash("_qxAxmc-biQLiYRHsmwd5Q", 4)
|
50
|
+
# => "$2a$04$RkIrosbdRtuet2eUk3si8eS4ufeNpiPc/rSSsfpniRK8ogM5YFOWS"
|
51
|
+
def self.token_hash(token, cost = nil)
|
52
|
+
cost ||= DeviseTokenAuth.token_cost
|
53
|
+
BCrypt::Password.create(token, cost: cost)
|
54
|
+
end
|
55
|
+
|
56
|
+
# Returns the value of time as an integer number of seconds. Takes one argument.
|
57
|
+
# Example:
|
58
|
+
# DeviseTokenAuth::TokenFactory.expiry
|
59
|
+
# => 1518983359
|
60
|
+
# DeviseTokenAuth::TokenFactory.expiry(10)
|
61
|
+
# => 1517773781
|
62
|
+
def self.expiry(lifespan = nil)
|
63
|
+
lifespan ||= DeviseTokenAuth.token_lifespan
|
64
|
+
(Time.zone.now + lifespan).to_i
|
65
|
+
end
|
66
|
+
|
67
|
+
# Generates a random URL-safe string.
|
68
|
+
# Example:
|
69
|
+
# DeviseTokenAuth::TokenFactory.secure_string
|
70
|
+
# => "ADBoIaqXsEDnxIpOuumrTA"
|
71
|
+
def self.secure_string
|
72
|
+
# https://ruby-doc.org/stdlib-2.5.0/libdoc/securerandom/rdoc/Random/Formatter.html#method-i-urlsafe_base64
|
73
|
+
SecureRandom.urlsafe_base64
|
74
|
+
end
|
75
|
+
|
76
|
+
# Returns true if token hash is a valid token hash.
|
77
|
+
# Example:
|
78
|
+
# token_hash = "$2a$10$ArjX0tskRIa5Z/Tmapy59OCiAXLStfhrCiaDz.8fCb6hnX1gJ0p/2"
|
79
|
+
# DeviseTokenAuth::TokenFactory.valid_token_hash?(token_hash)
|
80
|
+
# => true
|
81
|
+
def self.valid_token_hash?(token_hash)
|
82
|
+
!!BCrypt::Password.valid_hash?(token_hash)
|
83
|
+
end
|
84
|
+
|
85
|
+
# Compares a potential token against the token hash. Returns true if the token is the original token, false otherwise.
|
86
|
+
# Example:
|
87
|
+
# token = "4wZ9gcc900rMQD1McpcSNA"
|
88
|
+
# token_hash = "$2a$10$ArjX0tskRIa5Z/Tmapy59OCiAXLStfhrCiaDz.8fCb6hnX1gJ0p/2"
|
89
|
+
# DeviseTokenAuth::TokenFactory.token_hash_is_token?(token_hash, token)
|
90
|
+
# => true
|
91
|
+
def self.token_hash_is_token?(token_hash, token)
|
92
|
+
BCrypt::Password.new(token_hash).is_password?(token)
|
93
|
+
rescue StandardError
|
94
|
+
false
|
95
|
+
end
|
96
|
+
|
97
|
+
# Creates a token instance with instance variables equal nil.
|
98
|
+
# Example:
|
99
|
+
# DeviseTokenAuth::TokenFactory.new
|
100
|
+
# => #<struct DeviseTokenAuth::TokenFactory::Token client=nil, token=nil, token_hash=nil, expiry=nil>
|
101
|
+
def self.new
|
102
|
+
Token.new
|
103
|
+
end
|
104
|
+
|
105
|
+
Token = Struct.new(:client, :token, :token_hash, :expiry) do
|
106
|
+
# Sets all instance variables of the token to nil. It is faster than creating new empty token.
|
107
|
+
# Example:
|
108
|
+
# token.clear!
|
109
|
+
# => true
|
110
|
+
# token
|
111
|
+
# => #<struct DeviseTokenAuth::TokenFactory::Token client=nil, token=nil, token_hash=nil, expiry=nil>
|
112
|
+
def clear!
|
113
|
+
size.times { |i| self[i] = nil }
|
114
|
+
true
|
115
|
+
end
|
116
|
+
|
117
|
+
# Checks token attribute presence
|
118
|
+
# Example:
|
119
|
+
# token.present?
|
120
|
+
# => true
|
121
|
+
def present?
|
122
|
+
token.present?
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
data/lib/devise_token_auth.rb
CHANGED
@@ -1,11 +1,14 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require 'devise'
|
4
|
+
|
5
|
+
module DeviseTokenAuth
|
6
|
+
end
|
7
|
+
|
4
8
|
require 'devise_token_auth/engine'
|
5
9
|
require 'devise_token_auth/controllers/helpers'
|
6
10
|
require 'devise_token_auth/controllers/url_helpers'
|
7
11
|
require 'devise_token_auth/url'
|
8
12
|
require 'devise_token_auth/errors'
|
9
|
-
|
10
|
-
|
11
|
-
end
|
13
|
+
require 'devise_token_auth/blacklist'
|
14
|
+
require 'devise_token_auth/token_factory'
|
@@ -1,20 +1,14 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require_relative 'install_generator_helpers'
|
4
|
+
|
3
5
|
module DeviseTokenAuth
|
4
6
|
class InstallGenerator < Rails::Generators::Base
|
5
7
|
include Rails::Generators::Migration
|
8
|
+
include DeviseTokenAuth::InstallGeneratorHelpers
|
6
9
|
|
7
10
|
class_option :primary_key_type, type: :string, desc: 'The type for primary key'
|
8
11
|
|
9
|
-
source_root File.expand_path('templates', __dir__)
|
10
|
-
|
11
|
-
argument :user_class, type: :string, default: 'User'
|
12
|
-
argument :mount_path, type: :string, default: 'auth'
|
13
|
-
|
14
|
-
def create_initializer_file
|
15
|
-
copy_file('devise_token_auth.rb', 'config/initializers/devise_token_auth.rb')
|
16
|
-
end
|
17
|
-
|
18
12
|
def copy_migrations
|
19
13
|
if self.class.migration_exists?('db/migrate', "devise_token_auth_create_#{user_class.pluralize.gsub('::','').underscore}")
|
20
14
|
say_status('skipped', "Migration 'devise_token_auth_create_#{user_class.pluralize.gsub('::','').underscore}' already exists")
|
@@ -47,90 +41,12 @@ module DeviseTokenAuth
|
|
47
41
|
end
|
48
42
|
end
|
49
43
|
|
50
|
-
def include_controller_concerns
|
51
|
-
fname = 'app/controllers/application_controller.rb'
|
52
|
-
line = 'include DeviseTokenAuth::Concerns::SetUserByToken'
|
53
|
-
|
54
|
-
if File.exist?(File.join(destination_root, fname))
|
55
|
-
if parse_file_for_line(fname, line)
|
56
|
-
say_status('skipped', 'Concern is already included in the application controller.')
|
57
|
-
elsif is_rails_api?
|
58
|
-
inject_into_file fname, after: "class ApplicationController < ActionController::API\n" do <<-'RUBY'
|
59
|
-
include DeviseTokenAuth::Concerns::SetUserByToken
|
60
|
-
RUBY
|
61
|
-
end
|
62
|
-
else
|
63
|
-
inject_into_file fname, after: "class ApplicationController < ActionController::Base\n" do <<-'RUBY'
|
64
|
-
include DeviseTokenAuth::Concerns::SetUserByToken
|
65
|
-
RUBY
|
66
|
-
end
|
67
|
-
end
|
68
|
-
else
|
69
|
-
say_status('skipped', "app/controllers/application_controller.rb not found. Add 'include DeviseTokenAuth::Concerns::SetUserByToken' to any controllers that require authentication.")
|
70
|
-
end
|
71
|
-
end
|
72
|
-
|
73
|
-
def add_route_mount
|
74
|
-
f = 'config/routes.rb'
|
75
|
-
str = "mount_devise_token_auth_for '#{user_class}', at: '#{mount_path}'"
|
76
|
-
|
77
|
-
if File.exist?(File.join(destination_root, f))
|
78
|
-
line = parse_file_for_line(f, 'mount_devise_token_auth_for')
|
79
|
-
|
80
|
-
if line
|
81
|
-
existing_user_class = true
|
82
|
-
else
|
83
|
-
line = 'Rails.application.routes.draw do'
|
84
|
-
existing_user_class = false
|
85
|
-
end
|
86
|
-
|
87
|
-
if parse_file_for_line(f, str)
|
88
|
-
say_status('skipped', "Routes already exist for #{user_class} at #{mount_path}")
|
89
|
-
else
|
90
|
-
insert_after_line(f, line, str)
|
91
|
-
|
92
|
-
if existing_user_class
|
93
|
-
scoped_routes = ''\
|
94
|
-
"as :#{user_class.underscore} do\n"\
|
95
|
-
" # Define routes for #{user_class} within this block.\n"\
|
96
|
-
" end\n"
|
97
|
-
insert_after_line(f, str, scoped_routes)
|
98
|
-
end
|
99
|
-
end
|
100
|
-
else
|
101
|
-
say_status('skipped', "config/routes.rb not found. Add \"mount_devise_token_auth_for '#{user_class}', at: '#{mount_path}'\" to your routes file.")
|
102
|
-
end
|
103
|
-
end
|
104
|
-
|
105
44
|
private
|
106
45
|
|
107
46
|
def self.next_migration_number(path)
|
108
47
|
Time.zone.now.utc.strftime('%Y%m%d%H%M%S')
|
109
48
|
end
|
110
49
|
|
111
|
-
def insert_after_line(filename, line, str)
|
112
|
-
gsub_file filename, /(#{Regexp.escape(line)})/mi do |match|
|
113
|
-
"#{match}\n #{str}"
|
114
|
-
end
|
115
|
-
end
|
116
|
-
|
117
|
-
def parse_file_for_line(filename, str)
|
118
|
-
match = false
|
119
|
-
|
120
|
-
File.open(File.join(destination_root, filename)) do |f|
|
121
|
-
f.each_line do |line|
|
122
|
-
match = line if line =~ /(#{Regexp.escape(str)})/mi
|
123
|
-
end
|
124
|
-
end
|
125
|
-
match
|
126
|
-
end
|
127
|
-
|
128
|
-
def is_rails_api?
|
129
|
-
fname = 'app/controllers/application_controller.rb'
|
130
|
-
line = 'class ApplicationController < ActionController::API'
|
131
|
-
parse_file_for_line(fname, line)
|
132
|
-
end
|
133
|
-
|
134
50
|
def json_supported_database?
|
135
51
|
(postgres? && postgres_correct_version?) || (mysql? && mysql_correct_version?)
|
136
52
|
end
|
@@ -0,0 +1,98 @@
|
|
1
|
+
module DeviseTokenAuth
|
2
|
+
module InstallGeneratorHelpers
|
3
|
+
class << self
|
4
|
+
def included(mod)
|
5
|
+
mod.class_eval do
|
6
|
+
source_root File.expand_path('templates', __dir__)
|
7
|
+
|
8
|
+
argument :user_class, type: :string, default: 'User'
|
9
|
+
argument :mount_path, type: :string, default: 'auth'
|
10
|
+
|
11
|
+
def create_initializer_file
|
12
|
+
copy_file('devise_token_auth.rb', 'config/initializers/devise_token_auth.rb')
|
13
|
+
end
|
14
|
+
|
15
|
+
def include_controller_concerns
|
16
|
+
fname = 'app/controllers/application_controller.rb'
|
17
|
+
line = 'include DeviseTokenAuth::Concerns::SetUserByToken'
|
18
|
+
|
19
|
+
if File.exist?(File.join(destination_root, fname))
|
20
|
+
if parse_file_for_line(fname, line)
|
21
|
+
say_status('skipped', 'Concern is already included in the application controller.')
|
22
|
+
elsif is_rails_api?
|
23
|
+
inject_into_file fname, after: "class ApplicationController < ActionController::API\n" do <<-'RUBY'
|
24
|
+
include DeviseTokenAuth::Concerns::SetUserByToken
|
25
|
+
RUBY
|
26
|
+
end
|
27
|
+
else
|
28
|
+
inject_into_file fname, after: "class ApplicationController < ActionController::Base\n" do <<-'RUBY'
|
29
|
+
include DeviseTokenAuth::Concerns::SetUserByToken
|
30
|
+
RUBY
|
31
|
+
end
|
32
|
+
end
|
33
|
+
else
|
34
|
+
say_status('skipped', "app/controllers/application_controller.rb not found. Add 'include DeviseTokenAuth::Concerns::SetUserByToken' to any controllers that require authentication.")
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def add_route_mount
|
39
|
+
f = 'config/routes.rb'
|
40
|
+
str = "mount_devise_token_auth_for '#{user_class}', at: '#{mount_path}'"
|
41
|
+
|
42
|
+
if File.exist?(File.join(destination_root, f))
|
43
|
+
line = parse_file_for_line(f, 'mount_devise_token_auth_for')
|
44
|
+
|
45
|
+
if line
|
46
|
+
existing_user_class = true
|
47
|
+
else
|
48
|
+
line = 'Rails.application.routes.draw do'
|
49
|
+
existing_user_class = false
|
50
|
+
end
|
51
|
+
|
52
|
+
if parse_file_for_line(f, str)
|
53
|
+
say_status('skipped', "Routes already exist for #{user_class} at #{mount_path}")
|
54
|
+
else
|
55
|
+
insert_after_line(f, line, str)
|
56
|
+
|
57
|
+
if existing_user_class
|
58
|
+
scoped_routes = ''\
|
59
|
+
"as :#{user_class.underscore} do\n"\
|
60
|
+
" # Define routes for #{user_class} within this block.\n"\
|
61
|
+
" end\n"
|
62
|
+
insert_after_line(f, str, scoped_routes)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
else
|
66
|
+
say_status('skipped', "config/routes.rb not found. Add \"mount_devise_token_auth_for '#{user_class}', at: '#{mount_path}'\" to your routes file.")
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
private
|
71
|
+
|
72
|
+
def insert_after_line(filename, line, str)
|
73
|
+
gsub_file filename, /(#{Regexp.escape(line)})/mi do |match|
|
74
|
+
"#{match}\n #{str}"
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
def parse_file_for_line(filename, str)
|
79
|
+
match = false
|
80
|
+
|
81
|
+
File.open(File.join(destination_root, filename)) do |f|
|
82
|
+
f.each_line do |line|
|
83
|
+
match = line if line =~ /(#{Regexp.escape(str)})/mi
|
84
|
+
end
|
85
|
+
end
|
86
|
+
match
|
87
|
+
end
|
88
|
+
|
89
|
+
def is_rails_api?
|
90
|
+
fname = 'app/controllers/application_controller.rb'
|
91
|
+
line = 'class ApplicationController < ActionController::API'
|
92
|
+
parse_file_for_line(fname, line)
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'install_generator_helpers'
|
4
|
+
|
5
|
+
module DeviseTokenAuth
|
6
|
+
class InstallMongoidGenerator < Rails::Generators::Base
|
7
|
+
include DeviseTokenAuth::InstallGeneratorHelpers
|
8
|
+
|
9
|
+
def create_user_model
|
10
|
+
fname = "app/models/#{user_class.underscore}.rb"
|
11
|
+
if File.exist?(File.join(destination_root, fname))
|
12
|
+
inclusion = 'include DeviseTokenAuth::Concerns::User'
|
13
|
+
unless parse_file_for_line(fname, inclusion)
|
14
|
+
inject_into_file fname, before: /end\s\z/ do <<-'RUBY'
|
15
|
+
|
16
|
+
include Mongoid::Locker
|
17
|
+
|
18
|
+
field :locker_locked_at, type: Time
|
19
|
+
field :locker_locked_until, type: Time
|
20
|
+
|
21
|
+
locker locked_at_field: :locker_locked_at,
|
22
|
+
locked_until_field: :locker_locked_until
|
23
|
+
|
24
|
+
## Required
|
25
|
+
field :provider, type: String
|
26
|
+
field :uid, type: String, default: ''
|
27
|
+
|
28
|
+
## Tokens
|
29
|
+
field :tokens, type: Hash, default: {}
|
30
|
+
|
31
|
+
# Include default devise modules. Others available are:
|
32
|
+
# :confirmable, :lockable, :timeoutable and :omniauthable
|
33
|
+
devise :database_authenticatable, :registerable,
|
34
|
+
:recoverable, :rememberable, :trackable, :validatable
|
35
|
+
include DeviseTokenAuth::Concerns::User
|
36
|
+
|
37
|
+
index({ uid: 1, provider: 1}, { name: 'uid_provider_index', unique: true, background: true })
|
38
|
+
RUBY
|
39
|
+
end
|
40
|
+
end
|
41
|
+
else
|
42
|
+
template('user_mongoid.rb.erb', fname)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -11,6 +11,11 @@ DeviseTokenAuth.setup do |config|
|
|
11
11
|
# determines how long tokens will remain valid after they are issued.
|
12
12
|
# config.token_lifespan = 2.weeks
|
13
13
|
|
14
|
+
# Limiting the token_cost to just 4 in testing will increase the performance of
|
15
|
+
# your test suite dramatically. The possible cost value is within range from 4
|
16
|
+
# to 31. It is recommended to not use a value more than 10 in other environments.
|
17
|
+
config.token_cost = Rails.env.test? ? 4 : 10
|
18
|
+
|
14
19
|
# Sets the max number of concurrent devices per user, which is 10 by default.
|
15
20
|
# After this limit is reached, the oldest tokens will be removed.
|
16
21
|
# config.max_number_of_devices = 10
|
@@ -17,13 +17,6 @@ class DeviseTokenAuthCreate<%= user_class.pluralize.gsub("::","") %> < ActiveRec
|
|
17
17
|
## Rememberable
|
18
18
|
t.datetime :remember_created_at
|
19
19
|
|
20
|
-
## Trackable
|
21
|
-
t.integer :sign_in_count, :default => 0, :null => false
|
22
|
-
t.datetime :current_sign_in_at
|
23
|
-
t.datetime :last_sign_in_at
|
24
|
-
t.string :current_sign_in_ip
|
25
|
-
t.string :last_sign_in_ip
|
26
|
-
|
27
20
|
## Confirmable
|
28
21
|
t.string :confirmation_token
|
29
22
|
t.datetime :confirmed_at
|
@@ -0,0 +1,56 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class <%= user_class %>
|
4
|
+
include Mongoid::Document
|
5
|
+
include Mongoid::Timestamps
|
6
|
+
include Mongoid::Locker
|
7
|
+
|
8
|
+
field :locker_locked_at, type: Time
|
9
|
+
field :locker_locked_until, type: Time
|
10
|
+
|
11
|
+
locker locked_at_field: :locker_locked_at,
|
12
|
+
locked_until_field: :locker_locked_until
|
13
|
+
|
14
|
+
## Database authenticatable
|
15
|
+
field :email, type: String, default: ''
|
16
|
+
field :encrypted_password, type: String, default: ''
|
17
|
+
|
18
|
+
## Recoverable
|
19
|
+
field :reset_password_token, type: String
|
20
|
+
field :reset_password_sent_at, type: Time
|
21
|
+
field :reset_password_redirect_url, type: String
|
22
|
+
field :allow_password_change, type: Boolean, default: false
|
23
|
+
|
24
|
+
## Rememberable
|
25
|
+
field :remember_created_at, type: Time
|
26
|
+
|
27
|
+
## Confirmable
|
28
|
+
field :confirmation_token, type: String
|
29
|
+
field :confirmed_at, type: Time
|
30
|
+
field :confirmation_sent_at, type: Time
|
31
|
+
field :unconfirmed_email, type: String # Only if using reconfirmable
|
32
|
+
|
33
|
+
## Lockable
|
34
|
+
# field :failed_attempts, type: Integer, default: 0 # Only if lock strategy is :failed_attempts
|
35
|
+
# field :unlock_token, type: String # Only if unlock strategy is :email or :both
|
36
|
+
# field :locked_at, type: Time
|
37
|
+
|
38
|
+
## Required
|
39
|
+
field :provider, type: String
|
40
|
+
field :uid, type: String, default: ''
|
41
|
+
|
42
|
+
## Tokens
|
43
|
+
field :tokens, type: Hash, default: {}
|
44
|
+
|
45
|
+
# Include default devise modules. Others available are:
|
46
|
+
# :confirmable, :lockable, :timeoutable and :omniauthable
|
47
|
+
devise :database_authenticatable, :registerable,
|
48
|
+
:recoverable, :rememberable, :trackable, :validatable
|
49
|
+
include DeviseTokenAuth::Concerns::User
|
50
|
+
|
51
|
+
index({ email: 1 }, { name: 'email_index', unique: true, background: true })
|
52
|
+
index({ reset_password_token: 1 }, { name: 'reset_password_token_index', unique: true, sparse: true, background: true })
|
53
|
+
index({ confirmation_token: 1 }, { name: 'confirmation_token_index', unique: true, sparse: true, background: true })
|
54
|
+
index({ uid: 1, provider: 1}, { name: 'uid_provider_index', unique: true, background: true })
|
55
|
+
# index({ unlock_token: 1 }, { name: 'unlock_token_index', unique: true, sparse: true, background: true })
|
56
|
+
end
|
@@ -321,8 +321,8 @@ class DemoUserControllerTest < ActionDispatch::IntegrationTest
|
|
321
321
|
assert @resource.tokens.count > 1
|
322
322
|
|
323
323
|
# password changed from new device
|
324
|
-
@resource.
|
325
|
-
|
324
|
+
@resource.update(password: 'newsecret123',
|
325
|
+
password_confirmation: 'newsecret123')
|
326
326
|
|
327
327
|
get '/demo/members_only',
|
328
328
|
params: {},
|
@@ -23,6 +23,7 @@ class DeviseTokenAuth::ConfirmationsControllerTest < ActionController::TestCase
|
|
23
23
|
@new_user.send_confirmation_instructions(redirect_url: @redirect_url)
|
24
24
|
mail = ActionMailer::Base.deliveries.last
|
25
25
|
@token, @client_config = token_and_client_config_from(mail.body)
|
26
|
+
@token_params = %w[access-token client client_id config expiry token uid]
|
26
27
|
end
|
27
28
|
|
28
29
|
test 'should generate raw token' do
|
@@ -38,32 +39,79 @@ class DeviseTokenAuth::ConfirmationsControllerTest < ActionController::TestCase
|
|
38
39
|
end
|
39
40
|
|
40
41
|
describe 'success' do
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
42
|
+
describe 'when authenticated' do
|
43
|
+
before do
|
44
|
+
sign_in(@new_user)
|
45
|
+
get :show,
|
46
|
+
params: { confirmation_token: @token,
|
47
|
+
redirect_url: @redirect_url },
|
48
|
+
xhr: true
|
49
|
+
@resource = assigns(:resource)
|
50
|
+
end
|
48
51
|
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
+
test 'user should now be confirmed' do
|
53
|
+
assert @resource.confirmed?
|
54
|
+
end
|
52
55
|
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
+
test 'should redirect to success url' do
|
57
|
+
assert_redirected_to(/^#{@redirect_url}/)
|
58
|
+
end
|
56
59
|
|
57
|
-
|
58
|
-
|
60
|
+
test 'redirect url includes token params' do
|
61
|
+
assert @token_params.all? { |param| response.body.include?(param) }
|
62
|
+
assert response.body.include?('account_confirmation_success')
|
63
|
+
end
|
59
64
|
end
|
60
65
|
|
61
|
-
|
62
|
-
|
66
|
+
describe 'when unauthenticated' do
|
67
|
+
before do
|
68
|
+
sign_out(@new_user)
|
69
|
+
get :show,
|
70
|
+
params: { confirmation_token: @token,
|
71
|
+
redirect_url: @redirect_url },
|
72
|
+
xhr: true
|
73
|
+
@resource = assigns(:resource)
|
74
|
+
end
|
75
|
+
|
76
|
+
test 'user should now be confirmed' do
|
77
|
+
assert @resource.confirmed?
|
78
|
+
end
|
79
|
+
|
80
|
+
test 'should redirect to success url' do
|
81
|
+
assert_redirected_to(/^#{@redirect_url}/)
|
82
|
+
end
|
83
|
+
|
84
|
+
test 'redirect url does not include token params' do
|
85
|
+
refute @token_params.any? { |param| response.body.include?(param) }
|
86
|
+
assert response.body.include?('account_confirmation_success')
|
87
|
+
end
|
63
88
|
end
|
64
89
|
|
65
|
-
|
66
|
-
|
90
|
+
describe 'resend confirmation' do
|
91
|
+
before do
|
92
|
+
post :create,
|
93
|
+
params: { email: @new_user.email,
|
94
|
+
redirect_url: @redirect_url },
|
95
|
+
xhr: true
|
96
|
+
@resource = assigns(:resource)
|
97
|
+
|
98
|
+
@mail = ActionMailer::Base.deliveries.last
|
99
|
+
@token, @client_config = token_and_client_config_from(@mail.body)
|
100
|
+
end
|
101
|
+
|
102
|
+
test 'user should not be confirmed' do
|
103
|
+
assert_nil @resource.confirmed_at
|
104
|
+
end
|
105
|
+
|
106
|
+
test 'should generate raw token' do
|
107
|
+
assert @token
|
108
|
+
assert_equal @new_user.confirmation_token, @token
|
109
|
+
end
|
110
|
+
|
111
|
+
test 'user should receive confirmation email' do
|
112
|
+
assert_equal @resource.email, @mail['to'].to_s
|
113
|
+
end
|
114
|
+
|
67
115
|
end
|
68
116
|
end
|
69
117
|
|
@@ -75,6 +123,18 @@ class DeviseTokenAuth::ConfirmationsControllerTest < ActionController::TestCase
|
|
75
123
|
@resource = assigns(:resource)
|
76
124
|
refute @resource.confirmed?
|
77
125
|
end
|
126
|
+
|
127
|
+
test 'request resend confirmation without email' do
|
128
|
+
post :create, params: { email: nil }, xhr: true
|
129
|
+
|
130
|
+
assert_equal 401, response.status
|
131
|
+
end
|
132
|
+
|
133
|
+
test 'user should not be found on resend confirmation request' do
|
134
|
+
post :create, params: { email: 'bogus' }, xhr: true
|
135
|
+
|
136
|
+
assert_equal 404, response.status
|
137
|
+
end
|
78
138
|
end
|
79
139
|
end
|
80
140
|
|
@@ -155,6 +155,8 @@ class OmniauthTest < ActionDispatch::IntegrationTest
|
|
155
155
|
describe 'with new user' do
|
156
156
|
before do
|
157
157
|
User.any_instance.expects(:new_record?).returns(true).at_least_once
|
158
|
+
# https://docs.mongodb.com/mongoid/master/tutorials/mongoid-documents/#notes-on-persistence
|
159
|
+
User.any_instance.expects(:save!).returns(true)
|
158
160
|
end
|
159
161
|
|
160
162
|
test 'response contains oauth_registration attr' do
|