Files
ubicloud/spec/routes/web/account_spec.rb
Jeremy Evans 4e76b20b27 Add coverage and fix issues in account/multifactor views
Fixes:

* Fix invalid HTML on recovery code page, caused by nesting h2 in h2

* Remove rodauth.otp_keys_use_hmac? branch, since that is always true in
  our Rodauth configuration.

I moved the closing nocov for Config.test? specific routes to ensure that
those are covered in tests (still need nocov to handle the implied else
branch not taken).

After changes (rebased on main since last commit, so totals have changed):

Line Coverage: 99.39% (11192 / 11261)
Branch Coverage: 97.0% (2841 / 2929)
2025-01-14 09:04:22 -08:00

141 lines
6.3 KiB
Ruby

# frozen_string_literal: true
require_relative "spec_helper"
require "webauthn/fake_client"
RSpec.describe Clover, "account" do
it "can not access without login" do
visit "/account"
expect(page.title).to eq("Ubicloud - Login")
end
describe "authenticated" do
before do
create_account
login
end
it "show password change page" do
visit "/account/change-password"
expect(page.title).to eq("Ubicloud - Change Password")
expect(page).to have_content "Change Password"
end
[true, false].each do |clear_last_password_entry|
it "allows setting up and removing OTP authentication when password entry is #{"not " unless clear_last_password_entry}required" do
visit "/clear-last-password-entry" if clear_last_password_entry
visit "/account/multifactor-manage"
expect(page.title).to eq("Ubicloud - Multifactor Authentication")
click_link "Enable"
expect(page.title).to eq("Ubicloud - Setup One-Time Password")
totp = ROTP::TOTP.new(find_by_id("otp-secret").text)
fill_in "Authentication Code", with: totp.now
fill_in "Password", with: TEST_USER_PASSWORD if clear_last_password_entry
click_button "Enable One-Time Password Authentication"
expect(page).to have_flash_notice "One-time password authentication is now setup, please make note of your recovery codes"
expect(page.title).to eq("Ubicloud - Recovery Codes")
visit "/clear-last-password-entry" if clear_last_password_entry
visit "/account/multifactor-manage"
click_link "Disable"
expect(page.title).to eq("Ubicloud - Disable One-Time Password")
fill_in "Password", with: TEST_USER_PASSWORD if clear_last_password_entry
click_button "Disable One-Time Password Authentication"
expect(page).to have_flash_notice "One-time password authentication has been disabled"
end
it "allows setting up and removing Webauthn authentication when password entry is #{"not " unless clear_last_password_entry}required" do
2.times do |i|
visit "/clear-last-password-entry" if clear_last_password_entry
visit "/account/multifactor-manage"
expect(page.title).to eq("Ubicloud - Multifactor Authentication")
click_link "Add"
expect(page.title).to eq("Ubicloud - Setup Security Key")
webauthn_client = WebAuthn::FakeClient.new("http://www.example.com")
challenge = JSON.parse(page.find_by_id("webauthn-setup-form")["data-credential-options"])["challenge"]
fill_in "Key Name", with: "My Key #{i}"
fill_in "Password", with: TEST_USER_PASSWORD if clear_last_password_entry
fill_in "webauthn-setup", with: webauthn_client.create(challenge: challenge).to_json, visible: false
click_button "Setup Security Key"
expect(page).to have_flash_notice "Security key is now setup, please make note of your recovery codes"
expect(page.title).to eq("Ubicloud - Recovery Codes")
end
DB.transaction(rollback: :always) do
visit "/clear-last-password-entry" if clear_last_password_entry
visit "/account/multifactor-manage"
click_link "Remove"
expect(page.title).to eq("Ubicloud - Remove Security Key")
DB[:account_webauthn_keys].where(name: "My Key 1").delete
fill_in "Password", with: TEST_USER_PASSWORD if clear_last_password_entry
choose "My Key 1"
click_button "Remove Security Key"
end
expect(page).to have_flash_error "Error removing security key"
expect(find_by_id("webauthn_remove-error").text).to eq "Invalid security key to remove"
visit "/clear-last-password-entry" if clear_last_password_entry
visit "/account/multifactor-manage"
click_link "Remove"
fill_in "Password", with: TEST_USER_PASSWORD if clear_last_password_entry
choose "My Key 1"
click_button "Remove Security Key"
expect(page).to have_flash_notice "Security key has been removed"
end
end
it "allows viewing and regenerating recovery codes" do
visit "/account/multifactor-manage"
click_link "Enable"
totp = ROTP::TOTP.new(find_by_id("otp-secret").text)
fill_in "Authentication Code", with: totp.now
click_button "Enable One-Time Password Authentication"
path = page.current_path
visit "/clear-last-password-entry"
visit path
fill_in "Password", with: TEST_USER_PASSWORD
click_button "View Authentication Recovery Codes"
recovery_codes = DB[:account_recovery_codes].select_map(:code)
expect(page.all("#recovery-codes-text div").map(&:text).sort).to eq recovery_codes.sort
DB[:account_recovery_codes].delete
visit path
expect(page.all("#recovery-codes-text div").to_a).to be_empty
click_button "Add Authentication Recovery Codes"
recovery_codes = DB[:account_recovery_codes].select_map(:code)
expect(page.all("#recovery-codes-text div").map(&:text).sort).to eq recovery_codes.sort
end
it "allows removing all multifactor authentication methods" do
visit "/account/multifactor-manage"
click_link "Enable"
totp = ROTP::TOTP.new(find_by_id("otp-secret").text)
fill_in "Authentication Code", with: totp.now
click_button "Enable One-Time Password Authentication"
expect(page).to have_flash_notice "One-time password authentication is now setup, please make note of your recovery codes"
visit "/account/multifactor-manage"
click_link "Add"
webauthn_client = WebAuthn::FakeClient.new("http://www.example.com")
challenge = JSON.parse(page.find_by_id("webauthn-setup-form")["data-credential-options"])["challenge"]
fill_in "Key Name", with: "My Key"
fill_in "webauthn-setup", with: webauthn_client.create(challenge: challenge).to_json, visible: false
click_button "Setup Security Key"
visit "/account/multifactor-manage"
click_link "Remove All Multifactor Authentication Methods"
expect(page.title).to eq("Ubicloud - Remove All Multifactor Authentication Methods")
click_button "Remove All Multifactor Authentication Methods"
expect(page).to have_flash_notice "All multifactor authentication methods have been disabled"
end
end
end