@@ 313,16 313,33 @@ class Registration
def write
COMMAND_MANAGER.write(@reply).then do |iq|
- verify(iq.form.field("code")&.value&.to_s).then {
+ guard_too_many_tries.then {
+ verify(iq.form.field("code")&.value&.to_s)
+ }.then {
Finish.new(iq, @customer, @tel)
}.catch_only(Invalid) { |e|
- InviteCode.new(iq, @customer, @tel, error: e.message)
+ invalid_code(iq, e)
}.then(&:write)
end
end
protected
+ def guard_too_many_tries
+ REDIS.get("jmp_invite_tries-#{@customer.customer_id}").then do |t|
+ raise Invalid, "Too many wrong attempts" if t > 10
+ end
+ end
+
+ def invalid_code(iq, e)
+ EMPromise.all([
+ REDIS.incr("jmp_invite_tries-#{@customer.customer_id}").then do
+ REDIS.expire("jmp_invite_tries-#{@customer.customer_id}", 60 * 60)
+ end,
+ InviteCode.new(iq, @customer, @tel, error: e.message)
+ ]).then(&:last)
+ end
+
def customer_id
@customer.customer_id
end
@@ 342,6 342,8 @@ class RegistrationTest < Minitest::Test
class InviteCodeTest < Minitest::Test
Registration::Payment::InviteCode::DB =
Minitest::Mock.new
+ Registration::Payment::InviteCode::REDIS =
+ Minitest::Mock.new
Registration::Payment::InviteCode::COMMAND_MANAGER =
Minitest::Mock.new
Registration::Payment::InviteCode::Finish =
@@ 349,6 351,11 @@ class RegistrationTest < Minitest::Test
def test_write
customer = Customer.new("test", plan_name: "test_usd")
+ Registration::Payment::InviteCode::REDIS.expect(
+ :get,
+ EMPromise.resolve(0),
+ ["jmp_invite_tries-test"]
+ )
Registration::Payment::InviteCode::COMMAND_MANAGER.expect(
:write,
EMPromise.resolve(
@@ 380,12 387,18 @@ class RegistrationTest < Minitest::Test
).write.sync
Registration::Payment::InviteCode::COMMAND_MANAGER.verify
Registration::Payment::InviteCode::DB.verify
+ Registration::Payment::InviteCode::REDIS.verify
Registration::Payment::InviteCode::Finish.verify
end
em :test_write
def test_write_bad_code
customer = Customer.new("test", plan_name: "test_usd")
+ Registration::Payment::InviteCode::REDIS.expect(
+ :get,
+ EMPromise.resolve(0),
+ ["jmp_invite_tries-test"]
+ )
Registration::Payment::InviteCode::COMMAND_MANAGER.expect(
:write,
EMPromise.resolve(
@@ 401,6 414,16 @@ class RegistrationTest < Minitest::Test
Registration::Payment::InviteCode::DB.expect(:transaction, []) do
raise Registration::Payment::InviteCode::Invalid, "wut"
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]
+ )
Registration::Payment::InviteCode::COMMAND_MANAGER.expect(
:write,
EMPromise.reject(Promise::Error.new),
@@ 420,9 443,60 @@ class RegistrationTest < Minitest::Test
end
Registration::Payment::InviteCode::COMMAND_MANAGER.verify
Registration::Payment::InviteCode::DB.verify
- Registration::Payment::InviteCode::Finish.verify
+ Registration::Payment::InviteCode::REDIS.verify
end
em :test_write_bad_code
+
+ def test_write_bad_code_over_limit
+ customer = Customer.new("test", plan_name: "test_usd")
+ Registration::Payment::InviteCode::REDIS.expect(
+ :get,
+ EMPromise.resolve(11),
+ ["jmp_invite_tries-test"]
+ )
+ Registration::Payment::InviteCode::COMMAND_MANAGER.expect(
+ :write,
+ EMPromise.resolve(
+ Blather::Stanza::Iq::Command.new.tap { |iq|
+ iq.form.fields = [{ var: "code", value: "abc" }]
+ }
+ ),
+ [Matching.new do |reply|
+ assert_equal :form, reply.form.type
+ 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]
+ )
+ Registration::Payment::InviteCode::COMMAND_MANAGER.expect(
+ :write,
+ EMPromise.reject(Promise::Error.new),
+ [Matching.new do |reply|
+ assert_equal :form, reply.form.type
+ assert_equal "Too many wrong attempts", reply.form.instructions
+ end]
+ )
+ iq = Blather::Stanza::Iq::Command.new
+ iq.from = "test@example.com"
+ assert_raises Promise::Error do
+ Registration::Payment::InviteCode.new(
+ iq,
+ customer,
+ "+15555550000"
+ ).write.sync
+ end
+ Registration::Payment::InviteCode::COMMAND_MANAGER.verify
+ Registration::Payment::InviteCode::REDIS.verify
+ end
+ em :test_write_bad_code_over_limit
end
end