fix: make compiled docker auth and sqlite runtime work

This commit is contained in:
2026-05-01 09:41:35 +09:00
parent 8656f237d4
commit 6df915b287
8 changed files with 297 additions and 8 deletions

View File

@@ -4,8 +4,8 @@ import {
UnauthorizedException,
} from '@nestjs/common';
import { JwtService } from '@nestjs/jwt';
import * as argon2 from 'argon2';
import { AuthResponse, UserProfile } from '@codexdash/shared-types';
import { hashPassword, verifyPassword } from './password-hasher';
import { PrismaService } from '../prisma/prisma.service';
import { LoginDto } from './dto/login.dto';
import { RegisterDto } from './dto/register.dto';
@@ -30,7 +30,7 @@ export class AuthService {
data: {
email: dto.email.toLowerCase(),
name: dto.name.trim(),
passwordHash: await argon2.hash(dto.password),
passwordHash: await hashPassword(dto.password),
},
});
@@ -42,7 +42,7 @@ export class AuthService {
where: { email: dto.email.toLowerCase() },
});
if (!user || !(await argon2.verify(user.passwordHash, dto.password))) {
if (!user || !(await verifyPassword(user.passwordHash, dto.password))) {
throw new UnauthorizedException('Invalid email or password');
}

View File

@@ -0,0 +1,25 @@
import * as argon2 from 'argon2';
import { hashPassword, verifyPassword } from './password-hasher';
describe('password-hasher', () => {
it('hashes passwords into an argon2id digest that can be verified', async () => {
const digest = await hashPassword('correct horse battery staple');
expect(digest.startsWith('$argon2id$')).toBe(true);
await expect(
verifyPassword(digest, 'correct horse battery staple'),
).resolves.toBe(true);
await expect(verifyPassword(digest, 'wrong password')).resolves.toBe(false);
});
it('verifies legacy node-argon2 digests', async () => {
const legacyDigest = await argon2.hash('legacy secret');
await expect(verifyPassword(legacyDigest, 'legacy secret')).resolves.toBe(
true,
);
await expect(verifyPassword(legacyDigest, 'wrong password')).resolves.toBe(
false,
);
});
});

View File

@@ -0,0 +1,42 @@
type BunPasswordApi = {
hash(password: string, options?: { algorithm?: 'argon2id' }): Promise<string>;
verify(password: string, digest: string): Promise<boolean>;
};
function getBunPasswordApi(): BunPasswordApi | undefined {
const runtime = globalThis as typeof globalThis & {
Bun?: {
password?: BunPasswordApi;
};
};
return runtime.Bun?.password;
}
function loadArgon2(): typeof import('argon2') {
// eslint-disable-next-line @typescript-eslint/no-require-imports
return require('argon2') as typeof import('argon2');
}
export async function hashPassword(password: string): Promise<string> {
const bunPassword = getBunPasswordApi();
if (bunPassword) {
return bunPassword.hash(password, { algorithm: 'argon2id' });
}
const argon2 = loadArgon2();
return argon2.hash(password);
}
export async function verifyPassword(
digest: string,
password: string,
): Promise<boolean> {
const bunPassword = getBunPasswordApi();
if (bunPassword) {
return bunPassword.verify(password, digest);
}
const argon2 = loadArgon2();
return argon2.verify(digest, password);
}