Skip to content

MILESTONE -- Account Recovery #12

@jeturcotte

Description

@jeturcotte

For now, in the off chance someone forgets the password they'd used, they'll want a means of recovering it. For now we'll keep it simple and just offer a one time timed code via email. Some of the means for this should already have been accomplished through inventing a means of sending validation emails, so we'll build on that.

  • RESEARCH: Whether or not any of the following concepts are proffered already by CRO. It turns out a couple things in the past had been that I did not anticipate. I don't expect such in this case, but...
  • TASK: Build a new table 'password_reset' that stores temporary 'password update' tokens
    • Must have a field 'email' for the account email making the request
    • Must have a field 'token' for the randomly generated token representing this request - in mysql this would be a unique field but I don't know if sqlite supports that
    • Must have a field 'expired' for a datetime
  • TASK: Build a new POST endpoint servername.com/reset/request meant to accept the request to send out a password update token
    • Endpoint must be provided the login name or email address
    • Look up by whichever they send and find the account ... IF SO ::
      • Add a record to the new table :
        • Randomly generate a 9 character alphanumeric string (A-Za-z0-9) (in the future we can use this by other-than-email means, but we won't do those in first draft)
          • If sqllite does not support unique column constraints then you should loop through this process until a token is generated that is not already in the table (should almost never happen, but it CAN happen)
          • if sqlite DOES support unique column constraints (like mysql/postgres) then you can do this later during the insert when the db will error out and say 'i can't insert that' and try again with a newly generated token.
        • Select the email from the found account
        • Get the current time in the current timezone (these servers may be run wherever, so localism is important) and add 48 hours / 2 days to it. (we may make this configurable later, but for now, no need.)
        • Create a record in the newly created 'password_reset' table using the above
      • Send an email (in similar fashion to sending validation emails) to the account listed
        • Make a basic no-frills template email to fill in and send (variables in CAPS)
          • Oh, hey USERNAME
          • This is your password reset request mail
          • You have 48 hours to click this link
          • Heres the link. Click it
        • Fill in the template with some variables
          • pull username from the account that was found, pass it in
          • take the token that was created and inject it into a url servername.com/reset/response/TOKEN ... pass that to URL in the email template
        • Send the final result to EMAIL
        • Return a code 200 OK
    • IF NOT; rather, if there is no such account ::
      • Return a code 200 OK ...
        • we do this so we never confirm or deny the existence of any username or any email in our system ever.
  • TASK: Build a GET endpoint servername.com/reset/response/TOKEN
    meant to receive the URL sent along by any of these emails
    • Note that you are not YET going to look up the token
    • Collect the TOKEN and respond with a new page
      • Page has a form
      • Page has a field for new password and field for confirm password (don't worry about comparing them with javascript or anything at such an early stage)
      • Page has a hidden field for 'token' which is pre-filled with TOKEN from the url
      • Submit button please
  • TASK: Build a POST endpoint servername.com/reset/confirm
    • If any of the three fields between password, repeat, and token are missing, reply with 400 Bad Request error...
      • a future front end will know how to interpret that and dress it up, so no need to send anything more (same with the 200s above.)
    • Otherwise, if all three are submitted, but password and repeat fields don't match, reply with 422 Unprocessable Entity intead.
      • this is more specific than a vague 400; says 'your request has all the right parts but you didn't put the right stuff in them any' which we can interpret to mean the two didn't match
    • After that, use the token field to look up an entry it the password_reset table
      • If the token is present:
        • And the current datetime is BEFORE the expiration datetime
          • Update the account record with the new password
          • Delete the record from the password_reset table
          • Respond with 200 OK success
        • But if the expiration has passed...
          • Delete the record from the password_reset table
          • Respond with 410 Gone error
      • If the token is NOT present:
        • Respond with 410 Gone error
          • Again, this is so that a possible 'explorer' of our token database can't really learn if a fake token they make up exists
  • TEST...
    • I will write this later ... you are encouraged to THINK UP some tests for this (and put them in the comments first for me to double check) and if you are courageous, even try to write them first and develop the above work by bouncing them off these tests TDD style... but neither is required as eventually I'll have time to come back and add this section.

Metadata

Metadata

Labels

AuthenticationAny task tagged with this will add or modify authentication practicesEmail NotificationsAny task tagged with this will add or modify email-to-user functionalityUser AccountAny task tagged with this will add or modify user account functionality

Type

No type
No fields configured for issues without a type.

Projects

No projects

Relationships

None yet

Development

No branches or pull requests

Issue actions