From 6317f6225b1edc2160d7a292922be48849a99ba2 Mon Sep 17 00:00:00 2001 From: Stephen Paul Weber Date: Wed, 12 Apr 2023 15:48:12 -0500 Subject: [PATCH] Move too-many-tries guard into the repo --- lib/invites_repo.rb | 23 ++++++++++++++++++++--- lib/registration.rb | 19 +++---------------- test/test_registration.rb | 27 +++++++++++++-------------- 3 files changed, 36 insertions(+), 33 deletions(-) diff --git a/lib/invites_repo.rb b/lib/invites_repo.rb index a4dac5dbadf1991665afd62534066eca47e44730..fd4ba71f50367fdf728ef60366538147dc8dc97e 100644 --- a/lib/invites_repo.rb +++ b/lib/invites_repo.rb @@ -3,8 +3,9 @@ class InvitesRepo class Invalid < StandardError; end - def initialize(db=DB) + def initialize(db=DB, redis=REDIS) @db = db + @redis = redis end def unused_invites(customer_id) @@ -15,13 +16,13 @@ class InvitesRepo end def claim_code(customer_id, code, &blk) - EMPromise.resolve(nil).then do + guard_too_many_tries(customer_id).then do @db.transaction do valid = @db.exec(<<~SQL, [customer_id, code]).cmd_tuples.positive? UPDATE invites SET used_by_id=$1, used_at=LOCALTIMESTAMP WHERE code=$2 AND used_by_id IS NULL SQL - raise Invalid, "Not a valid invite code: #{code}" unless valid + invalid_code(customer_id, code).sync unless valid blk.call end @@ -76,4 +77,20 @@ class InvitesRepo SQL } end + +protected + + def guard_too_many_tries(customer_id) + @redis.get("jmp_invite_tries-#{customer_id}").then do |t| + raise Invalid, "Too many wrong attempts" if t.to_i > 10 + end + end + + def invalid_code(customer_id, code) + @redis.incr("jmp_invite_tries-#{customer_id}").then { + @redis.expire("jmp_invite_tries-#{customer_id}", 60 * 60) + }.then do + raise Invalid, "Not a valid invite code: #{code}" + end + end end diff --git a/lib/registration.rb b/lib/registration.rb index 8327848d7ffefcd528d15e0cc1329d0fe4d2aaa4..5b26ac77f58842516c59d633c5c38ba0415bf93e 100644 --- a/lib/registration.rb +++ b/lib/registration.rb @@ -434,28 +434,15 @@ class Registration def parse(iq) return Activation.for(@customer, nil, @tel).then(&:write) if iq.prev? - guard_too_many_tries.then { - verify(iq.form.field("code")&.value&.to_s) - }.then { + verify(iq.form.field("code")&.value&.to_s).then { Finish.new(@customer, @tel) }.catch_only(InvitesRepo::Invalid, &method(:invalid_code)).then(&:write) end protected - def guard_too_many_tries - REDIS.get("jmp_invite_tries-#{customer_id}").then do |t| - raise InvitesRepo::Invalid, "Too many wrong attempts" if t.to_i > 10 - end - end - def invalid_code(e) - EMPromise.all([ - REDIS.incr("jmp_invite_tries-#{customer_id}").then do - REDIS.expire("jmp_invite_tries-#{customer_id}", 60 * 60) - end, - InviteCode.new(@customer, @tel, error: e.message) - ]).then(&:last) + InviteCode.new(@customer, @tel, error: e.message) end def customer_id @@ -463,7 +450,7 @@ class Registration end def verify(code) - InvitesRepo.new(DB).claim_code(customer_id, code) do + InvitesRepo.new(DB, REDIS).claim_code(customer_id, code) do @customer.activate_plan_starting_now end end diff --git a/test/test_registration.rb b/test/test_registration.rb index 47623104673096bc7477e3b38348a1c78a9c9f81..7e739206e310b3643bd04e674cf80a23b4600888 100644 --- a/test/test_registration.rb +++ b/test/test_registration.rb @@ -628,9 +628,15 @@ class RegistrationTest < Minitest::Test EMPromise.resolve(0), ["jmp_invite_tries-test"] ) - Registration::Payment::InviteCode::DB.expect(:transaction, []) do - raise InvitesRepo::Invalid, "wut" - end + Registration::Payment::InviteCode::DB.expect( + :transaction, + [] + ) { |&blk| blk.call } + Registration::Payment::InviteCode::DB.expect( + :exec, + OpenStruct.new(cmd_tuples: 0), + [String, ["test", "abc"]] + ) Registration::Payment::InviteCode::REDIS.expect( :incr, EMPromise.resolve(nil), @@ -658,7 +664,10 @@ class RegistrationTest < Minitest::Test EMPromise.reject(:test_result), [Matching.new do |reply| assert_equal :form, reply.form.type - assert_equal "wut", reply.form.instructions + assert_equal( + "Not a valid invite code: abc", + reply.form.instructions + ) end] ) @@ -694,16 +703,6 @@ class RegistrationTest < Minitest::Test assert_nil reply.form.instructions end] ) - Registration::Payment::InviteCode::REDIS.expect( - :incr, - EMPromise.resolve(nil), - ["jmp_invite_tries-test"] - ) - Registration::Payment::InviteCode::REDIS.expect( - :expire, - EMPromise.resolve(nil), - ["jmp_invite_tries-test", 60 * 60] - ) Command::COMMAND_MANAGER.expect( :write, EMPromise.reject(:test_result),