4 changed files with 49 additions and 0 deletions
@ -0,0 +1,9 @@ |
|||||
|
import { createHash, randomBytes } from "node:crypto"; |
||||
|
|
||||
|
export function randomUrlToken(): string { |
||||
|
return randomBytes(32).toString("base64url"); |
||||
|
} |
||||
|
|
||||
|
export function hashChallengeToken(token: string): string { |
||||
|
return createHash("sha256").update(token, "utf8").digest("hex"); |
||||
|
} |
||||
@ -0,0 +1,15 @@ |
|||||
|
import bcrypt from "bcryptjs"; |
||||
|
|
||||
|
const ROUNDS = 10; |
||||
|
|
||||
|
export async function hashPassword(plain: string): Promise<string> { |
||||
|
const salt = await bcrypt.genSalt(ROUNDS); |
||||
|
return bcrypt.hash(plain, salt); |
||||
|
} |
||||
|
|
||||
|
export async function verifyPassword( |
||||
|
plain: string, |
||||
|
hash: string, |
||||
|
): Promise<boolean> { |
||||
|
return bcrypt.compare(plain, hash); |
||||
|
} |
||||
@ -0,0 +1,15 @@ |
|||||
|
import { describe, expect, it } from "bun:test"; |
||||
|
import { |
||||
|
hashChallengeToken, |
||||
|
randomUrlToken, |
||||
|
} from "../../server/utils/challenge-token"; |
||||
|
|
||||
|
describe("challenge-token", () => { |
||||
|
it("hash is stable", () => { |
||||
|
expect(hashChallengeToken("abc")).toBe(hashChallengeToken("abc")); |
||||
|
}); |
||||
|
|
||||
|
it("random has reasonable length", () => { |
||||
|
expect(randomUrlToken().length).toBeGreaterThan(20); |
||||
|
}); |
||||
|
}); |
||||
@ -0,0 +1,10 @@ |
|||||
|
import { describe, expect, it } from "bun:test"; |
||||
|
import { hashPassword, verifyPassword } from "../../server/utils/password"; |
||||
|
|
||||
|
describe("password", () => { |
||||
|
it("hashes and verifies", async () => { |
||||
|
const h = await hashPassword("hunter2"); |
||||
|
expect(await verifyPassword("hunter2", h)).toBe(true); |
||||
|
expect(await verifyPassword("wrong", h)).toBe(false); |
||||
|
}); |
||||
|
}); |
||||
Loading…
Reference in new issue