2024-06-04 03:42:53 -04:00
|
|
|
# frozen_string_literal: true
|
|
|
|
|
|
|
|
RSpec.describe UserPassword do
|
2024-10-20 19:24:43 -04:00
|
|
|
describe "#ensure_password_is_hashed" do
|
|
|
|
let(:password) { SecureRandom.hex }
|
|
|
|
fab!(:user_password)
|
|
|
|
|
|
|
|
it "ensures password_hash, password_salt, password_algorithm are saved correctly" do
|
|
|
|
user_password.update!(password:)
|
|
|
|
|
|
|
|
expect(user_password.password_salt).not_to be_nil
|
|
|
|
expect(user_password.password_algorithm).to eq(UserPassword::TARGET_PASSWORD_ALGORITHM)
|
|
|
|
new_hash =
|
|
|
|
described_class.new.send(
|
|
|
|
:hash_password,
|
|
|
|
password,
|
|
|
|
user_password.password_salt,
|
|
|
|
user_password.password_algorithm,
|
|
|
|
)
|
|
|
|
expect(user_password.password_hash).to eq(new_hash)
|
|
|
|
end
|
|
|
|
|
|
|
|
it "does not hash the password if no password given" do
|
|
|
|
expect { user_password.update!(password: nil) }.not_to change(user_password, :password_hash)
|
|
|
|
end
|
|
|
|
|
|
|
|
context "when password was expired" do
|
|
|
|
fab!(:expired_user_password)
|
|
|
|
|
|
|
|
it "resets expired password to nil when saving new password" do
|
|
|
|
expect { expired_user_password.update!(password: SecureRandom.hex) }.to change(
|
|
|
|
expired_user_password,
|
|
|
|
:password_expired_at,
|
|
|
|
).to(nil)
|
|
|
|
end
|
|
|
|
|
|
|
|
it "does not remove password_expired_at if no password given" do
|
|
|
|
expect { expired_user_password.update!(password: nil) }.not_to change(
|
|
|
|
user_password,
|
|
|
|
:password_expired_at,
|
|
|
|
)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2024-10-09 21:23:06 -04:00
|
|
|
describe "#confirm_password?" do
|
|
|
|
context "when input password is same as saved password" do
|
|
|
|
let(:pw) { SecureRandom.hex }
|
|
|
|
|
|
|
|
it "returns true after saving password for the first time" do
|
|
|
|
u = Fabricate(:user, password: nil)
|
|
|
|
u.password = pw
|
|
|
|
u.save!
|
|
|
|
expect(u.confirm_password?(pw)).to eq true
|
|
|
|
end
|
|
|
|
|
|
|
|
it "returns true after updating existing password" do
|
|
|
|
pw = SecureRandom.hex
|
|
|
|
u = Fabricate(:user, password: "initial_password_123")
|
|
|
|
u.update!(password: pw)
|
|
|
|
expect(u.confirm_password?(pw)).to eq true
|
|
|
|
end
|
|
|
|
|
|
|
|
it "updates the algorithm if it's outdated and password_hash, and returns true" do
|
|
|
|
user_password = Fabricate(:user, password: pw).user_password
|
|
|
|
old_algorithm = "$pbkdf2-sha256$i=5,l=32$"
|
|
|
|
old_hash =
|
|
|
|
described_class.new.send(:hash_password, pw, user_password.password_salt, old_algorithm)
|
|
|
|
user_password.update_columns(password_algorithm: old_algorithm, password_hash: old_hash)
|
|
|
|
|
|
|
|
result = nil
|
|
|
|
expect { result = user_password.confirm_password?(pw) }.to change {
|
|
|
|
user_password.password_algorithm
|
|
|
|
}.from(old_algorithm).to(described_class::TARGET_PASSWORD_ALGORITHM)
|
|
|
|
expect(result).to eq true
|
|
|
|
|
|
|
|
new_hash =
|
|
|
|
described_class.new.send(
|
|
|
|
:hash_password,
|
|
|
|
pw,
|
|
|
|
user_password.password_salt,
|
|
|
|
user_password.password_algorithm,
|
|
|
|
)
|
|
|
|
expect(user_password.password_hash).to eq(new_hash)
|
|
|
|
end
|
2024-06-04 03:42:53 -04:00
|
|
|
end
|
|
|
|
|
2024-10-09 21:23:06 -04:00
|
|
|
context "when input password is not the same as saved password" do
|
|
|
|
let(:actual_pw) { SecureRandom.hex }
|
2024-06-04 03:42:53 -04:00
|
|
|
|
2024-10-09 21:23:06 -04:00
|
|
|
it "returns false" do
|
|
|
|
u = Fabricate(:user, password: actual_pw)
|
|
|
|
expect(u.confirm_password?(SecureRandom.hex)).to eq false
|
|
|
|
end
|
2024-06-04 03:42:53 -04:00
|
|
|
end
|
|
|
|
|
2024-10-09 21:23:06 -04:00
|
|
|
context "when used on an unpersisted record" do
|
|
|
|
it "returns false" do
|
|
|
|
user_password = Fabricate.build(:user_password, user: nil)
|
|
|
|
expect(user_password.confirm_password?(user_password.password)).to eq false
|
|
|
|
end
|
2024-06-04 03:42:53 -04:00
|
|
|
end
|
2024-10-09 21:23:06 -04:00
|
|
|
end
|
2024-06-04 03:42:53 -04:00
|
|
|
|
2024-10-09 21:23:06 -04:00
|
|
|
context "for validations" do
|
|
|
|
it "should validate presence of user_id" do
|
|
|
|
user_password = Fabricate.build(:user_password, user: nil)
|
2024-06-04 03:42:53 -04:00
|
|
|
|
|
|
|
expect(user_password).not_to be_valid
|
2024-10-09 21:23:06 -04:00
|
|
|
expect(user_password.errors[:user]).to include("must exist")
|
2024-06-04 03:42:53 -04:00
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|