Skip to content

Commit bd8561a

Browse files
committed
feat(passwrd): allow custom hasing methods for password #31
1 parent 844ff66 commit bd8561a

File tree

5 files changed

+44
-26
lines changed

5 files changed

+44
-26
lines changed

README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,10 @@ Sets a custom method for generating random session IDs.
175175

176176
Sets a custom method for generating random email verification codes.
177177

178+
##### `setPasswordHashingMethods(fn: () => string)`
179+
180+
Sets a custom method for generating random email verification codes.
181+
178182
##### `getSession(sessionId: string)`
179183

180184
Fetches a session by its session ID.

src/runtime/core/core.ts

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,14 @@
11
import { createChecker, type supportedConnectors } from "drizzle-schema-checker";
22
import { getOAuthAccountsTableSchema, getSessionsTableSchema, getUsersTableSchema, getEmailVerificationCodesTableSchema } from "../database/lib/sqlite/schema.sqlite";
33
import { drizzle as drizzleIntegration } from "db0/integrations/drizzle/index";
4-
import type { ICreateOrLoginParams, ICreateUserParams, ILoginUserParams, ISlipAuthCoreOptions, SchemasMockValue, SlipAuthUser, tableNames } from "./types";
4+
import type { ICreateOrLoginParams, ICreateUserParams, ILoginUserParams, IPasswordHashingMethods, ISlipAuthCoreOptions, SchemasMockValue, SlipAuthUser, tableNames } from "./types";
55
import { createSlipHooks } from "./hooks";
66
import { UsersRepository } from "./repositories/UsersRepository";
77
import { SessionsRepository } from "./repositories/SessionsRepository";
88
import { OAuthAccountsRepository } from "./repositories/OAuthAccountsRepository";
99
import { EmailVerificationCodesRepository } from "./repositories/EmailVerificationCodesRepository";
1010
import type { SlipAuthPublicSession } from "../types";
11-
import { defaultIdGenerationMethod, isValidEmail, defaultEmailVerificationCodeGenerationMethod } from "./email-and-password-utils";
12-
import { hashPassword, verifyPassword } from "./password";
11+
import { defaultIdGenerationMethod, isValidEmail, defaultEmailVerificationCodeGenerationMethod, defaultHashPasswordMethod, defaultVerifyPasswordMethod } from "./email-and-password-utils";
1312
import { InvalidEmailOrPasswordError, UnhandledError } from "./errors/SlipAuthError.js";
1413
import type { Database } from "db0";
1514
import { isWithinExpirationDate } from "oslo";
@@ -30,6 +29,8 @@ export class SlipAuthCore {
3029
#createRandomSessionId: () => string;
3130
#createRandomEmailVerificationCode: () => string;
3231

32+
#passwordHashingMethods: IPasswordHashingMethods;
33+
3334
readonly schemas: SchemasMockValue;
3435
readonly hooks = createSlipHooks();
3536

@@ -62,6 +63,11 @@ export class SlipAuthCore {
6263
this.#createRandomUserId = defaultIdGenerationMethod;
6364

6465
this.#createRandomEmailVerificationCode = defaultEmailVerificationCodeGenerationMethod;
66+
67+
this.#passwordHashingMethods = {
68+
hash: defaultHashPasswordMethod,
69+
verify: defaultHashPasswordMethod,
70+
};
6571
}
6672

6773
public checkDbAndTables(dialect: supportedConnectors) {
@@ -105,7 +111,7 @@ export class SlipAuthCore {
105111
throw new InvalidEmailOrPasswordError("no password oauth user");
106112
}
107113

108-
const validPassword = await verifyPassword(existingUser.password, password);
114+
const validPassword = await this.#passwordHashingMethods.verify(existingUser.password, password);
109115
if (!validPassword) {
110116
throw new InvalidEmailOrPasswordError("login invalid password");
111117
}
@@ -131,7 +137,7 @@ export class SlipAuthCore {
131137
}
132138

133139
const userId = this.#createRandomUserId();
134-
const passwordHash = await hashPassword(password);
140+
const passwordHash = await this.#passwordHashingMethods.hash(password);
135141

136142
try {
137143
const user = await this.#repos.users.insert(userId, email, passwordHash);
@@ -254,6 +260,11 @@ export class SlipAuthCore {
254260
this.#createRandomEmailVerificationCode = fn;
255261
}
256262

263+
public setPasswordHashingMethods(fn: () => IPasswordHashingMethods) {
264+
const methods = fn();
265+
this.#passwordHashingMethods = methods;
266+
}
267+
257268
public getSession(sessionId: string) {
258269
return this.#repos.sessions.findById(sessionId);
259270
}

src/runtime/core/email-and-password-utils.ts

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
import { generateRandomString, alphabet } from "oslo/crypto";
2+
import type { Options as ArgonOptions } from "@node-rs/argon2";
3+
import { hash, verify } from "@node-rs/argon2";
24

35
/**
46
https://thecopenhagenbook.com/email-verification#input-validation
@@ -20,3 +22,20 @@ export function isValidEmail(email: string): boolean {
2022
export const defaultIdGenerationMethod = () => generateRandomString(15, alphabet("a-z", "A-Z", "0-9"));
2123

2224
export const defaultEmailVerificationCodeGenerationMethod = () => generateRandomString(6, alphabet("0-9", "A-Z"));
25+
26+
const hashOptions: ArgonOptions = {
27+
// recommended minimum parameters
28+
memoryCost: 19456,
29+
timeCost: 2,
30+
outputLen: 32,
31+
parallelism: 1,
32+
};
33+
34+
// https://thecopenhagenbook.com/password-authentication#argon2id
35+
export async function defaultHashPasswordMethod(rawPassword: string): Promise<string> {
36+
return await hash(rawPassword, hashOptions);
37+
};
38+
39+
export async function defaultVerifyPasswordMethod(sourceHashedPassword: string, rawPassword: string): Promise<boolean> {
40+
return verify(sourceHashedPassword, rawPassword, hashOptions);
41+
};

src/runtime/core/password.ts

Lines changed: 0 additions & 21 deletions
This file was deleted.

src/runtime/core/types.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,11 @@ export type SlipAuthOAuthAccount = ReturnType<typeof getOAuthAccountsTableSchema
4747
export type EmailVerificationCodeTableInsert = ReturnType<typeof getEmailVerificationCodesTableSchema>["$inferInsert"];
4848
export type SlipAuthEmailVerificationCode = ReturnType<typeof getEmailVerificationCodesTableSchema>["$inferSelect"];
4949

50+
export interface IPasswordHashingMethods {
51+
hash: (rawPassword: string) => Promise<string>
52+
verify: (sourceHashedPassword: string, rawPassword: string) => Promise<string>
53+
}
54+
5055
export interface ISlipAuthCoreOptions {
5156
/**
5257
* {@link https://github.com/unjs/h3/blob/c04c458810e34eb15c1647e1369e7d7ef19f567d/src/utils/session.ts#L24}

0 commit comments

Comments
 (0)