token_authenticate_me 0.4.3 → 0.5.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/{LICENSE → MIT-LICENSE} +1 -1
- data/Rakefile +27 -11
- data/app/controllers/token_authenticate_me/api/v1/base_controller.rb +9 -0
- data/app/controllers/token_authenticate_me/api/v1/invites_controller.rb +14 -0
- data/app/controllers/token_authenticate_me/api/v1/password_resets_controller.rb +11 -0
- data/app/controllers/token_authenticate_me/api/v1/sessions_controller.rb +11 -0
- data/app/controllers/token_authenticate_me/api/v1/users_controller.rb +17 -0
- data/app/controllers/token_authenticate_me/application_controller.rb +5 -0
- data/app/helpers/token_authenticate_me/application_helper.rb +4 -0
- data/app/mailers/token_authenticate_me_mailer.rb +16 -9
- data/app/models/token_authenticate_me/invite.rb +11 -0
- data/app/models/token_authenticate_me/session.rb +8 -0
- data/app/models/token_authenticate_me/user.rb +11 -0
- data/app/views/token_authenticate_me_mailer/invite_user_email.html.erb +0 -0
- data/config/routes.rb +23 -0
- data/db/migrate/20160620184327_create_token_authenticate_me_invites.rb +14 -0
- data/db/migrate/20160621211347_create_token_authenticate_me_users.rb +18 -0
- data/db/migrate/20160622203801_create_token_authenticate_me_sessions.rb +14 -0
- data/lib/generators/token_authenticate_me/controllers/controllers_generator.rb +1 -76
- data/lib/generators/token_authenticate_me/install/install_generator.rb +9 -3
- data/lib/generators/token_authenticate_me/models/models_generator.rb +1 -59
- data/lib/generators/token_authenticate_me/policies/policies_generator.rb +15 -0
- data/lib/generators/token_authenticate_me/policies/templates/invite_policy.rb +31 -0
- data/lib/generators/token_authenticate_me/policies/templates/user_policy.rb +23 -0
- data/lib/tasks/token_authenticate_me_tasks.rake +4 -0
- data/lib/token_authenticate_me.rb +11 -0
- data/lib/token_authenticate_me/concerns/controllers/invitable.rb +58 -0
- data/lib/token_authenticate_me/concerns/controllers/password_resetable.rb +97 -0
- data/lib/token_authenticate_me/concerns/controllers/sessionable.rb +55 -0
- data/lib/token_authenticate_me/concerns/controllers/token_authenticateable.rb +45 -0
- data/lib/token_authenticate_me/concerns/models/authenticatable.rb +102 -0
- data/lib/token_authenticate_me/concerns/models/invitable.rb +20 -0
- data/lib/token_authenticate_me/concerns/models/sessionable.rb +44 -0
- data/lib/token_authenticate_me/configuration.rb +16 -0
- data/lib/token_authenticate_me/engine.rb +2 -2
- data/lib/token_authenticate_me/models.rb +4 -0
- data/lib/token_authenticate_me/version.rb +1 -1
- data/test/dummy/README.rdoc +28 -0
- data/test/dummy/Rakefile +6 -0
- data/test/dummy/app/assets/javascripts/application.js +13 -0
- data/test/dummy/app/assets/stylesheets/application.css +15 -0
- data/{spec/internal → test/dummy}/app/controllers/application_controller.rb +0 -0
- data/test/dummy/app/helpers/application_helper.rb +2 -0
- data/test/dummy/app/views/layouts/application.html.erb +14 -0
- data/test/dummy/bin/bundle +3 -0
- data/test/dummy/bin/rails +4 -0
- data/test/dummy/bin/rake +4 -0
- data/test/dummy/bin/setup +29 -0
- data/test/dummy/config.ru +4 -0
- data/test/dummy/config/application.rb +25 -0
- data/test/dummy/config/boot.rb +5 -0
- data/test/dummy/config/database.yml +25 -0
- data/test/dummy/config/environment.rb +5 -0
- data/test/dummy/config/environments/development.rb +41 -0
- data/test/dummy/config/environments/production.rb +79 -0
- data/test/dummy/config/environments/test.rb +42 -0
- data/test/dummy/config/initializers/assets.rb +11 -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/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/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 +3 -0
- data/test/dummy/config/secrets.yml +22 -0
- data/test/dummy/log/test.log +0 -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/token_authenticate_me/invites.yml +11 -0
- data/test/fixtures/token_authenticate_me/sessions.yml +11 -0
- data/test/fixtures/token_authenticate_me/users.yml +11 -0
- data/test/integration/navigation_test.rb +7 -0
- data/test/models/token_authenticate_me/invite_test.rb +9 -0
- data/test/models/token_authenticate_me/session_test.rb +9 -0
- data/test/models/token_authenticate_me/user_test.rb +9 -0
- data/test/test_helper.rb +21 -0
- data/test/token_authenticate_me_test.rb +7 -0
- metadata +129 -160
- data/.editorconfig +0 -41
- data/.gitignore +0 -4
- data/.rubocop.yml +0 -8
- data/CHANGELOG.md +0 -2
- data/Gemfile +0 -7
- data/config.ru +0 -7
- data/lib/generators/token_authenticate_me/controllers/templates/password_reset.rb +0 -6
- data/lib/generators/token_authenticate_me/controllers/templates/sessions.rb +0 -6
- data/lib/generators/token_authenticate_me/controllers/templates/users.rb +0 -8
- data/lib/generators/token_authenticate_me/models/templates/authentication_migration.rb +0 -20
- data/lib/generators/token_authenticate_me/models/templates/authentication_model.rb +0 -11
- data/lib/generators/token_authenticate_me/models/templates/session_migration.rb +0 -17
- data/lib/generators/token_authenticate_me/models/templates/session_model.rb +0 -12
- data/lib/token_authenticate_me/controllers/password_resetable.rb +0 -95
- data/lib/token_authenticate_me/controllers/sessionable.rb +0 -53
- data/lib/token_authenticate_me/controllers/token_authenticateable.rb +0 -52
- data/lib/token_authenticate_me/models/authenticatable.rb +0 -93
- data/lib/token_authenticate_me/models/sessionable.rb +0 -36
- data/spec/acceptance/password_reset_api_spec.rb +0 -111
- data/spec/acceptance/session_api_spec.rb +0 -95
- data/spec/acceptance/users_api_spec.rb +0 -70
- data/spec/internal/app/controllers/password_resets_controller.rb +0 -5
- data/spec/internal/app/controllers/sessions_controller.rb +0 -5
- data/spec/internal/app/controllers/users_controller.rb +0 -7
- data/spec/internal/app/models/session.rb +0 -11
- data/spec/internal/app/models/user.rb +0 -11
- data/spec/internal/app/policies/user_policy.rb +0 -29
- data/spec/internal/app/serializers/user_serializer.rb +0 -3
- data/spec/internal/config/database.yml +0 -3
- data/spec/internal/config/routes.rb +0 -13
- data/spec/internal/db/fixtures/users.rb +0 -11
- data/spec/internal/db/schema.rb +0 -19
- data/spec/spec_helper.rb +0 -38
- data/token_authenticate_me.gemspec +0 -32
@@ -0,0 +1,15 @@
|
|
1
|
+
module TokenAuthenticateMe
|
2
|
+
module Generators
|
3
|
+
class PoliciesGenerator < ::Rails::Generators::Base
|
4
|
+
source_root File.expand_path('../templates', __FILE__)
|
5
|
+
|
6
|
+
def create_invite_poliocy
|
7
|
+
copy_file 'invite_policy.rb', 'app/policies/token_authenticate_me/invite_policy.rb'
|
8
|
+
end
|
9
|
+
|
10
|
+
def create_user_poliocy
|
11
|
+
copy_file 'user_policy.rb', 'app/policies/token_authenticate_me/user_policy.rb'
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module TokenAuthenticateMe
|
2
|
+
class InvitePolicy < ApplicationPolicy
|
3
|
+
def create?
|
4
|
+
record.owner_id == current_user.id || super
|
5
|
+
end
|
6
|
+
|
7
|
+
def show?
|
8
|
+
true
|
9
|
+
end
|
10
|
+
|
11
|
+
def update?
|
12
|
+
create?
|
13
|
+
end
|
14
|
+
|
15
|
+
def destroy?
|
16
|
+
record.owner_id == current_user.id || super
|
17
|
+
end
|
18
|
+
|
19
|
+
def accept?
|
20
|
+
current_user
|
21
|
+
end
|
22
|
+
|
23
|
+
def decline?
|
24
|
+
current_user
|
25
|
+
end
|
26
|
+
|
27
|
+
def permitted_attributes
|
28
|
+
[:email, :accepted, :meta]
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module TokenAuthenticateMe
|
2
|
+
class UserPolicy < ApplicationPolicy
|
3
|
+
def create?
|
4
|
+
true
|
5
|
+
end
|
6
|
+
|
7
|
+
def show?
|
8
|
+
true
|
9
|
+
end
|
10
|
+
|
11
|
+
def update?
|
12
|
+
record.id == current_user.id || super
|
13
|
+
end
|
14
|
+
|
15
|
+
def destroy?
|
16
|
+
record.id == current_user.id || super
|
17
|
+
end
|
18
|
+
|
19
|
+
def permitted_attributes
|
20
|
+
[:username, :email, :password, :password_confirmation]
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -1,6 +1,17 @@
|
|
1
1
|
require 'token_authenticate_me/engine'
|
2
2
|
require 'token_authenticate_me/version'
|
3
|
+
require 'token_authenticate_me/configuration'
|
3
4
|
|
4
5
|
module TokenAuthenticateMe
|
6
|
+
extend self
|
7
|
+
|
5
8
|
UUID_REGEX = /([a-f0-9]){32}/
|
9
|
+
|
10
|
+
def configure
|
11
|
+
yield configuration
|
12
|
+
end
|
13
|
+
|
14
|
+
def configuration
|
15
|
+
Configuration.instance
|
16
|
+
end
|
6
17
|
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
require 'api_me'
|
2
|
+
|
3
|
+
module TokenAuthenticateMe
|
4
|
+
module Concerns
|
5
|
+
module Controllers
|
6
|
+
module Invitable
|
7
|
+
extend ActiveSupport::Concern
|
8
|
+
|
9
|
+
include TokenAuthenticateMe::Controllers::TokenAuthenticateable
|
10
|
+
include ApiMe
|
11
|
+
|
12
|
+
included do |_base|
|
13
|
+
skip_before_action :authenticate, only: [:show]
|
14
|
+
|
15
|
+
def create
|
16
|
+
@object = model_klass.new(object_params)
|
17
|
+
authorize @object
|
18
|
+
@object.save!(object_params)
|
19
|
+
|
20
|
+
TokenAuthenticateMeMailer.invite_email(
|
21
|
+
@objec5,
|
22
|
+
request.base_url
|
23
|
+
).deliver_later
|
24
|
+
render status: 201, json: @object, serializer: serializer_klass
|
25
|
+
rescue ActiveRecord::RecordInvalid => e
|
26
|
+
handle_errors(e)
|
27
|
+
end
|
28
|
+
|
29
|
+
def accept
|
30
|
+
@object = model_klass.find(params[:id])
|
31
|
+
|
32
|
+
if @object.accepted.nil?
|
33
|
+
ActiveRecord::Base.transaction do
|
34
|
+
@object.accept!(current_user)
|
35
|
+
@object.update!(accepted: true)
|
36
|
+
end
|
37
|
+
|
38
|
+
render status: 204, nothing: true
|
39
|
+
else
|
40
|
+
render json: { message: 'The request has already been processed' }, status: 422
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def decline
|
45
|
+
@object = model_klass.find(params[:id])
|
46
|
+
|
47
|
+
if @object.accepted.nil?
|
48
|
+
@object.update!(accepted: false)
|
49
|
+
render status: 204, nothing: true
|
50
|
+
else
|
51
|
+
render json: { message: 'The request has already been processed' }, status: 422
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
@@ -0,0 +1,97 @@
|
|
1
|
+
require 'active_support/concern'
|
2
|
+
|
3
|
+
require 'token_authenticate_me/concerns/controllers/token_authenticateable'
|
4
|
+
|
5
|
+
module TokenAuthenticateMe
|
6
|
+
module Concerns
|
7
|
+
module Controllers
|
8
|
+
module PasswordResetable
|
9
|
+
extend ActiveSupport::Concern
|
10
|
+
|
11
|
+
include TokenAuthenticateMe::Concerns::Controllers::TokenAuthenticateable
|
12
|
+
|
13
|
+
included do
|
14
|
+
skip_before_action :authenticate, only: [:create, :update]
|
15
|
+
before_action :validate_reset_token, only: [:update]
|
16
|
+
|
17
|
+
# Send reset token to user with e-mail address
|
18
|
+
def create
|
19
|
+
@user = User.find_by_email(params[:email])
|
20
|
+
|
21
|
+
if @user
|
22
|
+
send_valid_reset_email(@user)
|
23
|
+
else
|
24
|
+
send_invalid_reset_email(params[:email])
|
25
|
+
end
|
26
|
+
|
27
|
+
render status: 204, nothing: true
|
28
|
+
end
|
29
|
+
|
30
|
+
# Allow user to reset password when the token is valid
|
31
|
+
# and not expired
|
32
|
+
def update
|
33
|
+
@user.update!(
|
34
|
+
password: params[:password],
|
35
|
+
password_confirmation: params[:password_confirmation],
|
36
|
+
reset_password_token: nil,
|
37
|
+
reset_password_token_exp: nil
|
38
|
+
)
|
39
|
+
|
40
|
+
render status: 204, nothing: true
|
41
|
+
rescue ActiveRecord::RecordInvalid => e
|
42
|
+
handle_errors(e)
|
43
|
+
end
|
44
|
+
|
45
|
+
private
|
46
|
+
|
47
|
+
def send_valid_reset_email(user)
|
48
|
+
user.create_reset_token!
|
49
|
+
|
50
|
+
TokenAuthenticateMeMailer.valid_user_reset_password_email(
|
51
|
+
request.base_url,
|
52
|
+
user
|
53
|
+
).deliver
|
54
|
+
end
|
55
|
+
|
56
|
+
def send_invalid_reset_email(email)
|
57
|
+
TokenAuthenticateMeMailer.invalid_user_reset_password_email(
|
58
|
+
request.base_url,
|
59
|
+
email
|
60
|
+
).deliver
|
61
|
+
end
|
62
|
+
|
63
|
+
def session_params
|
64
|
+
params.permit(:password, :password_confirmation)
|
65
|
+
end
|
66
|
+
|
67
|
+
def render_errors(errors, status = 422)
|
68
|
+
render(json: { errors: errors }, status: status)
|
69
|
+
end
|
70
|
+
|
71
|
+
def handle_errors(e)
|
72
|
+
render_errors(e.record.errors.messages)
|
73
|
+
end
|
74
|
+
|
75
|
+
def validate_reset_token
|
76
|
+
valid_reset_token? || render_not_found
|
77
|
+
end
|
78
|
+
|
79
|
+
def render_not_found
|
80
|
+
render status: 404, nothing: true
|
81
|
+
end
|
82
|
+
|
83
|
+
def valid_reset_token?
|
84
|
+
# Check for
|
85
|
+
# https://github.com/rails/rails/commit/e8572cf2f94872d81e7145da31d55c6e1b074247
|
86
|
+
# security issue when config.action_dispatch.perform_deep_munge = false is set
|
87
|
+
# which is common for JSON APIs
|
88
|
+
return false if params[:id].class == Array || params[:id].nil?
|
89
|
+
|
90
|
+
@user = User.find_by_reset_password_token(params[:id])
|
91
|
+
@user && @user.reset_password_token_exp > DateTime.now
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
require 'active_support/concern'
|
2
|
+
|
3
|
+
require 'token_authenticate_me/concerns/controllers/token_authenticateable'
|
4
|
+
|
5
|
+
module TokenAuthenticateMe
|
6
|
+
module Concerns
|
7
|
+
module Controllers
|
8
|
+
module Sessionable
|
9
|
+
extend ActiveSupport::Concern
|
10
|
+
|
11
|
+
include TokenAuthenticateMe::Concerns::Controllers::TokenAuthenticateable
|
12
|
+
|
13
|
+
included do
|
14
|
+
skip_before_action :authenticate, only: [:create]
|
15
|
+
after_action :cleanup_sessions, only: [:destroy]
|
16
|
+
|
17
|
+
def create
|
18
|
+
resource = User.where('username=? OR email=?', params[:username], params[:username]).first
|
19
|
+
if resource && resource.authenticate(params[:password])
|
20
|
+
@session = Session.create(user_id: resource.id)
|
21
|
+
render json: @session, status: 201
|
22
|
+
else
|
23
|
+
render json: { message: 'Bad credentials' }, status: 401
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def show
|
28
|
+
@session = authenticate_token
|
29
|
+
render json: @session
|
30
|
+
end
|
31
|
+
|
32
|
+
def destroy
|
33
|
+
authenticate_token.destroy
|
34
|
+
|
35
|
+
render status: 204, nothing: true
|
36
|
+
rescue
|
37
|
+
render_unauthorized
|
38
|
+
end
|
39
|
+
|
40
|
+
private
|
41
|
+
|
42
|
+
def session_params
|
43
|
+
params.permit(:username, :email, :password)
|
44
|
+
end
|
45
|
+
|
46
|
+
def cleanup_sessions
|
47
|
+
ApiSession.where('expiration < ?', DateTime.now).delete_all
|
48
|
+
rescue
|
49
|
+
Rails.logger.warn 'Error cleaning up old authentication sessions'
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
require 'active_support/concern'
|
2
|
+
|
3
|
+
module TokenAuthenticateMe
|
4
|
+
module Concerns
|
5
|
+
module Controllers
|
6
|
+
module TokenAuthenticateable
|
7
|
+
extend ActiveSupport::Concern
|
8
|
+
|
9
|
+
included do
|
10
|
+
before_action :authenticate
|
11
|
+
end
|
12
|
+
|
13
|
+
protected
|
14
|
+
|
15
|
+
def authenticate
|
16
|
+
authenticate_token || render_unauthorized
|
17
|
+
end
|
18
|
+
|
19
|
+
def current_user
|
20
|
+
if authenticate_token
|
21
|
+
@current_user ||= User.find_by_id(authenticate_token.user_id)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def authenticate_token
|
26
|
+
@session ||= authenticate_with_http_token(&method(:token_handler))
|
27
|
+
end
|
28
|
+
|
29
|
+
def render_unauthorized
|
30
|
+
headers['WWW-Authenticate'] = 'Token realm="Application"'
|
31
|
+
render json: 'Bad credentials', status: 401
|
32
|
+
end
|
33
|
+
|
34
|
+
def token_handler(token, _options)
|
35
|
+
session = TokenAuthenticateMe::Session.find_by_key(token)
|
36
|
+
if session && session.expiration > DateTime.now
|
37
|
+
session
|
38
|
+
else
|
39
|
+
false
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,102 @@
|
|
1
|
+
require 'active_support/concern'
|
2
|
+
|
3
|
+
module TokenAuthenticateMe
|
4
|
+
module Concerns
|
5
|
+
module Models
|
6
|
+
module Authenticatable
|
7
|
+
extend ActiveSupport::Concern
|
8
|
+
|
9
|
+
included do
|
10
|
+
has_secure_password validations: false
|
11
|
+
attr_accessor :current_password
|
12
|
+
|
13
|
+
has_many :sessions
|
14
|
+
has_many :invites, inverse_of: 'creator', foreign_key: 'creator_id'
|
15
|
+
|
16
|
+
validates(
|
17
|
+
:email,
|
18
|
+
presence: true,
|
19
|
+
uniqueness: { case_sensitive: false },
|
20
|
+
format: {
|
21
|
+
with: /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\z/i,
|
22
|
+
message: 'invalid e-mail address'
|
23
|
+
}
|
24
|
+
)
|
25
|
+
|
26
|
+
validates(
|
27
|
+
:username,
|
28
|
+
format: { with: /\A[a-zA-Z0-9]+\Z/ },
|
29
|
+
presence: true,
|
30
|
+
uniqueness: { case_sensitive: false }
|
31
|
+
)
|
32
|
+
|
33
|
+
validates(
|
34
|
+
:password,
|
35
|
+
presence: true,
|
36
|
+
length: { in: 8..72 },
|
37
|
+
confirmation: true,
|
38
|
+
if: :password_required?
|
39
|
+
)
|
40
|
+
|
41
|
+
validate(
|
42
|
+
:current_password_correct,
|
43
|
+
if: :current_password_required?
|
44
|
+
)
|
45
|
+
|
46
|
+
def attributes
|
47
|
+
{
|
48
|
+
'id' => id,
|
49
|
+
'username' => username,
|
50
|
+
'email' => email,
|
51
|
+
'created_at' => created_at,
|
52
|
+
'updated_at' => updated_at
|
53
|
+
}
|
54
|
+
end
|
55
|
+
|
56
|
+
def as_json(options = nil)
|
57
|
+
{ user: super(options) }
|
58
|
+
end
|
59
|
+
|
60
|
+
def create_reset_token!
|
61
|
+
# rubocop:disable Lint/Loop
|
62
|
+
begin
|
63
|
+
self.reset_password_token = SecureRandom.hex
|
64
|
+
end while self.class.exists?(reset_password_token: reset_password_token)
|
65
|
+
|
66
|
+
self.reset_password_token_exp = password_expiration_hours.hours.from_now
|
67
|
+
save!
|
68
|
+
end
|
69
|
+
|
70
|
+
def password_expiration_hours
|
71
|
+
8
|
72
|
+
end
|
73
|
+
|
74
|
+
def password=(unencrypted_password)
|
75
|
+
super(unencrypted_password) unless unencrypted_password.blank? && !password_required?
|
76
|
+
end
|
77
|
+
|
78
|
+
def current_password_correct
|
79
|
+
errors.add(:current_password, 'is required to change email and/or password') if current_password.blank? # rubocop:disable Metrics/LineLength
|
80
|
+
errors.add(:current_password, 'is incorrect') unless authenticate(current_password)
|
81
|
+
end
|
82
|
+
|
83
|
+
def current_password_required?
|
84
|
+
!new_record? && (email_changed? || attempting_to_change_password?) && !password_resetting?
|
85
|
+
end
|
86
|
+
|
87
|
+
def password_resetting?
|
88
|
+
reset_password_token_changed? && reset_password_token_exp_changed?
|
89
|
+
end
|
90
|
+
|
91
|
+
def password_required?
|
92
|
+
attempting_to_change_password? || new_record?
|
93
|
+
end
|
94
|
+
|
95
|
+
def attempting_to_change_password?
|
96
|
+
(!password.blank? || !password_confirmation.blank?) && password_digest_changed?
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|