- update to AdonisJS 6
Some checks failed
CI Pipeline / japa-tests (push) Failing after 1m15s

This commit is contained in:
Kaimbacher 2024-03-14 20:25:27 +01:00
parent f828ca4491
commit cb51a4136f
167 changed files with 21485 additions and 21212 deletions

View file

@ -0,0 +1,65 @@
import { type ScryptOptions } from 'node:crypto';
// export declare const MAX_UINT32: number;
// export declare const MAX_UINT24: number;
import { promisify } from 'node:util';
import { randomBytes, scrypt } from 'node:crypto';
import phc from '@phc/format';
/**
* Validates a number to be within a given range.
*/
export class RangeValidator {
// static validate(label: string, value: unknown, range: [number, number]): void;
static validate(label: string, value: unknown, range: [number, number]): void {
if (typeof value !== 'number' || !Number.isInteger(value)) {
throw new TypeError(`The "${label}" option must be an integer`);
}
const [min, max] = range;
if (value < min || value > max) {
throw new TypeError(`The "${label}" option must be in the range (${min} <= ${label} <= ${max})`);
}
}
}
/**
* Validates a value to be one of the allowed values
*/
export class EnumValidator {
// static validate(label: string, value: unknown, allowedValues: any[]): void;
static validate(label: string, value: unknown, allowedValues: any[]): void {
if (!allowedValues.includes(value)) {
throw new TypeError(`The "${label}" option must be one of: ${allowedValues}`);
}
}
}
/**
* Async function to generate random bytes
*/
// export declare const randomBytesAsync: (arg1: number) => Promise<Buffer>;
export const randomBytesAsync: (arg1: number) => Promise<Buffer> = promisify(randomBytes);
/**
* Async version of scrypt.
*/
// export declare const scryptAsync: (arg1: string, arg2: Buffer, arg3: number, arg4: ScryptOptions) => Promise<Buffer>;
export const scryptAsync: (arg1: string, arg2: Buffer, arg3: number, arg4: ScryptOptions) => Promise<Buffer> = promisify(scrypt);
export class PhcFormatter {
/**
* Serialize salt and hash with predefined options.
*/
serialize(salt: Buffer, hash: Buffer, options: any): string {
return phc.serialize({
id: options.id,
version: options.version,
params: options.params,
salt,
hash,
});
}
/**
* Deserialize a PHC string to an object
*/
deserialize(phcString: string): DeserializeResult {
return phc.deserialize(phcString);
}
}

View file

@ -1,9 +1,34 @@
import { HashDriverContract } from '@ioc:Adonis/Core/Hash';
// const bcrypt = require("bcrypt");
import bcrypt from 'bcryptjs';
// import bcrypt from 'bcrypt/bcrypt.js'
import { HashDriverContract, ManagerDriverFactory } from '@adonisjs/core/types/hash';
import { EnumValidator, RangeValidator, PhcFormatter } from './helpers.js';
/**
* Config accepted by the hash driver
*/
export type PbkdfConfig = {
rounds: number;
saltSize?: number;
version?: number;
}
const saltRounds = 10;
export class LaravelHash implements HashDriverContract {
export class LaravelDriver implements HashDriverContract {
private config: PbkdfConfig;
// private binding;
private phcFormatter = new PhcFormatter();
constructor(config: {}) {
this.config = {
rounds: 10,
saltSize: 16,
version: 98,
...config
};
}
public async make(value: string) {
const hashedValue = bcrypt.hashSync(value, saltRounds);
return hashedValue;
@ -18,4 +43,101 @@ export class LaravelHash implements HashDriverContract {
}
return await bcrypt.compareSync(plainValue, newHash);
}
/**
* Check if the value is a valid hash. This method just checks
* for the formatting of the hash.
*
* ```ts
* bcrypt.isValidHash('hello world') // false
* bcrypt.isValidHash('$bcrypt$v=98$r=10$Jtxi46WJ26OQ0khsYLLlnw$knXGfuRFsSjXdj88JydPOnUIglvm1S8')
* ```
*/
public isValidHash(value: string) {
try {
this.validatePhcString(value);
return true;
} catch {
return false;
}
}
public needsReHash(value: string): boolean {
if (value.startsWith('$2b') || value.startsWith('$2a')) {
return true;
}
const phcNode = this.phcFormatter.deserialize(value);
if (phcNode.id !== 'bcrypt') {
return true;
}
if (phcNode.version !== this.config.version) {
return true;
}
if (!phcNode.params) {
return true;
}
if (phcNode.params.r !== this.config.rounds) {
return true;
}
return false;
}
/**
* Validate phc hash string
*/
private validatePhcString(phcString: string) {
const phcNode = this.phcFormatter.deserialize(phcString);
if (!phcNode.version) {
phcNode.version = 97;
}
if (phcNode.id !== 'bcrypt') {
throw new TypeError(`Invalid "id" found in the phc string`);
}
if (!phcNode.params) {
throw new TypeError(`No "params" found in the phc string`);
}
if (!phcNode.salt) {
throw new TypeError(`No "salt" found in the phc string`);
}
if (!phcNode.hash) {
throw new TypeError(`No "hash" found in the phc string`);
}
if (!phcNode.hash.byteLength) {
throw new TypeError(`No "hash" found in the phc string`);
}
RangeValidator.validate('salt.byteLength', phcNode.salt.byteLength, [8, 1024]);
EnumValidator.validate('version', phcNode.version, [97, 98]);
RangeValidator.validate('r', phcNode.params.r, [4, 31]);
return {
id: phcNode.id,
version: phcNode.version,
hash: phcNode.hash,
salt: phcNode.salt,
params: {
r: phcNode.params.r,
},
};
}
/**
* Dynamically importing underlying binding
*/
// private async importBinding() {
// if (this.binding) {
// return this.binding;
// }
// this.binding = await import('bcrypt');
// return this.binding;
// }
}
/**
* Factory function to reference the driver
* inside the config file.
*/
export function laravelDriver (config: PbkdfConfig): ManagerDriverFactory {
return () => {
return new LaravelDriver(config)
}
}