devise-tokens 1.0.0 → 1.0.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.
- checksums.yaml +4 -4
- data/app/controllers/devise_tokens/application_controller.rb +77 -0
- data/app/controllers/devise_tokens/concerns/resource_finder.rb +42 -0
- data/app/controllers/devise_tokens/concerns/set_user_by_token.rb +160 -0
- data/app/controllers/devise_tokens/confirmations_controller.rb +79 -0
- data/app/controllers/devise_tokens/omniauth_callbacks_controller.rb +284 -0
- data/app/controllers/devise_tokens/passwords_controller.rb +204 -0
- data/app/controllers/devise_tokens/registrations_controller.rb +203 -0
- data/app/controllers/devise_tokens/sessions_controller.rb +128 -0
- data/app/controllers/devise_tokens/token_validations_controller.rb +29 -0
- data/app/controllers/devise_tokens/unlocks_controller.rb +87 -0
- 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 +253 -0
- data/app/models/devise_token_auth/concerns/user_omniauth_callbacks.rb +28 -0
- data/app/validators/devise_token_auth_email_validator.rb +23 -0
- data/app/views/devise/mailer/confirmation_instructions.html.erb +5 -0
- data/app/views/devise/mailer/reset_password_instructions.html.erb +8 -0
- data/app/views/devise/mailer/unlock_instructions.html.erb +7 -0
- data/app/views/devise_token_auth/omniauth_external_window.html.erb +38 -0
- data/config/locales/da-DK.yml +52 -0
- data/config/locales/de.yml +51 -0
- data/config/locales/en.yml +57 -0
- data/config/locales/es.yml +51 -0
- data/config/locales/fr.yml +51 -0
- data/config/locales/he.yml +52 -0
- data/config/locales/it.yml +48 -0
- data/config/locales/ja.yml +48 -0
- data/config/locales/nl.yml +32 -0
- data/config/locales/pl.yml +50 -0
- data/config/locales/pt-BR.yml +48 -0
- data/config/locales/pt.yml +50 -0
- data/config/locales/ro.yml +48 -0
- data/config/locales/ru.yml +52 -0
- data/config/locales/sq.yml +48 -0
- data/config/locales/sv.yml +52 -0
- data/config/locales/uk.yml +61 -0
- data/config/locales/vi.yml +52 -0
- data/config/locales/zh-CN.yml +48 -0
- data/config/locales/zh-HK.yml +50 -0
- data/config/locales/zh-TW.yml +50 -0
- data/lib/devise_tokens.rb +14 -0
- data/lib/devise_tokens/blacklist.rb +2 -0
- data/lib/devise_tokens/controllers/helpers.rb +161 -0
- data/lib/devise_tokens/controllers/url_helpers.rb +10 -0
- data/lib/devise_tokens/engine.rb +92 -0
- data/lib/devise_tokens/errors.rb +6 -0
- data/lib/devise_tokens/rails/routes.rb +116 -0
- data/lib/devise_tokens/token_factory.rb +126 -0
- data/lib/devise_tokens/url.rb +39 -0
- data/lib/devise_tokens/version.rb +3 -0
- data/lib/generators/devise_tokens/USAGE +31 -0
- data/lib/generators/devise_tokens/install_generator.rb +91 -0
- data/lib/generators/devise_tokens/install_generator_helpers.rb +98 -0
- data/lib/generators/devise_tokens/install_mongoid_generator.rb +46 -0
- data/lib/generators/devise_tokens/install_views_generator.rb +18 -0
- data/lib/generators/devise_tokens/templates/devise_tokens.rb +55 -0
- data/lib/generators/devise_tokens/templates/devise_tokens_create_users.rb.erb +49 -0
- data/lib/generators/devise_tokens/templates/user.rb.erb +9 -0
- data/lib/generators/devise_tokens/templates/user_mongoid.rb.erb +56 -0
- data/lib/tasks/devise_tokens_tasks.rake +6 -0
- metadata +208 -4
- data/lib/devise-tokens.rb +0 -5
@@ -0,0 +1,116 @@
|
|
1
|
+
|
2
|
+
|
3
|
+
module ActionDispatch::Routing
|
4
|
+
class Mapper
|
5
|
+
def mount_devise_tokens_for(resource, opts)
|
6
|
+
# ensure objects exist to simplify attr checks
|
7
|
+
opts[:controllers] ||= {}
|
8
|
+
opts[:skip] ||= []
|
9
|
+
|
10
|
+
# check for ctrl overrides, fall back to defaults
|
11
|
+
sessions_ctrl = opts[:controllers][:sessions] || 'devise_tokens/sessions'
|
12
|
+
registrations_ctrl = opts[:controllers][:registrations] || 'devise_tokens/registrations'
|
13
|
+
passwords_ctrl = opts[:controllers][:passwords] || 'devise_tokens/passwords'
|
14
|
+
confirmations_ctrl = opts[:controllers][:confirmations] || 'devise_tokens/confirmations'
|
15
|
+
token_validations_ctrl = opts[:controllers][:token_validations] || 'devise_tokens/token_validations'
|
16
|
+
omniauth_ctrl = opts[:controllers][:omniauth_callbacks] || 'devise_tokens/omniauth_callbacks'
|
17
|
+
unlocks_ctrl = opts[:controllers][:unlocks] || 'devise_tokens/unlocks'
|
18
|
+
|
19
|
+
# define devise controller mappings
|
20
|
+
controllers = { sessions: sessions_ctrl,
|
21
|
+
registrations: registrations_ctrl,
|
22
|
+
passwords: passwords_ctrl,
|
23
|
+
confirmations: confirmations_ctrl }
|
24
|
+
|
25
|
+
controllers[:unlocks] = unlocks_ctrl if unlocks_ctrl
|
26
|
+
|
27
|
+
# remove any unwanted devise modules
|
28
|
+
opts[:skip].each{ |item| controllers.delete(item) }
|
29
|
+
|
30
|
+
devise_for resource.pluralize.underscore.gsub('/', '_').to_sym,
|
31
|
+
class_name: resource,
|
32
|
+
module: :devise,
|
33
|
+
path: opts[:at].to_s,
|
34
|
+
controllers: controllers,
|
35
|
+
skip: opts[:skip] + [:omniauth_callbacks]
|
36
|
+
|
37
|
+
unnest_namespace do
|
38
|
+
# get full url path as if it were namespaced
|
39
|
+
full_path = "#{@scope[:path]}/#{opts[:at]}"
|
40
|
+
|
41
|
+
# get namespace name
|
42
|
+
namespace_name = @scope[:as]
|
43
|
+
|
44
|
+
# clear scope so controller routes aren't namespaced
|
45
|
+
@scope = ActionDispatch::Routing::Mapper::Scope.new(
|
46
|
+
path: '',
|
47
|
+
shallow_path: '',
|
48
|
+
constraints: {},
|
49
|
+
defaults: {},
|
50
|
+
options: {},
|
51
|
+
parent: nil
|
52
|
+
)
|
53
|
+
|
54
|
+
mapping_name = resource.underscore.gsub('/', '_')
|
55
|
+
mapping_name = "#{namespace_name}_#{mapping_name}" if namespace_name
|
56
|
+
|
57
|
+
devise_scope mapping_name.to_sym do
|
58
|
+
# path to verify token validity
|
59
|
+
get "#{full_path}/validate_token", controller: token_validations_ctrl.to_s, action: 'validate_token' if !opts[:skip].include?(:token_validations)
|
60
|
+
|
61
|
+
# omniauth routes. only define if omniauth is installed and not skipped.
|
62
|
+
if defined?(::OmniAuth) && !opts[:skip].include?(:omniauth_callbacks)
|
63
|
+
match "#{full_path}/failure", controller: omniauth_ctrl, action: 'omniauth_failure', via: [:get]
|
64
|
+
match "#{full_path}/:provider/callback", controller: omniauth_ctrl, action: 'omniauth_success', via: [:get]
|
65
|
+
|
66
|
+
match "#{DeviseTokens.omniauth_prefix}/:provider/callback", controller: omniauth_ctrl, action: 'redirect_callbacks', via: [:get, :post]
|
67
|
+
match "#{DeviseTokens.omniauth_prefix}/failure", controller: omniauth_ctrl, action: 'omniauth_failure', via: [:get, :post]
|
68
|
+
|
69
|
+
# preserve the resource class thru oauth authentication by setting name of
|
70
|
+
# resource as "resource_class" param
|
71
|
+
match "#{full_path}/:provider", to: redirect{ |params, request|
|
72
|
+
# get the current querystring
|
73
|
+
qs = CGI::parse(request.env['QUERY_STRING'])
|
74
|
+
|
75
|
+
# append name of current resource
|
76
|
+
qs['resource_class'] = [resource]
|
77
|
+
qs['namespace_name'] = [namespace_name] if namespace_name
|
78
|
+
|
79
|
+
set_omniauth_path_prefix!(DeviseTokens.omniauth_prefix)
|
80
|
+
|
81
|
+
redirect_params = {}.tap { |hash| qs.each{ |k, v| hash[k] = v.first } }
|
82
|
+
|
83
|
+
if DeviseTokens.redirect_whitelist
|
84
|
+
redirect_url = request.params['auth_origin_url']
|
85
|
+
unless DeviseTokens::Url.whitelisted?(redirect_url)
|
86
|
+
message = I18n.t(
|
87
|
+
'devise_tokens.registrations.redirect_url_not_allowed',
|
88
|
+
redirect_url: redirect_url
|
89
|
+
)
|
90
|
+
redirect_params['message'] = message
|
91
|
+
next "#{::OmniAuth.config.path_prefix}/failure?#{redirect_params.to_param}"
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
# re-construct the path for omniauth
|
96
|
+
"#{::OmniAuth.config.path_prefix}/#{params[:provider]}?#{redirect_params.to_param}"
|
97
|
+
}, via: [:get]
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
# this allows us to use namespaced paths without namespacing the routes
|
104
|
+
def unnest_namespace
|
105
|
+
current_scope = @scope.dup
|
106
|
+
yield
|
107
|
+
ensure
|
108
|
+
@scope = current_scope
|
109
|
+
end
|
110
|
+
|
111
|
+
# ignore error about omniauth/multiple model support
|
112
|
+
def set_omniauth_path_prefix!(path_prefix)
|
113
|
+
::OmniAuth.config.path_prefix = path_prefix
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
@@ -0,0 +1,126 @@
|
|
1
|
+
require 'bcrypt'
|
2
|
+
|
3
|
+
module DeviseTokens
|
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
|
+
# DeviseTokens::TokenFactory.create
|
12
|
+
# => #<struct DeviseTokens::TokenFactory::Token client="tElcgkdZ7f9XEa0unZhrYQ", token="rAMcWOs0-mGHFMnIgJD2cA", token_hash="$2a$10$wrsdlHVRGlYW11wfImxU..jr0Ux3bHo/qbXcSfgp8zmvVUNHosita", expiry=1518982690>
|
13
|
+
#
|
14
|
+
# DeviseTokens::TokenFactory.create(lifespan: 10, cost: 4)
|
15
|
+
# => #<struct DeviseTokens::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
|
+
# DeviseTokens::TokenFactory.client
|
29
|
+
# => "zNf0pNP5iGfuBItZJGCseQ"
|
30
|
+
def self.client
|
31
|
+
secure_string
|
32
|
+
end
|
33
|
+
|
34
|
+
# Generates a random URL-safe token.
|
35
|
+
# Example:
|
36
|
+
# DeviseTokens::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
|
+
# DeviseTokens::TokenFactory.token_hash("_qxAxmc-biQLiYRHsmwd5Q")
|
47
|
+
# => "$2a$10$6/cTAtQ3CBLfpkeHW7dlt.PD2aVCbFRN5vDDJUUhGsZ6pzYFlh4Me"
|
48
|
+
#
|
49
|
+
# DeviseTokens::TokenFactory.token_hash("_qxAxmc-biQLiYRHsmwd5Q", 4)
|
50
|
+
# => "$2a$04$RkIrosbdRtuet2eUk3si8eS4ufeNpiPc/rSSsfpniRK8ogM5YFOWS"
|
51
|
+
def self.token_hash(token, cost = nil)
|
52
|
+
cost ||= DeviseTokens.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
|
+
# DeviseTokens::TokenFactory.expiry
|
59
|
+
# => 1518983359
|
60
|
+
# DeviseTokens::TokenFactory.expiry(10)
|
61
|
+
# => 1517773781
|
62
|
+
def self.expiry(lifespan = nil)
|
63
|
+
lifespan ||= DeviseTokens.token_lifespan
|
64
|
+
(Time.zone.now + lifespan).to_i
|
65
|
+
end
|
66
|
+
|
67
|
+
# Generates a random URL-safe string.
|
68
|
+
# Example:
|
69
|
+
# DeviseTokens::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
|
+
# DeviseTokens::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
|
+
# DeviseTokens::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
|
+
# DeviseTokens::TokenFactory.new
|
100
|
+
# => #<struct DeviseTokens::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 DeviseTokens::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
|
@@ -0,0 +1,39 @@
|
|
1
|
+
module DeviseTokens::Url
|
2
|
+
|
3
|
+
def self.generate(url, params = {})
|
4
|
+
uri = URI(url)
|
5
|
+
|
6
|
+
res = "#{uri.scheme}://#{uri.host}"
|
7
|
+
res += ":#{uri.port}" if (uri.port && uri.port != 80 && uri.port != 443)
|
8
|
+
res += uri.path.to_s if uri.path
|
9
|
+
query = [uri.query, params.to_query].reject(&:blank?).join('&')
|
10
|
+
res += "?#{query}"
|
11
|
+
res += "##{uri.fragment}" if uri.fragment
|
12
|
+
|
13
|
+
res
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.whitelisted?(url)
|
17
|
+
url.nil? || \
|
18
|
+
!!DeviseTokens.redirect_whitelist.find do |pattern|
|
19
|
+
!!Wildcat.new(pattern).match(url)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
# wildcard convenience class
|
24
|
+
class Wildcat
|
25
|
+
def self.parse_to_regex(str)
|
26
|
+
escaped = Regexp.escape(str).gsub('\*','.*?')
|
27
|
+
Regexp.new("^#{escaped}$", Regexp::IGNORECASE)
|
28
|
+
end
|
29
|
+
|
30
|
+
def initialize(str)
|
31
|
+
@regex = self.class.parse_to_regex(str)
|
32
|
+
end
|
33
|
+
|
34
|
+
def match(str)
|
35
|
+
!!@regex.match(str)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
Description:
|
2
|
+
This generator will install all the necessary configuration and migration
|
3
|
+
files for the devise_tokens gem. See
|
4
|
+
https://github.com/lynndylanhurley/devise_tokens for more information.
|
5
|
+
|
6
|
+
Arguments:
|
7
|
+
USER_CLASS # The name of the class to use for user authentication. Default is
|
8
|
+
# 'User'
|
9
|
+
MOUNT_PATH # The path at which to mount the authentication routes. Default is
|
10
|
+
# 'auth'. More detail documentation is here:
|
11
|
+
# https://github.com/lynndylanhurley/devise_tokens#usage-tldr
|
12
|
+
|
13
|
+
Example:
|
14
|
+
rails generate devise_tokens:install User auth
|
15
|
+
|
16
|
+
This will create:
|
17
|
+
config/initializers/devise_tokens.rb
|
18
|
+
db/migrate/<%= Time.zone.now.utc.strftime("%Y%m%d%H%M%S") %>_create_devise_tokens_create_users.rb
|
19
|
+
app/models/user.rb
|
20
|
+
|
21
|
+
If 'app/models/user.rb' already exists, the following line will be inserted
|
22
|
+
after the class definition:
|
23
|
+
include DeviseTokens::Concerns::User
|
24
|
+
|
25
|
+
The following line will be inserted into your application controller at
|
26
|
+
app/controllers/application_controller.rb:
|
27
|
+
include DeviseTokens::Concerns::SetUserByToken
|
28
|
+
|
29
|
+
The following line will be inserted at the top of 'config/routes.rb' if it
|
30
|
+
does not already exist:
|
31
|
+
mount_devise_tokens_for "User", at: 'auth'
|
@@ -0,0 +1,91 @@
|
|
1
|
+
|
2
|
+
|
3
|
+
require_relative 'install_generator_helpers'
|
4
|
+
|
5
|
+
module DeviseTokens
|
6
|
+
class InstallGenerator < Rails::Generators::Base
|
7
|
+
include Rails::Generators::Migration
|
8
|
+
include DeviseTokens::InstallGeneratorHelpers
|
9
|
+
|
10
|
+
class_option :primary_key_type, type: :string, desc: 'The type for primary key'
|
11
|
+
|
12
|
+
def copy_migrations
|
13
|
+
if self.class.migration_exists?('db/migrate', "devise_tokens_create_#{user_class.pluralize.gsub('::','').underscore}")
|
14
|
+
say_status('skipped', "Migration 'devise_tokens_create_#{user_class.pluralize.gsub('::','').underscore}' already exists")
|
15
|
+
else
|
16
|
+
migration_template(
|
17
|
+
'devise_tokens_create_users.rb.erb',
|
18
|
+
"db/migrate/devise_tokens_create_#{user_class.pluralize.gsub('::','').underscore}.rb"
|
19
|
+
)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def create_user_model
|
24
|
+
fname = "app/models/#{user_class.underscore}.rb"
|
25
|
+
if File.exist?(File.join(destination_root, fname))
|
26
|
+
inclusion = 'include DeviseTokens::Concerns::User'
|
27
|
+
unless parse_file_for_line(fname, inclusion)
|
28
|
+
|
29
|
+
active_record_needle = (Rails::VERSION::MAJOR == 5) ? 'ApplicationRecord' : 'ActiveRecord::Base'
|
30
|
+
inject_into_file fname, after: "class #{user_class} < #{active_record_needle}\n" do <<-'RUBY'
|
31
|
+
# Include default devise modules.
|
32
|
+
devise :database_authenticatable, :registerable,
|
33
|
+
:recoverable, :rememberable, :trackable, :validatable,
|
34
|
+
:confirmable, :omniauthable
|
35
|
+
include DeviseTokens::Concerns::User
|
36
|
+
RUBY
|
37
|
+
end
|
38
|
+
end
|
39
|
+
else
|
40
|
+
template('user.rb.erb', fname)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
private
|
45
|
+
|
46
|
+
def self.next_migration_number(path)
|
47
|
+
Time.zone.now.utc.strftime('%Y%m%d%H%M%S')
|
48
|
+
end
|
49
|
+
|
50
|
+
def json_supported_database?
|
51
|
+
(postgres? && postgres_correct_version?) || (mysql? && mysql_correct_version?)
|
52
|
+
end
|
53
|
+
|
54
|
+
def postgres?
|
55
|
+
database_name == 'ActiveRecord::ConnectionAdapters::PostgreSQLAdapter'
|
56
|
+
end
|
57
|
+
|
58
|
+
def postgres_correct_version?
|
59
|
+
database_version > '9.3'
|
60
|
+
end
|
61
|
+
|
62
|
+
def mysql?
|
63
|
+
database_name == 'ActiveRecord::ConnectionAdapters::MysqlAdapter'
|
64
|
+
end
|
65
|
+
|
66
|
+
def mysql_correct_version?
|
67
|
+
database_version > '5.7.7'
|
68
|
+
end
|
69
|
+
|
70
|
+
def database_name
|
71
|
+
ActiveRecord::Base.connection.class.name
|
72
|
+
end
|
73
|
+
|
74
|
+
def database_version
|
75
|
+
ActiveRecord::Base.connection.select_value('SELECT VERSION()')
|
76
|
+
end
|
77
|
+
|
78
|
+
def rails5?
|
79
|
+
Rails.version.start_with? '5'
|
80
|
+
end
|
81
|
+
|
82
|
+
def primary_key_type
|
83
|
+
primary_key_string if rails5?
|
84
|
+
end
|
85
|
+
|
86
|
+
def primary_key_string
|
87
|
+
key_string = options[:primary_key_type]
|
88
|
+
", id: :#{key_string}" if key_string
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
@@ -0,0 +1,98 @@
|
|
1
|
+
module DeviseTokens
|
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_tokens.rb', 'config/initializers/devise_tokens.rb')
|
13
|
+
end
|
14
|
+
|
15
|
+
def include_controller_concerns
|
16
|
+
fname = 'app/controllers/application_controller.rb'
|
17
|
+
line = 'include DeviseTokens::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 DeviseTokens::Concerns::SetUserByToken
|
25
|
+
RUBY
|
26
|
+
end
|
27
|
+
else
|
28
|
+
inject_into_file fname, after: "class ApplicationController < ActionController::Base\n" do <<-'RUBY'
|
29
|
+
include DeviseTokens::Concerns::SetUserByToken
|
30
|
+
RUBY
|
31
|
+
end
|
32
|
+
end
|
33
|
+
else
|
34
|
+
say_status('skipped', "app/controllers/application_controller.rb not found. Add 'include DeviseTokens::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_tokens_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_tokens_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_tokens_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
|