hash pasword types fix
This commit is contained in:
@@ -13,8 +13,8 @@ describe("hashPassword", () => {
|
|||||||
expect(parts[1]).toBe("pbkdf2-sha256");
|
expect(parts[1]).toBe("pbkdf2-sha256");
|
||||||
expect(parts[2]).toBe("100000");
|
expect(parts[2]).toBe("100000");
|
||||||
// Salt and hash should be non-empty base64 strings
|
// Salt and hash should be non-empty base64 strings
|
||||||
expect(parts[3].length).toBeGreaterThan(0);
|
expect(parts[3]?.length).toBeGreaterThan(0);
|
||||||
expect(parts[4].length).toBeGreaterThan(0);
|
expect(parts[4]?.length).toBeGreaterThan(0);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should generate different hashes for the same password", async () => {
|
it("should generate different hashes for the same password", async () => {
|
||||||
@@ -98,4 +98,66 @@ describe("verifyPassword", () => {
|
|||||||
const wrongResult = await verifyPassword("password", hash);
|
const wrongResult = await verifyPassword("password", hash);
|
||||||
expect(wrongResult).toBe(false);
|
expect(wrongResult).toBe(false);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("should verify known hash for 'password'", async () => {
|
||||||
|
// This hash was generated for the password "password"
|
||||||
|
const storedHash =
|
||||||
|
"$pbkdf2-sha256$100000$iUaDbbVm+Mf0HG7RcCCOzw==$IQfBN4chRU3wqCEoC9XOusIVYkyW24dbJd/ksm0VBJk=";
|
||||||
|
const password = "password";
|
||||||
|
|
||||||
|
const result = await verifyPassword(password, storedHash);
|
||||||
|
expect(result).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should derive consistent hash for known salt and password", async () => {
|
||||||
|
// Manually verify the derivation produces the expected hash
|
||||||
|
const password = "password";
|
||||||
|
const saltB64 = "iUaDbbVm+Mf0HG7RcCCOzw==";
|
||||||
|
const expectedHashB64 = "IQfBN4chRU3wqCEoC9XOusIVYkyW24dbJd/ksm0VBJk=";
|
||||||
|
const iterations = 100000;
|
||||||
|
|
||||||
|
// Decode salt
|
||||||
|
const saltBinary = atob(saltB64);
|
||||||
|
const salt = new Uint8Array(saltBinary.length);
|
||||||
|
for (let i = 0; i < saltBinary.length; i++) {
|
||||||
|
salt[i] = saltBinary.charCodeAt(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Derive key
|
||||||
|
const encoder = new TextEncoder();
|
||||||
|
const passwordBuffer = encoder.encode(password);
|
||||||
|
|
||||||
|
const keyMaterial = await crypto.subtle.importKey(
|
||||||
|
"raw",
|
||||||
|
passwordBuffer,
|
||||||
|
"PBKDF2",
|
||||||
|
false,
|
||||||
|
["deriveBits"],
|
||||||
|
);
|
||||||
|
|
||||||
|
const derivedBits = await crypto.subtle.deriveBits(
|
||||||
|
{
|
||||||
|
name: "PBKDF2",
|
||||||
|
salt,
|
||||||
|
iterations,
|
||||||
|
hash: "SHA-256",
|
||||||
|
},
|
||||||
|
keyMaterial,
|
||||||
|
32 * 8,
|
||||||
|
);
|
||||||
|
|
||||||
|
// Encode result to base64
|
||||||
|
const derivedArray = new Uint8Array(derivedBits);
|
||||||
|
let binary = "";
|
||||||
|
for (const byte of derivedArray) {
|
||||||
|
binary += String.fromCharCode(byte);
|
||||||
|
}
|
||||||
|
const derivedB64 = btoa(binary);
|
||||||
|
|
||||||
|
console.log("Expected hash:", expectedHashB64);
|
||||||
|
console.log("Derived hash: ", derivedB64);
|
||||||
|
console.log("Match:", derivedB64 === expectedHashB64);
|
||||||
|
|
||||||
|
expect(derivedB64).toBe(expectedHashB64);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -107,6 +107,7 @@ export const verifyPassword = async (
|
|||||||
const derivedBits = await crypto.subtle.deriveBits(
|
const derivedBits = await crypto.subtle.deriveBits(
|
||||||
{
|
{
|
||||||
name: "PBKDF2",
|
name: "PBKDF2",
|
||||||
|
// @ts-expect-error - salt is a Uint8Array
|
||||||
salt,
|
salt,
|
||||||
iterations,
|
iterations,
|
||||||
hash: "SHA-256",
|
hash: "SHA-256",
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
{
|
{
|
||||||
"extends": "@macalinao/tsconfig/tsconfig.base.json",
|
"extends": "@macalinao/tsconfig/tsconfig.base.json",
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"types": ["@cloudflare/workers-types"]
|
"types": ["bun"]
|
||||||
},
|
}
|
||||||
"exclude": ["**/*.test.ts"]
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user