chore: checkpoint before Python removal

This commit is contained in:
2026-03-26 22:33:59 +00:00
parent 683cec9307
commit e568ddf82a
29972 changed files with 11269302 additions and 2 deletions

38
vendor/password-hash/tests/encoding.rs vendored Normal file
View File

@@ -0,0 +1,38 @@
//! Base64 encoding tests.
//!
//! # B64 Notes
//!
//! "B64" is a ubset of the standard Base64 encoding (RFC 4648, section 4) which
//! omits padding (`=`) as well as extra whitespace, as described in the PHC
//! string format specification:
//!
//! <https://github.com/P-H-C/phc-string-format/blob/master/phc-sf-spec.md#b64>
use password_hash::{Output, Salt};
// Example salt encoded as a B64 string.
const EXAMPLE_SALT_B64: &str = "REVBREJFRUZERUFEQkVFRg";
const EXAMPLE_SALT_RAW: &[u8] = b"DEADBEEFDEADBEEF";
// Example PHF output encoded as a B64 string.
const EXAMPLE_OUTPUT_B64: &str =
"REVBREJFRUZERUFEQkVFRkRFQURCRUVGREVBREJFRUZERUFEQkVFRkRFQURCRUVGREVBREJFRUZERUFEQkVFRg";
const EXAMPLE_OUTPUT_RAW: &[u8] =
b"DEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEF";
#[test]
fn salt_roundtrip() {
let mut buffer = [0u8; 64];
let salt = Salt::from_b64(EXAMPLE_SALT_B64).unwrap();
assert_eq!(salt.as_ref(), EXAMPLE_SALT_B64);
let salt_decoded = salt.decode_b64(&mut buffer).unwrap();
assert_eq!(salt_decoded, EXAMPLE_SALT_RAW);
}
#[test]
fn output_roundtrip() {
let out = EXAMPLE_OUTPUT_B64.parse::<Output>().unwrap();
assert_eq!(out.as_ref(), EXAMPLE_OUTPUT_RAW);
assert_eq!(out.to_string(), EXAMPLE_OUTPUT_B64);
}

88
vendor/password-hash/tests/hashing.rs vendored Normal file
View File

@@ -0,0 +1,88 @@
//! Password hashing tests
pub use password_hash::{
Decimal, Error, Ident, Output, ParamsString, PasswordHash, PasswordHasher, Result, Salt,
};
const ALG: Ident = Ident::new_unwrap("example");
/// Stub password hashing function for testing.
pub struct StubPasswordHasher;
impl PasswordHasher for StubPasswordHasher {
type Params = StubParams;
fn hash_password_customized<'a>(
&self,
password: &[u8],
algorithm: Option<Ident<'a>>,
version: Option<Decimal>,
params: StubParams,
salt: impl Into<Salt<'a>>,
) -> Result<PasswordHash<'a>> {
let salt = salt.into();
let mut output = Vec::new();
if let Some(alg) = algorithm {
if alg != ALG {
return Err(Error::Algorithm);
}
}
for slice in &[b"pw", password, b",salt:", salt.as_str().as_bytes()] {
output.extend_from_slice(slice);
}
let hash = Output::new(&output)?;
Ok(PasswordHash {
algorithm: ALG,
version,
params: params.try_into()?,
salt: Some(salt),
hash: Some(hash),
})
}
}
/// Stub parameters
#[derive(Clone, Debug, Default)]
pub struct StubParams;
impl<'a> TryFrom<&PasswordHash<'a>> for StubParams {
type Error = Error;
fn try_from(_: &PasswordHash<'a>) -> Result<Self> {
Ok(Self)
}
}
impl<'a> TryFrom<StubParams> for ParamsString {
type Error = Error;
fn try_from(_: StubParams) -> Result<Self> {
Ok(Self::default())
}
}
#[test]
fn verify_password_hash() {
let valid_password = "test password";
let salt = Salt::from_b64("test-salt").unwrap();
let hash = PasswordHash::generate(StubPasswordHasher, valid_password, salt).unwrap();
// Sanity tests for StubFunction impl above
assert_eq!(hash.algorithm, ALG);
assert_eq!(hash.salt.unwrap(), salt);
// Tests for generic password verification logic
assert_eq!(
hash.verify_password(&[&StubPasswordHasher], valid_password),
Ok(())
);
assert_eq!(
hash.verify_password(&[&StubPasswordHasher], "wrong password"),
Err(Error::Password)
);
}

View File

@@ -0,0 +1,146 @@
//! Tests for `PasswordHash` encoding/decoding.
//!
//! Each test implements a different permutation of the possible combinations
//! of the string encoding, and ensures password hashes round trip under each
//! of the conditions.
use password_hash::{Ident, ParamsString, PasswordHash, Salt};
const EXAMPLE_ALGORITHM: Ident = Ident::new_unwrap("argon2d");
const EXAMPLE_SALT: &str = "saltsaltsaltsaltsalt";
const EXAMPLE_HASH: &[u8] = &[
0x85, 0xab, 0x21, 0x85, 0xab, 0x21, 0x85, 0xab, 0x21, 0x85, 0xab, 0x21, 0x85, 0xab, 0x21, 0x85,
0xab, 0x21, 0x85, 0xab, 0x21, 0x85, 0xab, 0x21, 0x85, 0xab, 0x21, 0x85, 0xab, 0x21, 0x85, 0xab,
];
/// Example parameters
fn example_params() -> ParamsString {
let mut params = ParamsString::new();
params.add_decimal("a", 1).unwrap();
params.add_decimal("b", 2).unwrap();
params.add_decimal("c", 3).unwrap();
params
}
#[test]
fn algorithm_alone() {
let ph = PasswordHash::new("$argon2d").unwrap();
assert_eq!(ph.algorithm, EXAMPLE_ALGORITHM);
let s = ph.to_string();
assert_eq!(s, "$argon2d");
let ph2 = PasswordHash::try_from(s.as_str()).unwrap();
assert_eq!(ph, ph2);
}
#[test]
fn params() {
let ph = PasswordHash {
algorithm: EXAMPLE_ALGORITHM,
version: None,
params: example_params(),
salt: None,
hash: None,
};
let s = ph.to_string();
assert_eq!(s, "$argon2d$a=1,b=2,c=3");
let ph2 = PasswordHash::try_from(s.as_str()).unwrap();
assert_eq!(ph, ph2);
}
#[test]
fn salt() {
let ph = PasswordHash {
algorithm: EXAMPLE_ALGORITHM,
version: None,
params: ParamsString::new(),
salt: Some(Salt::from_b64(EXAMPLE_SALT).unwrap()),
hash: None,
};
let s = ph.to_string();
assert_eq!(s, "$argon2d$saltsaltsaltsaltsalt");
let ph2 = PasswordHash::try_from(s.as_str()).unwrap();
assert_eq!(ph, ph2);
}
#[test]
fn one_param_and_salt() {
let mut params = ParamsString::new();
params.add_decimal("a", 1).unwrap();
let ph = PasswordHash {
algorithm: EXAMPLE_ALGORITHM,
version: None,
params,
salt: Some(Salt::from_b64(EXAMPLE_SALT).unwrap()),
hash: None,
};
let s = ph.to_string();
assert_eq!(s, "$argon2d$a=1$saltsaltsaltsaltsalt");
let ph2 = PasswordHash::try_from(s.as_str()).unwrap();
assert_eq!(ph, ph2);
}
#[test]
fn params_and_salt() {
let ph = PasswordHash {
algorithm: EXAMPLE_ALGORITHM,
version: None,
params: example_params(),
salt: Some(Salt::from_b64(EXAMPLE_SALT).unwrap()),
hash: None,
};
let s = ph.to_string();
assert_eq!(s, "$argon2d$a=1,b=2,c=3$saltsaltsaltsaltsalt");
let ph2 = PasswordHash::try_from(s.as_str()).unwrap();
assert_eq!(ph, ph2);
}
#[test]
fn salt_and_hash() {
let ph = PasswordHash {
algorithm: EXAMPLE_ALGORITHM,
version: None,
params: ParamsString::default(),
salt: Some(Salt::from_b64(EXAMPLE_SALT).unwrap()),
hash: Some(EXAMPLE_HASH.try_into().unwrap()),
};
let s = ph.to_string();
assert_eq!(
s,
"$argon2d$saltsaltsaltsaltsalt$hashhashhashhashhashhashhashhashhashhashhas"
);
let ph2 = PasswordHash::try_from(s.as_str()).unwrap();
assert_eq!(ph, ph2);
}
#[test]
fn all_fields() {
let ph = PasswordHash {
algorithm: EXAMPLE_ALGORITHM,
version: None,
params: example_params(),
salt: Some(Salt::from_b64(EXAMPLE_SALT).unwrap()),
hash: Some(EXAMPLE_HASH.try_into().unwrap()),
};
let s = ph.to_string();
assert_eq!(
s,
"$argon2d$a=1,b=2,c=3$saltsaltsaltsaltsalt$hashhashhashhashhashhashhashhashhashhashhas"
);
let ph2 = PasswordHash::try_from(s.as_str()).unwrap();
assert_eq!(ph, ph2);
}

View File

@@ -0,0 +1,51 @@
//! Test vectors for commonly used password hashing algorithms.
use password_hash::{Ident, PasswordHash};
const ARGON2D_HASH: &str =
"$argon2d$v=19$m=512,t=3,p=2$5VtWOO3cGWYQHEMaYGbsfQ$AcmqasQgW/wI6wAHAMk4aQ";
const BCRYPT_HASH: &str = "$2b$MTIzNA$i5btSOiulHhaPHPbgNUGdObga/GCAVG/y5HHY1ra7L0C9dpCaw8u";
const SCRYPT_HASH: &str =
"$scrypt$epIxT/h6HbbwHaehFnh/bw$7H0vsXlY8UxxyW/BWx/9GuY7jEvGjT71GFd6O4SZND0";
#[test]
fn argon2id() {
let ph = PasswordHash::new(ARGON2D_HASH).unwrap();
assert_eq!(ph.algorithm, Ident::new("argon2d").unwrap());
assert_eq!(ph.version, Some(19));
assert_eq!(ph.params.iter().count(), 3);
assert_eq!(ph.params.get_decimal("m").unwrap(), 512);
assert_eq!(ph.params.get_decimal("t").unwrap(), 3);
assert_eq!(ph.params.get_decimal("p").unwrap(), 2);
assert_eq!(ph.salt.unwrap().as_ref(), "5VtWOO3cGWYQHEMaYGbsfQ");
assert_eq!(ph.hash.unwrap().to_string(), "AcmqasQgW/wI6wAHAMk4aQ");
assert_eq!(ph.to_string(), ARGON2D_HASH);
}
#[test]
fn bcrypt() {
let ph = PasswordHash::new(BCRYPT_HASH).unwrap();
assert_eq!(ph.algorithm, Ident::new("2b").unwrap());
assert_eq!(ph.version, None);
assert_eq!(ph.params.len(), 0);
assert_eq!(ph.salt.unwrap().to_string(), "MTIzNA");
assert_eq!(
ph.hash.unwrap().to_string(),
"i5btSOiulHhaPHPbgNUGdObga/GCAVG/y5HHY1ra7L0C9dpCaw8u"
);
assert_eq!(ph.to_string(), BCRYPT_HASH);
}
#[test]
fn scrypt() {
let ph = PasswordHash::new(SCRYPT_HASH).unwrap();
assert_eq!(ph.algorithm, Ident::new("scrypt").unwrap());
assert_eq!(ph.version, None);
assert_eq!(ph.params.len(), 0);
assert_eq!(ph.salt.unwrap().to_string(), "epIxT/h6HbbwHaehFnh/bw");
assert_eq!(
ph.hash.unwrap().to_string(),
"7H0vsXlY8UxxyW/BWx/9GuY7jEvGjT71GFd6O4SZND0"
);
assert_eq!(ph.to_string(), SCRYPT_HASH);
}