-
-
Notifications
You must be signed in to change notification settings - Fork 468
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Set an expiration for password reset tokens #532
Conversation
unless find_user_by_id_and_confirmation_token | ||
unless find_user_from_password_reset | ||
flash_failure_when_forbidden | ||
render template: 'passwords/new' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Prefer double-quoted strings unless you need single quotes to avoid extra backslashes for escaping.
840d69b
to
c686c74
Compare
def time_limit | ||
Clearance.configuration.password_reset_time_limit | ||
end | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Extra empty line detected at body end.
b011ae8
to
5690e51
Compare
deliver_email(user) | ||
password_reset = PasswordReset.new | ||
password_reset.user = user | ||
password_reset.save |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's been a while since I've Rails'ed, but there's a better way to do this, right? It's a one-way association, i.e. there's only a belongs_to
association in PasswordReset
, no has_many
from User
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe:
password_reset = PasswordReset.create!(user: user)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, I had something like that originally, but Rails 3.2 doesn't seem to like it because of mass-assignments. =\ I guess I could at least extract the reset-building as a private method in here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Did something like this instead: f2ee26c.
Since this changes the interface for documented template methods (the documentation is about as broad as possible: "See app/controllers/clearance for the default behavior"), this means that this will be part of the major version bump. Right? |
@mike-burns Yes, you are correct. |
t.timestamps null: false | ||
end | ||
|
||
add_index :password_resets, :user_id |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
should we index the expires_at
column as well? Maybe change this to a compound index on [:user_id, :expires_at]
? Might be too much...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sounds good to me. Done in 8f0f9a8.
Took a quick spin through everything. This is great, thanks so much. I do think we can do this in a manner that lets us ship this in opt-in fashion for 1.x. Either via a separate controller and/or via service objects like monban. We can look at it Friday. |
@@ -0,0 +1,36 @@ | |||
class PasswordReset < ActiveRecord::Base |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should this be a template instead of in app/models
, like https://github.com/thoughtbot/clearance/blob/master/lib/generators/clearance/install/templates/user.rb?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No. Clearance models are internal to clearance and not generate. User is a template because we expect you already have a user class of some sort.
def up | ||
expiration_timestamp = Clearance.configuration. | ||
password_reset_time_limit. | ||
from_now |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Align the operands of an expression in an assignment spanning multiple lines.
provide_existing_application_controller | ||
allow(password_reset_migration_generator).to receive(:new). | ||
and_return( | ||
instance_double(password_reset_migration_generator).as_null_object |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Put a comma after the last parameter of a multiline method call.
where( | ||
"#{Clearance.configuration.user_id_parameter} = ? AND expires_at > ?", | ||
user_id, | ||
Time.zone.now |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Put a comma after the last parameter of a multiline method call.
@derekprior Whenever you get a chance, could you take a look at this again? I think it's pretty much all set to go. The only thing I might add is an "Upgrade Guide" of sorts. That could be done separately though. |
With Clearance 2.0 progressing, I was finally able to return to this. I made some major changes that are afforded by dropping support for older versions of Rails. We now no longer need the database for password reset tokens, so the resulting PR is simpler, I think. See #682. |
Overview:
Password reset tokens will now have an expiration date/time. By default, it
will be in 15 minutes. This is configurable via the
password_reset_time_limit
option.
Users can request a reset as many times as they wish. Once they "claim" a reset
with one of their tokens, all others will be invalidated (set as expired).
Details:
password_resets
.User
model. It's nowhandled at the controller level, referring to the
PasswordReset
andPasswordResetDeactivator
classes as needed.PasswordsController
toPasswordResetsController
later.
Clearance::Generators::Migration
to abstract common migration-related methodsThis has been tested on a repo that's currently using Clearance, and it seems to work fine. I plan on adding some info on the Wiki for anyone who's adding the expiration feature to their existing Clearance'd project.
Also, this is a huge PR. Suggestions on how to break this up would be great appreciated.
Fixes #465