-
Notifications
You must be signed in to change notification settings - Fork 116
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
Allow multiple USPS confirmation codes #1661
Conversation
@@ -9,7 +9,7 @@ def index | |||
@verify_account_form = VerifyAccountForm.new(user: current_user) | |||
|
|||
return unless FeatureManagement.reveal_usps_code? | |||
@code = JSON.parse(user_session[:decrypted_pii])['otp']['raw'] | |||
@code = session[:last_usps_confirmation_code] |
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.
I kept OTP prefilling by sticking the OTP in the session. It's a little bit brittle, so I also considered displaying it in flash message on the come back later screen. No problem making it work that way if we think that's better.
@@ -0,0 +1,16 @@ | |||
class UspsConfirmationCode < ApplicationRecord |
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.
I am definitely not in love with this name. It is a bit confusing since we have a UspsConfirmation
model. Happy to change it if someone has a better idea.
app/models/usps_confirmation_code.rb
Outdated
belongs_to :profile | ||
|
||
def self.find_with_otp(otp) | ||
find do |usps_confirmation_code| |
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.
I'm super unfamiliar with find
with a block --- is this a table scan?
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.
Oh I see this is used on a relation -- makes wayyyy more sense, but still used the wrong way could be a table scan.
Do you think it would be clearer if we made this a scope? Same result but hopefully it would make it more obvious to users that it's suppsed to be combined with other scopes and not just be a finder mehtod like our others (that are used for point queries)
scope :first_with_otp, ->(otp) { to_a.find { |usps_confirmation_code| ... } }
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.
Good idea 👍
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.
Hmm, this is turning out to be problematic since scopes have to return a relation and find
returns a record 🤔
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.
ah dangit, my bad. maybe just a rename to first_with_otp
will make it clearer it's not a point query
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.
Done ✅
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.
Some small questions, but no blockers, LGTM!
This does not include the logic about "only allow 3 in flight at a time" or anything, and we can add that later, right?
confirmation_maker.perform | ||
|
||
return unless FeatureManagement.reveal_usps_code? | ||
session[:last_usps_confirmation_code] = confirmation_maker.otp |
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.
CodeClimate is reporting this as not tested, do you think we should add test coverage? Since we expect to use this in our lower envs & development?
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.
👍. I'll write up a test
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.
@zachmargolis: I actually found a bug writing the test (yay!) and I had to do some wacky things in the idv review controller to surface the OTP and put in the session. Mind taking another look to lmk what you think?
create_table :usps_confirmation_codes do |t| | ||
t.integer :profile_id, null: false | ||
t.string :otp_fingerprint, null: false | ||
t.datetime :code_sent_at, null: false, default: ->{ 'CURRENT_TIMESTAMP' } |
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.
does this need to be a function? CURRENT_TIMESTAMP()
? Also does it need to be a proc or can it be a literal value?
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.
CURRENT_TIMESTAMP
is the Postgres syntax. It ends up becoming now()
in the schema. We have to use the proc because otherwise Rails tries to treat it like a primitive and sets the default to 'CURRENT_TIMESTAMP'
instead of CURRENT_TIMESTAMP
.
ref: rails/rails#27077
|
||
factory :usps_confirmation_code do | ||
profile | ||
sequence(:otp_fingerprint) { |n| Pii::Fingerprinter.fingerprint(n.to_s.rjust(6, '0')) } |
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.
there's no unique index ... would it be easier it we just fingerprinted a fixed value like '000000' or something? And we can override in tests where we need a specific value?
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.
Good catch. Originally I had a uniqueness constraint on this column before I realized that was a bad idea and this is leftover from that.
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.
LGTM!
**Why**: So that when a user resends a letter, it does not invalidate the USPS confirmation code in preceding letters. This means that if a user resends a letter before receiving their first letter, the code in the first letter can still be used to verify their account. **How**: This commit adds a new model named `UspsConfirmationCode`. This model is associated with a profile and has an asymmetrically encrypted OTP. When the user enters an OTP, the record with the matching OTP fingerprint is found. This is used to determine whether the entered OTP is valid for verifying their account.
5cdf174
to
5c3ea90
Compare
Why: So that when a user resends a letter, it does not invalidate
the USPS confirmation code in preceding letters. This means that if a
user resends a letter before receiving their first letter, the code in
the first letter can still be used to verify their account.
How: This commit adds a new model named
UspsConfirmationCode
. Thismodel is associated with a profile and has an asymmetrically encrypted
OTP. When the user enters an OTP, the record with the matching OTP
fingerprint is found. This is used to determine whether the entered OTP
is valid for verifying their account.