mirror of
https://github.com/maybe-finance/maybe.git
synced 2025-07-23 07:09:39 +02:00
Multi-factor authentication (#1817)
* Initial pass * Tests for MFA and locale cleanup * Brakeman * Update two-factor authentication status styling * Update app/models/user.rb Co-authored-by: Zach Gollwitzer <zach@maybe.co> Signed-off-by: Josh Pigford <josh@joshpigford.com> * Refactor MFA verification and session handling in tests --------- Signed-off-by: Josh Pigford <josh@joshpigford.com> Co-authored-by: Zach Gollwitzer <zach@maybe.co>
This commit is contained in:
parent
7ba9063e04
commit
842e37658c
29 changed files with 598 additions and 33 deletions
|
@ -70,4 +70,72 @@ class UserTest < ActiveSupport::TestCase
|
|||
assert_equal "Bob", @user.first_name
|
||||
assert_equal "Dylan", @user.last_name
|
||||
end
|
||||
|
||||
# MFA Tests
|
||||
test "setup_mfa! generates required fields" do
|
||||
user = users(:family_member)
|
||||
user.setup_mfa!
|
||||
|
||||
assert user.otp_secret.present?
|
||||
assert_not user.otp_required?
|
||||
assert_empty user.otp_backup_codes
|
||||
end
|
||||
|
||||
test "enable_mfa! enables MFA and generates backup codes" do
|
||||
user = users(:family_member)
|
||||
user.setup_mfa!
|
||||
user.enable_mfa!
|
||||
|
||||
assert user.otp_required?
|
||||
assert_equal 8, user.otp_backup_codes.length
|
||||
assert user.otp_backup_codes.all? { |code| code.length == 8 }
|
||||
end
|
||||
|
||||
test "disable_mfa! removes all MFA data" do
|
||||
user = users(:family_member)
|
||||
user.setup_mfa!
|
||||
user.enable_mfa!
|
||||
user.disable_mfa!
|
||||
|
||||
assert_nil user.otp_secret
|
||||
assert_not user.otp_required?
|
||||
assert_empty user.otp_backup_codes
|
||||
end
|
||||
|
||||
test "verify_otp? validates TOTP codes" do
|
||||
user = users(:family_member)
|
||||
user.setup_mfa!
|
||||
|
||||
totp = ROTP::TOTP.new(user.otp_secret, issuer: "Maybe")
|
||||
valid_code = totp.now
|
||||
|
||||
assert user.verify_otp?(valid_code)
|
||||
assert_not user.verify_otp?("invalid")
|
||||
assert_not user.verify_otp?("123456")
|
||||
end
|
||||
|
||||
test "verify_otp? accepts backup codes" do
|
||||
user = users(:family_member)
|
||||
user.setup_mfa!
|
||||
user.enable_mfa!
|
||||
|
||||
backup_code = user.otp_backup_codes.first
|
||||
assert user.verify_otp?(backup_code)
|
||||
|
||||
# Backup code should be consumed
|
||||
assert_not user.otp_backup_codes.include?(backup_code)
|
||||
assert_equal 7, user.otp_backup_codes.length
|
||||
|
||||
# Used backup code should not work again
|
||||
assert_not user.verify_otp?(backup_code)
|
||||
end
|
||||
|
||||
test "provisioning_uri generates correct URI" do
|
||||
user = users(:family_member)
|
||||
user.setup_mfa!
|
||||
|
||||
assert_match %r{otpauth://totp/}, user.provisioning_uri
|
||||
assert_match %r{secret=#{user.otp_secret}}, user.provisioning_uri
|
||||
assert_match %r{issuer=Maybe}, user.provisioning_uri
|
||||
end
|
||||
end
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue