cm-devise_token_auth 0.1.30.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/LICENSE +13 -0
- data/README.md +688 -0
- data/Rakefile +34 -0
- data/app/controllers/devise_token_auth/application_controller.rb +17 -0
- data/app/controllers/devise_token_auth/concerns/set_user_by_token.rb +109 -0
- data/app/controllers/devise_token_auth/confirmations_controller.rb +31 -0
- data/app/controllers/devise_token_auth/omniauth_callbacks_controller.rb +171 -0
- data/app/controllers/devise_token_auth/passwords_controller.rb +155 -0
- data/app/controllers/devise_token_auth/registrations_controller.rb +123 -0
- data/app/controllers/devise_token_auth/sessions_controller.rb +98 -0
- data/app/controllers/devise_token_auth/token_validations_controller.rb +23 -0
- data/app/models/devise_token_auth/concerns/user.rb +231 -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_failure.html.erb +2 -0
- data/app/views/devise_token_auth/omniauth_success.html.erb +8 -0
- data/app/views/layouts/omniauth_response.html.erb +31 -0
- data/config/initializers/devise.rb +203 -0
- data/config/locales/devise.en.yml +59 -0
- data/config/routes.rb +5 -0
- data/lib/devise_token_auth.rb +7 -0
- data/lib/devise_token_auth/controllers/helpers.rb +129 -0
- data/lib/devise_token_auth/controllers/url_helpers.rb +8 -0
- data/lib/devise_token_auth/engine.rb +25 -0
- data/lib/devise_token_auth/rails/routes.rb +65 -0
- data/lib/devise_token_auth/version.rb +3 -0
- data/lib/generators/devise_token_auth/USAGE +31 -0
- data/lib/generators/devise_token_auth/install_generator.rb +115 -0
- data/lib/generators/devise_token_auth/install_views_generator.rb +16 -0
- data/lib/generators/devise_token_auth/templates/devise_token_auth.rb +22 -0
- data/lib/generators/devise_token_auth/templates/devise_token_auth_create_users.rb.erb +54 -0
- data/lib/generators/devise_token_auth/templates/user.rb +3 -0
- data/lib/tasks/devise_token_auth_tasks.rake +4 -0
- data/test/controllers/demo_group_controller_test.rb +126 -0
- data/test/controllers/demo_mang_controller_test.rb +263 -0
- data/test/controllers/demo_user_controller_test.rb +262 -0
- data/test/controllers/devise_token_auth/confirmations_controller_test.rb +107 -0
- data/test/controllers/devise_token_auth/omniauth_callbacks_controller_test.rb +167 -0
- data/test/controllers/devise_token_auth/passwords_controller_test.rb +287 -0
- data/test/controllers/devise_token_auth/registrations_controller_test.rb +458 -0
- data/test/controllers/devise_token_auth/sessions_controller_test.rb +221 -0
- data/test/controllers/overrides/confirmations_controller_test.rb +44 -0
- data/test/controllers/overrides/omniauth_callbacks_controller_test.rb +44 -0
- data/test/controllers/overrides/passwords_controller_test.rb +62 -0
- data/test/controllers/overrides/registrations_controller_test.rb +40 -0
- data/test/controllers/overrides/sessions_controller_test.rb +33 -0
- data/test/controllers/overrides/token_validations_controller_test.rb +38 -0
- data/test/dummy/README.rdoc +28 -0
- data/test/dummy/Rakefile +6 -0
- data/test/dummy/app/assets/images/logo.jpg +0 -0
- data/test/dummy/app/assets/images/omniauth-provider-settings.png +0 -0
- data/test/dummy/app/assets/javascripts/application.js +13 -0
- data/test/dummy/app/assets/stylesheets/application.css +15 -0
- data/test/dummy/app/controllers/application_controller.rb +16 -0
- data/test/dummy/app/controllers/demo_group_controller.rb +13 -0
- data/test/dummy/app/controllers/demo_mang_controller.rb +12 -0
- data/test/dummy/app/controllers/demo_user_controller.rb +12 -0
- data/test/dummy/app/controllers/overrides/confirmations_controller.rb +32 -0
- data/test/dummy/app/controllers/overrides/omniauth_callbacks_controller.rb +14 -0
- data/test/dummy/app/controllers/overrides/passwords_controller.rb +39 -0
- data/test/dummy/app/controllers/overrides/registrations_controller.rb +27 -0
- data/test/dummy/app/controllers/overrides/sessions_controller.rb +43 -0
- data/test/dummy/app/controllers/overrides/token_validations_controller.rb +23 -0
- data/test/dummy/app/helpers/application_helper.rb +1065 -0
- data/test/dummy/app/models/evil_user.rb +3 -0
- data/test/dummy/app/models/mang.rb +3 -0
- data/test/dummy/app/models/user.rb +18 -0
- data/test/dummy/app/views/layouts/application.html.erb +14 -0
- data/test/dummy/bin/bundle +3 -0
- data/test/dummy/bin/rails +8 -0
- data/test/dummy/bin/rake +8 -0
- data/test/dummy/bin/spring +18 -0
- data/test/dummy/config.ru +16 -0
- data/test/dummy/config/application.rb +23 -0
- data/test/dummy/config/application.yml.bk +0 -0
- data/test/dummy/config/boot.rb +5 -0
- data/test/dummy/config/database.yml +31 -0
- data/test/dummy/config/environment.rb +5 -0
- data/test/dummy/config/environments/development.rb +44 -0
- data/test/dummy/config/environments/production.rb +82 -0
- data/test/dummy/config/environments/test.rb +40 -0
- data/test/dummy/config/initializers/assets.rb +8 -0
- data/test/dummy/config/initializers/backtrace_silencers.rb +7 -0
- data/test/dummy/config/initializers/cookies_serializer.rb +3 -0
- data/test/dummy/config/initializers/devise_token_auth.rb +22 -0
- data/test/dummy/config/initializers/figaro.rb +1 -0
- data/test/dummy/config/initializers/filter_parameter_logging.rb +4 -0
- data/test/dummy/config/initializers/inflections.rb +16 -0
- data/test/dummy/config/initializers/mime_types.rb +4 -0
- data/test/dummy/config/initializers/omniauth.rb +8 -0
- data/test/dummy/config/initializers/session_store.rb +3 -0
- data/test/dummy/config/initializers/wrap_parameters.rb +14 -0
- data/test/dummy/config/locales/en.yml +23 -0
- data/test/dummy/config/routes.rb +30 -0
- data/test/dummy/config/secrets.yml +22 -0
- data/test/dummy/config/spring.rb +1 -0
- data/test/dummy/db/migrate/20140715061447_devise_token_auth_create_users.rb +56 -0
- data/test/dummy/db/migrate/20140715061805_devise_token_auth_create_mangs.rb +56 -0
- data/test/dummy/db/migrate/20140829044006_add_operating_thetan_to_user.rb +6 -0
- data/test/dummy/db/migrate/20140916224624_add_favorite_color_to_mangs.rb +5 -0
- data/test/dummy/db/migrate/20140928231203_devise_token_auth_create_evil_users.rb +57 -0
- data/test/dummy/db/schema.rb +114 -0
- data/test/dummy/public/404.html +67 -0
- data/test/dummy/public/422.html +67 -0
- data/test/dummy/public/500.html +66 -0
- data/test/dummy/public/favicon.ico +0 -0
- data/test/fixtures/evil_users.yml +29 -0
- data/test/fixtures/mangs.yml +29 -0
- data/test/fixtures/users.yml +29 -0
- data/test/integration/navigation_test.rb +10 -0
- data/test/lib/generators/devise_token_auth/install_generator_test.rb +178 -0
- data/test/lib/generators/devise_token_auth/install_views_generator_test.rb +23 -0
- data/test/models/user_test.rb +90 -0
- data/test/test_helper.rb +60 -0
- metadata +310 -0
data/Rakefile
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
begin
|
2
|
+
require 'bundler/setup'
|
3
|
+
rescue LoadError
|
4
|
+
puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
|
5
|
+
end
|
6
|
+
|
7
|
+
require 'rdoc/task'
|
8
|
+
|
9
|
+
RDoc::Task.new(:rdoc) do |rdoc|
|
10
|
+
rdoc.rdoc_dir = 'rdoc'
|
11
|
+
rdoc.title = 'DeviseTokenAuth'
|
12
|
+
rdoc.options << '--line-numbers'
|
13
|
+
rdoc.rdoc_files.include('README.rdoc')
|
14
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
15
|
+
end
|
16
|
+
|
17
|
+
APP_RAKEFILE = File.expand_path("../test/dummy/Rakefile", __FILE__)
|
18
|
+
load 'rails/tasks/engine.rake'
|
19
|
+
|
20
|
+
|
21
|
+
|
22
|
+
Bundler::GemHelper.install_tasks
|
23
|
+
|
24
|
+
require 'rake/testtask'
|
25
|
+
|
26
|
+
Rake::TestTask.new(:test) do |t|
|
27
|
+
t.libs << 'lib'
|
28
|
+
t.libs << 'test'
|
29
|
+
t.pattern = 'test/**/*_test.rb'
|
30
|
+
t.verbose = false
|
31
|
+
end
|
32
|
+
|
33
|
+
|
34
|
+
task default: :test
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module DeviseTokenAuth
|
2
|
+
class ApplicationController < DeviseController
|
3
|
+
include DeviseTokenAuth::Concerns::SetUserByToken
|
4
|
+
respond_to :json
|
5
|
+
|
6
|
+
|
7
|
+
def resource_class(m=nil)
|
8
|
+
if m
|
9
|
+
mapping = Devise.mappings[m]
|
10
|
+
else
|
11
|
+
mapping = Devise.mappings[resource_name] || Devise.mappings.values.first
|
12
|
+
end
|
13
|
+
|
14
|
+
mapping.to
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,109 @@
|
|
1
|
+
module DeviseTokenAuth::Concerns::SetUserByToken
|
2
|
+
extend ActiveSupport::Concern
|
3
|
+
include DeviseTokenAuth::Controllers::Helpers
|
4
|
+
|
5
|
+
included do
|
6
|
+
before_action :set_request_start
|
7
|
+
after_action :update_auth_header
|
8
|
+
end
|
9
|
+
|
10
|
+
# keep track of request duration
|
11
|
+
def set_request_start
|
12
|
+
@request_started_at = Time.now
|
13
|
+
end
|
14
|
+
|
15
|
+
# user auth
|
16
|
+
def set_user_by_token(mapping=nil)
|
17
|
+
|
18
|
+
# determine target authentication class
|
19
|
+
rc = resource_class(mapping)
|
20
|
+
rc = rc.active if rc.respond_to?(:active)
|
21
|
+
|
22
|
+
# no default user defined
|
23
|
+
return unless rc
|
24
|
+
|
25
|
+
# user has already been found and authenticated
|
26
|
+
return @resource if @resource and @resource.class == rc
|
27
|
+
|
28
|
+
# parse header for values necessary for authentication
|
29
|
+
uid = request.headers['uid']
|
30
|
+
@token = request.headers['access-token']
|
31
|
+
@client_id = request.headers['client']
|
32
|
+
|
33
|
+
return false unless @token
|
34
|
+
|
35
|
+
# client_id isn't required, set to 'default' if absent
|
36
|
+
@client_id ||= 'default'
|
37
|
+
|
38
|
+
# mitigate timing attacks by finding by uid instead of auth token
|
39
|
+
user = uid && rc.find_by_uid(uid)
|
40
|
+
|
41
|
+
if user && user.valid_token?(@token, @client_id)
|
42
|
+
sign_in(:user, user, store: false, bypass: true)
|
43
|
+
return @resource = user
|
44
|
+
else
|
45
|
+
# zero all values previously set values
|
46
|
+
return @resource = nil
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
|
51
|
+
def update_auth_header
|
52
|
+
|
53
|
+
# cannot save object if model has invalid params
|
54
|
+
return unless @resource and @resource.valid? and @client_id
|
55
|
+
|
56
|
+
# Lock the user record during any auth_header updates to ensure
|
57
|
+
# we don't have write contention from multiple threads
|
58
|
+
@resource.with_lock do
|
59
|
+
|
60
|
+
# determine batch request status after request processing, in case
|
61
|
+
# another processes has updated it during that processing
|
62
|
+
@is_batch_request = is_batch_request?(@resource, @client_id)
|
63
|
+
|
64
|
+
auth_header = {}
|
65
|
+
|
66
|
+
if not DeviseTokenAuth.change_headers_on_each_request
|
67
|
+
auth_header = @resource.build_auth_header(@token, @client_id)
|
68
|
+
return unless auth_header
|
69
|
+
|
70
|
+
# update the response header
|
71
|
+
response.headers.merge!(auth_header)
|
72
|
+
|
73
|
+
# extend expiration of batch buffer to account for the duration of
|
74
|
+
# this request
|
75
|
+
elsif @is_batch_request
|
76
|
+
auth_header = @resource.extend_batch_buffer(@token, @client_id)
|
77
|
+
|
78
|
+
# update Authorization response header with new token
|
79
|
+
else
|
80
|
+
auth_header = @resource.create_new_auth_token(@client_id)
|
81
|
+
|
82
|
+
# update the response header
|
83
|
+
response.headers.merge!(auth_header)
|
84
|
+
end
|
85
|
+
|
86
|
+
end # end lock
|
87
|
+
|
88
|
+
end
|
89
|
+
|
90
|
+
def resource_class(m=nil)
|
91
|
+
if m
|
92
|
+
mapping = Devise.mappings[m]
|
93
|
+
else
|
94
|
+
mapping = Devise.mappings[resource_name] || Devise.mappings.values.first
|
95
|
+
end
|
96
|
+
|
97
|
+
mapping.to
|
98
|
+
end
|
99
|
+
|
100
|
+
|
101
|
+
private
|
102
|
+
|
103
|
+
|
104
|
+
def is_batch_request?(user, client_id)
|
105
|
+
user.tokens[client_id] and
|
106
|
+
user.tokens[client_id]['updated_at'] and
|
107
|
+
Time.parse(user.tokens[client_id]['updated_at']) > @request_started_at - DeviseTokenAuth.batch_request_buffer_throttle
|
108
|
+
end
|
109
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module DeviseTokenAuth
|
2
|
+
class ConfirmationsController < DeviseTokenAuth::ApplicationController
|
3
|
+
def show
|
4
|
+
@resource = resource_class.confirm_by_token(params[:confirmation_token])
|
5
|
+
|
6
|
+
if @resource and @resource.id
|
7
|
+
# create client id
|
8
|
+
client_id = SecureRandom.urlsafe_base64(nil, false)
|
9
|
+
token = SecureRandom.urlsafe_base64(nil, false)
|
10
|
+
token_hash = BCrypt::Password.create(token)
|
11
|
+
expiry = (Time.now + DeviseTokenAuth.token_lifespan).to_i
|
12
|
+
|
13
|
+
@resource.tokens[client_id] = {
|
14
|
+
token: token_hash,
|
15
|
+
expiry: expiry
|
16
|
+
}
|
17
|
+
|
18
|
+
@resource.save!
|
19
|
+
|
20
|
+
redirect_to(@resource.build_auth_url(params[:redirect_url], {
|
21
|
+
token: token,
|
22
|
+
client_id: client_id,
|
23
|
+
account_confirmation_success: true,
|
24
|
+
config: params[:config]
|
25
|
+
}))
|
26
|
+
else
|
27
|
+
raise ActionController::RoutingError.new('Not Found')
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,171 @@
|
|
1
|
+
module DeviseTokenAuth
|
2
|
+
class OmniauthCallbacksController < DeviseTokenAuth::ApplicationController
|
3
|
+
skip_before_filter :set_user_by_token
|
4
|
+
skip_after_filter :update_auth_header
|
5
|
+
|
6
|
+
# intermediary route for successful omniauth authentication. omniauth does
|
7
|
+
# not support multiple models, so we must resort to this terrible hack.
|
8
|
+
def redirect_callbacks
|
9
|
+
# derive target redirect route from 'resource_class' param, which was set
|
10
|
+
# before authentication.
|
11
|
+
devise_mapping = request.env['omniauth.params']['resource_class'].underscore.to_sym
|
12
|
+
redirect_route = "#{Devise.mappings[devise_mapping].as_json["path_prefix"]}/#{params[:provider]}/callback"
|
13
|
+
|
14
|
+
# preserve omniauth info for success route
|
15
|
+
session['dta.omniauth.auth'] = request.env['omniauth.auth']
|
16
|
+
session['dta.omniauth.params'] = request.env['omniauth.params']
|
17
|
+
|
18
|
+
redirect_to redirect_route
|
19
|
+
end
|
20
|
+
|
21
|
+
def omniauth_success
|
22
|
+
# find or create user by provider and provider uid
|
23
|
+
@resource = resource_class.where({
|
24
|
+
uid: auth_hash['uid'],
|
25
|
+
provider: auth_hash['provider']
|
26
|
+
}).first_or_initialize
|
27
|
+
|
28
|
+
# create token info
|
29
|
+
@client_id = SecureRandom.urlsafe_base64(nil, false)
|
30
|
+
@token = SecureRandom.urlsafe_base64(nil, false)
|
31
|
+
@expiry = (Time.now + DeviseTokenAuth.token_lifespan).to_i
|
32
|
+
|
33
|
+
@auth_origin_url = generate_url(omniauth_params['auth_origin_url'], {
|
34
|
+
token: @token,
|
35
|
+
client_id: @client_id,
|
36
|
+
uid: @resource.uid,
|
37
|
+
expiry: @expiry
|
38
|
+
})
|
39
|
+
|
40
|
+
# set crazy password for new oauth users. this is only used to prevent
|
41
|
+
# access via email sign-in.
|
42
|
+
unless @resource.id
|
43
|
+
p = SecureRandom.urlsafe_base64(nil, false)
|
44
|
+
@resource.password = p
|
45
|
+
@resource.password_confirmation = p
|
46
|
+
end
|
47
|
+
|
48
|
+
@resource.tokens[@client_id] = {
|
49
|
+
token: BCrypt::Password.create(@token),
|
50
|
+
expiry: @expiry
|
51
|
+
}
|
52
|
+
|
53
|
+
# sync user info with provider, update/generate auth token
|
54
|
+
assign_provider_attrs(@resource, auth_hash)
|
55
|
+
|
56
|
+
# assign any additional (whitelisted) attributes
|
57
|
+
extra_params = whitelisted_params
|
58
|
+
@resource.assign_attributes(extra_params) if extra_params
|
59
|
+
|
60
|
+
# don't send confirmation email!!!
|
61
|
+
@resource.skip_confirmation!
|
62
|
+
|
63
|
+
sign_in(:user, @resource, store: false, bypass: false)
|
64
|
+
|
65
|
+
@resource.save!
|
66
|
+
|
67
|
+
# render user info to javascript postMessage communication window
|
68
|
+
respond_to do |format|
|
69
|
+
format.html { render :layout => "omniauth_response", :template => "devise_token_auth/omniauth_success" }
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
|
74
|
+
# break out provider attribute assignment for easy method extension
|
75
|
+
def assign_provider_attrs(user, auth_hash)
|
76
|
+
user.assign_attributes({
|
77
|
+
nickname: auth_hash['info']['nickname'],
|
78
|
+
name: auth_hash['info']['name'],
|
79
|
+
image: auth_hash['info']['image'],
|
80
|
+
email: auth_hash['info']['email']
|
81
|
+
})
|
82
|
+
end
|
83
|
+
|
84
|
+
|
85
|
+
def omniauth_failure
|
86
|
+
@error = params[:message]
|
87
|
+
|
88
|
+
respond_to do |format|
|
89
|
+
format.html { render :layout => "omniauth_response", :template => "devise_token_auth/omniauth_failure" }
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
|
94
|
+
# derive allowed params from the standard devise parameter sanitizer
|
95
|
+
def whitelisted_params
|
96
|
+
whitelist = devise_parameter_sanitizer.for(:sign_up)
|
97
|
+
|
98
|
+
whitelist.inject({}){|coll, key|
|
99
|
+
param = omniauth_params[key.to_s]
|
100
|
+
if param
|
101
|
+
coll[key] = param
|
102
|
+
end
|
103
|
+
coll
|
104
|
+
}
|
105
|
+
end
|
106
|
+
|
107
|
+
# pull resource class from omniauth return
|
108
|
+
def resource_class
|
109
|
+
if omniauth_params
|
110
|
+
omniauth_params['resource_class'].constantize
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
def resource_name
|
115
|
+
resource_class
|
116
|
+
end
|
117
|
+
|
118
|
+
# this will be determined differently depending on the action that calls
|
119
|
+
# it. redirect_callbacks is called upon returning from successful omniauth
|
120
|
+
# authentication, and the target params live in an omniauth-specific
|
121
|
+
# request.env variable. this variable is then persisted thru the redirect
|
122
|
+
# using our own dta.omniauth.params session var. the omniauth_success
|
123
|
+
# method will access that session var and then destroy it immediately
|
124
|
+
# after use.
|
125
|
+
def omniauth_params
|
126
|
+
if request.env['omniauth.params']
|
127
|
+
request.env['omniauth.params']
|
128
|
+
else
|
129
|
+
@_omniauth_params ||= session.delete('dta.omniauth.params')
|
130
|
+
@_omniauth_params
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
# this sesison value is set by the redirect_callbacks method. its purpose
|
135
|
+
# is to persist the omniauth auth hash value thru a redirect. the value
|
136
|
+
# must be destroyed immediatly after it is accessed by omniauth_success
|
137
|
+
def auth_hash
|
138
|
+
@_auth_hash ||= session.delete('dta.omniauth.auth')
|
139
|
+
@_auth_hash
|
140
|
+
end
|
141
|
+
|
142
|
+
# ensure that this controller responds to :devise_controller? conditionals.
|
143
|
+
# this is used primarily for access to the parameter sanitizers.
|
144
|
+
def assert_is_devise_resource!
|
145
|
+
true
|
146
|
+
end
|
147
|
+
|
148
|
+
# necessary for access to devise_parameter_sanitizers
|
149
|
+
def devise_mapping
|
150
|
+
if omniauth_params
|
151
|
+
Devise.mappings[omniauth_params['resource_class'].underscore.to_sym]
|
152
|
+
else
|
153
|
+
request.env['devise.mapping']
|
154
|
+
end
|
155
|
+
end
|
156
|
+
|
157
|
+
def generate_url(url, params = {})
|
158
|
+
auth_url = url
|
159
|
+
|
160
|
+
# ensure that hash-bang is present BEFORE querystring for angularjs
|
161
|
+
unless url.match(/#/)
|
162
|
+
auth_url += '#'
|
163
|
+
end
|
164
|
+
|
165
|
+
# add query AFTER hash-bang
|
166
|
+
auth_url += "?#{params.to_query}"
|
167
|
+
|
168
|
+
return auth_url
|
169
|
+
end
|
170
|
+
end
|
171
|
+
end
|
@@ -0,0 +1,155 @@
|
|
1
|
+
module DeviseTokenAuth
|
2
|
+
class PasswordsController < DeviseTokenAuth::ApplicationController
|
3
|
+
before_filter :set_user_by_token, :only => [:update]
|
4
|
+
skip_after_filter :update_auth_header, :only => [:create, :edit]
|
5
|
+
|
6
|
+
# this action is responsible for generating password reset tokens and
|
7
|
+
# sending emails
|
8
|
+
def create
|
9
|
+
unless resource_params[:email]
|
10
|
+
return render json: {
|
11
|
+
success: false,
|
12
|
+
errors: ['You must provide an email address.']
|
13
|
+
}, status: 401
|
14
|
+
end
|
15
|
+
|
16
|
+
unless params[:redirect_url]
|
17
|
+
return render json: {
|
18
|
+
success: false,
|
19
|
+
errors: ['Missing redirect url.']
|
20
|
+
}, status: 401
|
21
|
+
end
|
22
|
+
|
23
|
+
# honor devise configuration for case_insensitive_keys
|
24
|
+
if resource_class.case_insensitive_keys.include?(:email)
|
25
|
+
email = resource_params[:email].downcase
|
26
|
+
else
|
27
|
+
email = resource_params[:email]
|
28
|
+
end
|
29
|
+
|
30
|
+
q = "uid='#{email}' AND provider='email'"
|
31
|
+
|
32
|
+
# fix for mysql default case insensitivity
|
33
|
+
if ActiveRecord::Base.connection.adapter_name.downcase.starts_with? 'mysql'
|
34
|
+
q = "BINARY uid='#{email}' AND provider='email'"
|
35
|
+
end
|
36
|
+
|
37
|
+
@resource = resource_class.where(q).first
|
38
|
+
|
39
|
+
errors = nil
|
40
|
+
|
41
|
+
if @resource
|
42
|
+
@resource.send_reset_password_instructions({
|
43
|
+
email: email,
|
44
|
+
provider: 'email',
|
45
|
+
redirect_url: params[:redirect_url],
|
46
|
+
client_config: params[:config_name]
|
47
|
+
})
|
48
|
+
|
49
|
+
if @resource.errors.empty?
|
50
|
+
render json: {
|
51
|
+
success: true,
|
52
|
+
message: "An email has been sent to #{email} containing "+
|
53
|
+
"instructions for resetting your password."
|
54
|
+
}
|
55
|
+
else
|
56
|
+
errors = @resource.errors
|
57
|
+
end
|
58
|
+
else
|
59
|
+
errors = ["Unable to find user with email '#{email}'."]
|
60
|
+
end
|
61
|
+
|
62
|
+
if errors
|
63
|
+
render json: {
|
64
|
+
success: false,
|
65
|
+
errors: errors
|
66
|
+
}, status: 400
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
|
71
|
+
# this is where users arrive after visiting the email confirmation link
|
72
|
+
def edit
|
73
|
+
@resource = resource_class.reset_password_by_token({
|
74
|
+
reset_password_token: resource_params[:reset_password_token]
|
75
|
+
})
|
76
|
+
|
77
|
+
if @resource and @resource.id
|
78
|
+
client_id = SecureRandom.urlsafe_base64(nil, false)
|
79
|
+
token = SecureRandom.urlsafe_base64(nil, false)
|
80
|
+
token_hash = BCrypt::Password.create(token)
|
81
|
+
expiry = (Time.now + DeviseTokenAuth.token_lifespan).to_i
|
82
|
+
|
83
|
+
@resource.tokens[client_id] = {
|
84
|
+
token: token_hash,
|
85
|
+
expiry: expiry
|
86
|
+
}
|
87
|
+
|
88
|
+
# ensure that user is confirmed
|
89
|
+
@resource.skip_confirmation! unless @resource.confirmed_at
|
90
|
+
|
91
|
+
@resource.save!
|
92
|
+
|
93
|
+
redirect_to(@resource.build_auth_url(params[:redirect_url], {
|
94
|
+
token: token,
|
95
|
+
client_id: client_id,
|
96
|
+
reset_password: true,
|
97
|
+
config: params[:config]
|
98
|
+
}))
|
99
|
+
else
|
100
|
+
raise ActionController::RoutingError.new('Not Found')
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
def update
|
105
|
+
# make sure user is authorized
|
106
|
+
unless @resource
|
107
|
+
return render json: {
|
108
|
+
success: false,
|
109
|
+
errors: ['Unauthorized']
|
110
|
+
}, status: 401
|
111
|
+
end
|
112
|
+
|
113
|
+
# make sure account doesn't use oauth2 provider
|
114
|
+
unless @resource.provider == 'email'
|
115
|
+
return render json: {
|
116
|
+
success: false,
|
117
|
+
errors: ["This account does not require a password. Sign in using "+
|
118
|
+
"your #{@resource.provider.humanize} account instead."]
|
119
|
+
}, status: 422
|
120
|
+
end
|
121
|
+
|
122
|
+
# ensure that password params were sent
|
123
|
+
unless password_resource_params[:password] and password_resource_params[:password_confirmation]
|
124
|
+
return render json: {
|
125
|
+
success: false,
|
126
|
+
errors: ['You must fill out the fields labeled "password" and "password confirmation".']
|
127
|
+
}, status: 422
|
128
|
+
end
|
129
|
+
|
130
|
+
if @resource.update_attributes(password_resource_params)
|
131
|
+
return render json: {
|
132
|
+
success: true,
|
133
|
+
data: {
|
134
|
+
user: @resource,
|
135
|
+
message: "Your password has been successfully updated."
|
136
|
+
}
|
137
|
+
}
|
138
|
+
else
|
139
|
+
return render json: {
|
140
|
+
success: false,
|
141
|
+
errors: @resource.errors
|
142
|
+
}, status: 422
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
146
|
+
def password_resource_params
|
147
|
+
params.permit(devise_parameter_sanitizer.for(:account_update))
|
148
|
+
end
|
149
|
+
|
150
|
+
def resource_params
|
151
|
+
params.permit(:email, :password, :password_confirmation, :reset_password_token)
|
152
|
+
end
|
153
|
+
|
154
|
+
end
|
155
|
+
end
|