This commit is contained in:
Tutur33
2023-11-24 22:35:41 +01:00
parent 3c0b507a93
commit 7644b2a0f7
45165 changed files with 4803356 additions and 3 deletions
+9
View File
@@ -0,0 +1,9 @@
# The MIT License
Copyright 2022 Harminder Virk, contributors
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the 'Software'), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+53
View File
@@ -0,0 +1,53 @@
<div align="center">
<img src="https://res.cloudinary.com/adonisjs/image/upload/q_100/v1558612869/adonis-readme_zscycu.jpg" width="600px">
</div>
<br />
<div align="center">
<h3>AdonisJS Hash Provider</h3>
<p>A multi driver hash provider to hash values (usually passwords). The hash output follows the <a href="https://github.com/P-H-C/phc-string-format/blob/master/phc-sf-spec.md"> PHC format spec. </a></p>
</div>
<br />
<div align="center">
[![gh-workflow-image]][gh-workflow-url] [![npm-image]][npm-url] ![][typescript-image] [![license-image]][license-url] [![synk-image]][synk-url]
</div>
<div align="center">
<h3>
<a href="https://adonisjs.com">
Website
</a>
<span> | </span>
<a href="https://docs.adonisjs.com/guides/security/hashing">
Guides
</a>
<span> | </span>
<a href="CONTRIBUTING.md">
Contributing
</a>
</h3>
</div>
<div align="center">
<sub>Built with ❤︎ by <a href="https://twitter.com/AmanVirk1">Harminder Virk</a>
</div>
[gh-workflow-image]: https://img.shields.io/github/workflow/status/adonisjs/hash/test?style=for-the-badge
[gh-workflow-url]: https://github.com/adonisjs/hash/actions/workflows/test.yml "Github action"
[typescript-image]: https://img.shields.io/badge/Typescript-294E80.svg?style=for-the-badge&logo=typescript
[typescript-url]: "typescript"
[npm-image]: https://img.shields.io/npm/v/@adonisjs/hash.svg?style=for-the-badge&logo=npm
[npm-url]: https://npmjs.org/package/@adonisjs/hash "npm"
[license-image]: https://img.shields.io/npm/l/@adonisjs/hash?color=blueviolet&style=for-the-badge
[license-url]: LICENSE.md "license"
[synk-image]: https://img.shields.io/snyk/vulnerabilities/github/adonisjs/hash?label=Synk%20Vulnerabilities&style=for-the-badge
[synk-url]: https://snyk.io/test/github/adonisjs/hash?targetFile=package.json "synk"
+14
View File
@@ -0,0 +1,14 @@
/**
* @adonisjs/hash
*
* (c) Harminder Virk <virk@adonisjs.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
declare module '@ioc:Adonis/Core/Application' {
import { HashContract } from '@ioc:Adonis/Core/Hash';
interface ContainerBindings {
'Adonis/Core/Hash': HashContract;
}
}
+8
View File
@@ -0,0 +1,8 @@
/**
* @adonisjs/hash
*
* (c) Harminder Virk <virk@adonisjs.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
+186
View File
@@ -0,0 +1,186 @@
declare module '@ioc:Adonis/Core/Hash' {
import { ApplicationContract } from '@ioc:Adonis/Core/Application';
import { ManagerContract } from '@poppinss/manager';
/**
* Every driver must implement the Hash driver
* contract
*/
export interface HashDriverContract {
ids?: string[];
params?: any;
/**
* Hash plain text value using the default mapping
*/
make(value: string): Promise<string>;
/**
* Check the hash against the current config to find it needs
* to be re-hashed or not
*/
needsReHash?(hashedValue: string): boolean;
/**
* Verify plain value against the hashed value to find if it's
* valid or not
*/
verify(hashedValue: string, plainValue: string): Promise<boolean>;
}
/**
* Shape of bcrypt config
*/
export type BcryptConfig = {
driver: 'bcrypt';
rounds: number;
};
/**
* Bcrypt driver contract
*/
export interface BcryptContract extends HashDriverContract {
ids: ['bcrypt'];
params: {
rounds: 'r';
};
}
/**
* Shape of argon2 config
*/
export type ArgonConfig = {
driver: 'argon2';
variant: 'd' | 'i' | 'id';
iterations: number;
memory: number;
parallelism: number;
saltSize: number;
};
/**
* Argon2 driver contract
*/
export interface ArgonContract extends HashDriverContract {
ids: ['argon2d', 'argon2i', 'argon2id'];
params: {
iterations: 't';
memory: 'm';
parallelism: 'p';
};
}
/**
* Shape of scrypt config
*/
export type ScryptConfig = {
driver: 'scrypt';
/**
* CPU/memory cost parameter. Must be a power of two greater than one.
* Default: 16384
*/
cost: number;
/**
* Block size parameter.
* Default: 8
*/
blockSize: number;
/**
* Parallelization parameter.
* Default: 1
*/
parallelization: number;
/**
* Size of the salt.
* Minimum: 16
* Default: 16
*/
saltSize: number;
/**
* Memory upper bound.
* Default: 16777216
*/
maxMemory: number;
/**
* Desired key length in bytes.
* Default: 64
*/
keyLength: number;
};
/**
* Scrypt driver contract
*/
export interface ScryptContract extends HashDriverContract {
ids: ['scrypt'];
params: {
cost: 'n';
blockSize: 'r';
parallelization: 'p';
};
}
export interface FakeContract extends HashDriverContract {
ids: ['fake'];
needsReHash(hashedValue: string): boolean;
}
/**
* Default list of available drivers. One can you reference this type
* to setup the `HashersList`.
*
* We will remove this later. Make sure all stubs are not using this
* type.
*/
export interface HashDrivers {
bcrypt: {
config: BcryptConfig;
implementation: BcryptContract;
};
argon2: {
config: ArgonConfig;
implementation: ArgonContract;
};
scrypt: {
config: ScryptConfig;
implementation: ScryptContract;
};
}
/**
* List of hash mappings used by the app. Using declaration merging, one
* must extend this interface.
*
* MUST BE SET IN THE USER LAND.
*/
export interface HashersList {
}
/**
* Shape of config accepted by the Hash module.
*/
export interface HashConfig {
default: keyof HashersList;
list: {
[P in keyof HashersList]: HashersList[P]['config'];
};
}
/**
* Hash mananger interface
*/
export interface HashContract extends ManagerContract<ApplicationContract, HashDriverContract, HashDriverContract, {
[P in keyof HashersList]: HashersList[P]['implementation'];
}> {
readonly isFaked: boolean;
/**
* Hash plain text value using the default mapping
*/
make(value: string): ReturnType<HashDriverContract['make']>;
/**
* Fake hash
*/
fake(): void;
/**
* Remove fake
*/
restore(): void;
/**
* Verify plain value against the hashed value to find if it's
* valid or not
*/
verify(hashedValue: string, plainValue: string): ReturnType<HashDriverContract['verify']>;
/**
* Check the hash against the current config to find it needs
* to be re-hashed or not
*/
needsReHash(hashedValue: string): boolean;
}
const Hash: HashContract;
export default Hash;
}
+8
View File
@@ -0,0 +1,8 @@
/*
* @adonisjs/hash
*
* (c) Harminder Virk <virk@adonisjs.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
+2
View File
@@ -0,0 +1,2 @@
/// <reference path="hash.d.ts" />
/// <reference path="container.d.ts" />
+10
View File
@@ -0,0 +1,10 @@
/*
* @adonisjs/hash
*
* (c) Harminder Virk <virk@adonisjs.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
/// <reference path="./hash.ts" />
/// <reference path="./container.ts" />
+28
View File
@@ -0,0 +1,28 @@
import { HashDrivers } from '@ioc:Adonis/Core/Hash';
/**
* Expected shape of the config accepted by the "hashConfig"
* method
*/
declare type HashConfig = {
list: {
[name: string]: {
[K in keyof HashDrivers]: HashDrivers[K]['config'] & {
driver: K;
};
}[keyof HashDrivers];
};
};
/**
* Define config for the Hash module
*/
export declare function hashConfig<T extends HashConfig & {
default: keyof T['list'];
}>(config: T): T;
/**
* Pull hashers list from the config defined inside the "config/hash.ts"
* file
*/
export declare type InferListFromConfig<T extends HashConfig> = {
[K in keyof T['list']]: HashDrivers[T['list'][K]['driver']];
};
export {};
+18
View File
@@ -0,0 +1,18 @@
"use strict";
/*
* @adonisjs/hash
*
* (c) Harminder Virk <virk@adonisjs.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.hashConfig = void 0;
/**
* Define config for the Hash module
*/
function hashConfig(config) {
return config;
}
exports.hashConfig = hashConfig;
+7
View File
@@ -0,0 +1,7 @@
import { ApplicationContract } from '@ioc:Adonis/Core/Application';
export default class HashProvider {
protected app: ApplicationContract;
constructor(app: ApplicationContract);
static needsApplication: boolean;
register(): void;
}
+24
View File
@@ -0,0 +1,24 @@
"use strict";
/*
* @adonisjs/hash
*
* (c) Harminder Virk <virk@adonisjs.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
Object.defineProperty(exports, "__esModule", { value: true });
class HashProvider {
constructor(app) {
this.app = app;
}
register() {
this.app.container.singleton('Adonis/Core/Hash', () => {
const config = this.app.container.resolveBinding('Adonis/Core/Config').get('hash', {});
const { Hash } = require('../src/Hash');
return new Hash(this, config);
});
}
}
exports.default = HashProvider;
HashProvider.needsApplication = true;
+44
View File
@@ -0,0 +1,44 @@
/// <reference path="../../adonis-typings/hash.d.ts" />
import { ArgonConfig, ArgonContract } from '@ioc:Adonis/Core/Hash';
/**
* Hash driver built on top of argon hashing algorithm. The driver adheres
* to `phc` string format.
*/
export declare class Argon implements ArgonContract {
private config;
/**
* A list of ids to find if hash belongs to this driver
* or not.
*/
ids: ArgonContract['ids'];
/**
* A list of params encoded to the hash value.
*/
params: ArgonContract['params'];
/**
* The current argon version in use
*/
version: number;
constructor(config: ArgonConfig);
/**
* Hash a value using argon algorithm. The options can be used to override
* default settings.
*/
make(value: string): any;
/**
* Verifies the hash against a plain value to find if it's
* a valid hash or not.
*/
verify(hashedValue: string, plainValue: string): Promise<boolean>;
/**
* Returns a boolean telling if the hash needs a rehash or not. The rehash is
* required when
*
* 1. The argon2 version is changed
* 2. Number of iterations are changed.
* 3. The memory value is changed.
* 4. The parellelism value is changed.
* 5. The argon variant is changed.
*/
needsReHash(value: string): boolean;
}
+92
View File
@@ -0,0 +1,92 @@
"use strict";
/*
* @adonisjs/hash
*
* (c) Harminder Virk <virk@adonisjs.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.Argon = void 0;
/// <reference path="../../adonis-typings/hash.ts" />
const format_1 = __importDefault(require("@phc/format"));
const phc_argon2_1 = __importDefault(require("phc-argon2"));
/**
* Hash driver built on top of argon hashing algorithm. The driver adheres
* to `phc` string format.
*/
class Argon {
constructor(config) {
this.config = config;
/**
* A list of ids to find if hash belongs to this driver
* or not.
*/
this.ids = ['argon2d', 'argon2i', 'argon2id'];
/**
* A list of params encoded to the hash value.
*/
this.params = {
iterations: 't',
memory: 'm',
parallelism: 'p',
};
/**
* The current argon version in use
*/
this.version = 19;
}
/**
* Hash a value using argon algorithm. The options can be used to override
* default settings.
*/
make(value) {
return phc_argon2_1.default.hash(value, this.config);
}
/**
* Verifies the hash against a plain value to find if it's
* a valid hash or not.
*/
verify(hashedValue, plainValue) {
return phc_argon2_1.default.verify(hashedValue, plainValue);
}
/**
* Returns a boolean telling if the hash needs a rehash or not. The rehash is
* required when
*
* 1. The argon2 version is changed
* 2. Number of iterations are changed.
* 3. The memory value is changed.
* 4. The parellelism value is changed.
* 5. The argon variant is changed.
*/
needsReHash(value) {
const deserialized = format_1.default.deserialize(value);
if (!this.ids.includes(deserialized.id)) {
throw new Error('value is not an argon2 hash');
}
/**
* Version mis-match
*/
if (deserialized.version !== this.version) {
return true;
}
/**
* Variant mis-match
*/
if (deserialized.id !== `argon2${this.config.variant}`) {
return true;
}
/**
* Check for params mis-match
*/
return !!Object.keys(this.params).find((key) => {
return deserialized.params[this.params[key]] !== this.config[key];
});
}
}
exports.Argon = Argon;
+26
View File
@@ -0,0 +1,26 @@
/// <reference path="../../adonis-typings/hash.d.ts" />
import { BcryptConfig, BcryptContract } from '@ioc:Adonis/Core/Hash';
/**
* Generates and verifies hash using Bcrypt as underlying
* algorigthm.
*/
export declare class Bcrypt implements BcryptContract {
private config;
ids: BcryptContract['ids'];
params: BcryptContract['params'];
version: number;
constructor(config: BcryptConfig);
/**
* Returns hash for a given value
*/
make(value: string): any;
/**
* Verify hash to know if two values are same.
*/
verify(hashedValue: string, plainValue: string): Promise<boolean>;
/**
* Returns a boolean telling if hash needs a rehash. Returns true when
* one of the original params have been changed.
*/
needsReHash(value: string): boolean;
}
+67
View File
@@ -0,0 +1,67 @@
"use strict";
/*
* @adonisjs/hash
*
* (c) Harminder Virk <virk@adonisjs.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.Bcrypt = void 0;
/// <reference path="../../adonis-typings/hash.ts" />
const format_1 = __importDefault(require("@phc/format"));
const phc_bcrypt_1 = __importDefault(require("phc-bcrypt"));
/**
* Generates and verifies hash using Bcrypt as underlying
* algorigthm.
*/
class Bcrypt {
constructor(config) {
this.config = config;
this.ids = ['bcrypt'];
this.params = { rounds: 'r' };
this.version = 98;
}
/**
* Returns hash for a given value
*/
make(value) {
return phc_bcrypt_1.default.hash(value, this.config);
}
/**
* Verify hash to know if two values are same.
*/
verify(hashedValue, plainValue) {
return phc_bcrypt_1.default.verify(hashedValue, plainValue);
}
/**
* Returns a boolean telling if hash needs a rehash. Returns true when
* one of the original params have been changed.
*/
needsReHash(value) {
const deserialized = format_1.default.deserialize(value);
/**
* Phc formatted Bycrpt hash
*/
if (deserialized.id === 'bcrypt') {
if (this.version !== deserialized.version) {
return true;
}
return !!Object.keys(this.params).find((key) => {
return deserialized.params[this.params[key]] !== this.config[key];
});
}
/**
* Re-format non phc formatted bcrypt hashes.
*/
if (value.startsWith('$2b') || value.startsWith('$2a')) {
return true;
}
throw new Error('value is not a bcrypt hash');
}
}
exports.Bcrypt = Bcrypt;
+21
View File
@@ -0,0 +1,21 @@
/// <reference path="../../adonis-typings/hash.d.ts" />
import { FakeContract } from '@ioc:Adonis/Core/Hash';
/**
* Generates and verifies hash using no algorigthm.
*/
export declare class Fake implements FakeContract {
ids: FakeContract['ids'];
/**
* Returns hash for a given value
*/
make(value: string): Promise<string>;
/**
* Verify hash to know if two values are same.
*/
verify(hashedValue: string, plainValue: string): Promise<boolean>;
/**
* Returns a boolean telling if hash needs a rehash. Returns true when
* one of the original params have been changed.
*/
needsReHash(_value: string): boolean;
}
+39
View File
@@ -0,0 +1,39 @@
"use strict";
/*
* @adonisjs/hash
*
* (c) Harminder Virk <virk@adonisjs.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.Fake = void 0;
/**
* Generates and verifies hash using no algorigthm.
*/
class Fake {
constructor() {
this.ids = ['fake'];
}
/**
* Returns hash for a given value
*/
make(value) {
return Promise.resolve(value);
}
/**
* Verify hash to know if two values are same.
*/
verify(hashedValue, plainValue) {
return Promise.resolve(hashedValue === plainValue);
}
/**
* Returns a boolean telling if hash needs a rehash. Returns true when
* one of the original params have been changed.
*/
needsReHash(_value) {
return false;
}
}
exports.Fake = Fake;
+33
View File
@@ -0,0 +1,33 @@
import type { ScryptConfig, ScryptContract } from '@ioc:Adonis/Core/Hash';
/**
* Hash driver built on top of scrypt hashing algorithm. The driver adheres
* to `phc` string format.
*/
export declare class Scrypt implements ScryptContract {
private readonly config;
/**
* A list of ids to find if hash belongs to this driver
* or not.
*/
ids: ScryptContract['ids'];
/**
* A list of params encoded to the hash value.
*/
params: ScryptContract['params'];
constructor(config: ScryptConfig);
/**
* Hash a value using scrypt algorithm. The options can be used to override
* default settings.
*/
make(value: string): Promise<any>;
/**
* Verifies the hash against a plain value to find if it's
* a valid hash or not. The hash must be a valid `phc` string
*/
verify(hashedValue: string, plainValue: string): Promise<boolean>;
/**
* Returns a boolean telling if hash needs a rehash. Returns true when
* one of the original params have been changed.
*/
needsReHash(hashedValue: string): boolean;
}
+178
View File
@@ -0,0 +1,178 @@
"use strict";
/*
* @adonisjs/hash
*
* (c) AdonisJS
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.Scrypt = void 0;
const format_1 = __importDefault(require("@phc/format"));
const crypto_1 = require("crypto");
const utils_1 = require("../utils");
const defaultConfig = Object.freeze({
cost: 16384,
blockSize: 8,
parallelization: 1,
saltSize: 16,
keyLength: 64,
maxMemory: 128 * 16384 * 8,
});
function scryptAsync(password, salt, keyLength, options) {
return new Promise((resolve, reject) => {
(0, crypto_1.scrypt)(password, salt, keyLength, options, (error, derivedKey) => {
if (error) {
reject(error);
}
else {
resolve(derivedKey);
}
});
});
}
/**
* Hash driver built on top of scrypt hashing algorithm. The driver adheres
* to `phc` string format.
*/
class Scrypt {
constructor(config) {
this.config = config;
/**
* A list of ids to find if hash belongs to this driver
* or not.
*/
this.ids = ['scrypt'];
/**
* A list of params encoded to the hash value.
*/
this.params = {
cost: 'n',
blockSize: 'r',
parallelization: 'p',
};
// Cost Validation
if (config.cost < 1 || config.cost % 2 !== 0) {
throw new TypeError("The 'cost' option must be a power of 2 greater than 1");
}
// Parallelization Validation
if (config.parallelization < 1 || config.parallelization > utils_1.kMaxUint24) {
throw new TypeError(`The 'parallelism' option must be in the range (1 <= parallelism <= ${utils_1.kMaxUint24})`);
}
// Memory Validation
const maxMemory = 128 * config.cost * config.blockSize;
if (maxMemory > config.maxMemory) {
throw new TypeError(`The 'maxmem' option must be less than ${maxMemory}, found ${config.maxMemory}`);
}
// Salt Size Validation
if (config.saltSize < 16 || config.saltSize > 1024) {
throw new TypeError("The 'saltSize' option must be in the range (8 <= saltSize <= 1024)");
}
// Key Length Validation
if (config.keyLength < 64 || config.keyLength > 128) {
throw new TypeError("The 'keylen' option must be in the range (64 <= keylen <= 128)");
}
this.config = Object.assign({}, defaultConfig, config);
}
/**
* Hash a value using scrypt algorithm. The options can be used to override
* default settings.
*/
async make(value) {
const salt = await (0, utils_1.randomBytesAsync)(this.config.saltSize);
const derivedKey = await scryptAsync(value, salt, this.config.keyLength, this.config);
return format_1.default.serialize({
id: this.ids[0],
params: {
n: this.config.cost,
r: this.config.blockSize,
p: this.config.parallelization,
},
salt,
hash: derivedKey,
});
}
/**
* Verifies the hash against a plain value to find if it's
* a valid hash or not. The hash must be a valid `phc` string
*/
async verify(hashedValue, plainValue) {
let deserializedHash;
try {
deserializedHash = format_1.default.deserialize(hashedValue);
}
catch (error) {
throw new TypeError('The hash must be a valid phc string');
}
// Identifier Validation
if (!this.ids.includes(deserializedHash.id)) {
throw new TypeError(`Incompatible ${deserializedHash.id} identifier found in the hash`);
}
// Parameters Existence Validation
if (typeof deserializedHash.params !== 'object') {
throw new TypeError('The param section cannot be empty');
}
// Cost Validation
if (typeof deserializedHash.params.n !== 'number' ||
!Number.isInteger(deserializedHash.params.n)) {
throw new TypeError("The 'n' param must be an integer");
}
// Cost Validation
if (deserializedHash.params.n < 1 || deserializedHash.params.n % 2 !== 0) {
throw new TypeError("The 'n' param must be a power of 2 greater than 1");
}
// Block size Validation
if (typeof deserializedHash.params.r !== 'number' ||
!Number.isInteger(deserializedHash.params.r)) {
throw new TypeError("The 'r' param must be an integer");
}
// Parallelization Validation
if (typeof deserializedHash.params.p !== 'number' ||
!Number.isInteger(deserializedHash.params.p)) {
throw new TypeError("The 'p' param must be an integer");
}
// Parallelization Validation
if (deserializedHash.params.p < 1 || deserializedHash.params.p > utils_1.kMaxUint24) {
throw new TypeError(`The 'p' param must be in the range (1 <= parallelism <= ${utils_1.kMaxUint24})`);
}
// Salt Validation
if (typeof deserializedHash.salt === 'undefined') {
throw new TypeError('No salt found in the given string');
}
// Hash Validation
if (typeof deserializedHash.hash === 'undefined') {
throw new TypeError('No hash found in the given string');
}
const derivedKey = await scryptAsync(plainValue, deserializedHash.salt, deserializedHash.hash.length, {
maxmem: this.config.maxMemory,
cost: deserializedHash.params.n,
blockSize: deserializedHash.params.r,
parallelization: deserializedHash.params.p,
});
return (0, crypto_1.timingSafeEqual)(deserializedHash.hash, derivedKey);
}
/**
* Returns a boolean telling if hash needs a rehash. Returns true when
* one of the original params have been changed.
*/
needsReHash(hashedValue) {
let deserializedHash;
try {
deserializedHash = format_1.default.deserialize(hashedValue);
}
catch (error) {
return true;
}
if (!this.ids.includes(deserializedHash.id)) {
throw new Error('Value is not a scrypt hash');
}
return Object.keys(this.params).some((key) => {
return deserializedHash.params[this.params[key]] !== this.config[key];
});
}
}
exports.Scrypt = Scrypt;
+88
View File
@@ -0,0 +1,88 @@
/// <reference path="../../adonis-typings/hash.d.ts" />
import { Manager } from '@poppinss/manager';
import { ApplicationContract } from '@ioc:Adonis/Core/Application';
import { HashConfig, HashContract, HashDriverContract, HashersList } from '@ioc:Adonis/Core/Hash';
/**
* The Hash module exposes the API to hash values using an underlying
* Hash driver.
*/
export declare class Hash<Config extends HashConfig> extends Manager<ApplicationContract, HashDriverContract, HashDriverContract, {
[P in keyof HashersList]: HashersList[P]['implementation'];
}> implements HashContract {
config: Config;
/**
* Reference to fake driver. Created when `Hash.fake` is called
*/
private fakeDriver;
protected singleton: boolean;
/**
* A boolean to know, if hash module is running in fake
* mode or not
*/
get isFaked(): boolean;
constructor(application: ApplicationContract, config: Config);
/**
* Validate config
*/
private validateConfig;
/**
* Pulling the default driver name from the user config.
*/
protected getDefaultMappingName(): never;
/**
* Returns the config for a mapping
*/
protected getMappingConfig(name: keyof HashersList): never;
/**
* Returns the driver name for a mapping
*/
protected getMappingDriver(name: keyof HashersList): string | undefined;
/**
* Creating bcrypt driver. The manager will call this method anytime
* someone will ask for the `bcrypt` driver.
*/
protected createBcrypt(_: string, config: any): any;
/**
* Creating argon driver. The manager will call this method anytime
* someone will ask for the `argon` driver.
*/
protected createArgon2(_: string, config: any): any;
/**
* Creating scrypt driver. The manager will call this method anytime
* someone will ask for the `scrypt` driver.
*/
protected createScrypt(_: string, config: any): any;
/**
* Creating fake driver. The manager will call this method anytime
* someone will ask for the `fake` driver.
*/
protected createFake(): any;
/**
* Initiate faking hash calls. All methods invoked on the main hash
* module and the underlying drivers will be faked using the
* fake driver.
*
* To restore the fake. Run the `Hash.restore` method.
*/
fake(): void;
/**
* Restore fake
*/
restore(): void;
/**
* Hash value using the default driver
*/
make(value: string): any;
/**
* Verify value using the default driver
*/
verify(hashedValue: string, plainValue: string): any;
/**
* Find if value needs to be re-hashed as per the default driver.
*/
needsReHash(hashedValue: string): any;
/**
* Pull pre-configured driver instance
*/
use<K extends keyof HashersList>(name?: K): ReturnType<HashContract['use']>;
}
+149
View File
@@ -0,0 +1,149 @@
"use strict";
/*
* @adonisjs/hash
*
* (c) Harminder Virk <virk@adonisjs.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.Hash = void 0;
/// <reference path="../../adonis-typings/hash.ts" />
const manager_1 = require("@poppinss/manager");
const utils_1 = require("@poppinss/utils");
/**
* The Hash module exposes the API to hash values using an underlying
* Hash driver.
*/
class Hash extends manager_1.Manager {
constructor(application, config) {
super(application);
this.config = config;
this.singleton = true;
this.validateConfig();
}
/**
* A boolean to know, if hash module is running in fake
* mode or not
*/
get isFaked() {
return !!this.fakeDriver;
}
/**
* Validate config
*/
validateConfig() {
const validator = new utils_1.ManagerConfigValidator(this.config, 'hash', 'config/hash');
validator.validateDefault('default');
validator.validateList('list', 'default');
}
/**
* Pulling the default driver name from the user config.
*/
getDefaultMappingName() {
return this.config.default;
}
/**
* Returns the config for a mapping
*/
getMappingConfig(name) {
return this.config.list[name];
}
/**
* Returns the driver name for a mapping
*/
getMappingDriver(name) {
const config = this.getMappingConfig(name);
return config ? config.driver : undefined;
}
/**
* Creating bcrypt driver. The manager will call this method anytime
* someone will ask for the `bcrypt` driver.
*/
createBcrypt(_, config) {
const { Bcrypt } = require('../Drivers/Bcrypt');
return new Bcrypt(config);
}
/**
* Creating argon driver. The manager will call this method anytime
* someone will ask for the `argon` driver.
*/
createArgon2(_, config) {
const { Argon } = require('../Drivers/Argon');
return new Argon(config);
}
/**
* Creating scrypt driver. The manager will call this method anytime
* someone will ask for the `scrypt` driver.
*/
createScrypt(_, config) {
const { Scrypt } = require('../Drivers/Scrypt');
return new Scrypt(config);
}
/**
* Creating fake driver. The manager will call this method anytime
* someone will ask for the `fake` driver.
*/
createFake() {
const { Fake } = require('../Drivers/Fake');
return new Fake();
}
/**
* Initiate faking hash calls. All methods invoked on the main hash
* module and the underlying drivers will be faked using the
* fake driver.
*
* To restore the fake. Run the `Hash.restore` method.
*/
fake() {
this.fakeDriver = this.fakeDriver || this.createFake();
}
/**
* Restore fake
*/
restore() {
this.fakeDriver = undefined;
}
/**
* Hash value using the default driver
*/
make(value) {
if (this.fakeDriver) {
return this.fakeDriver.make(value);
}
return this.use().make(value);
}
/**
* Verify value using the default driver
*/
verify(hashedValue, plainValue) {
if (this.fakeDriver) {
return this.fakeDriver.verify(hashedValue, plainValue);
}
return this.use().verify(hashedValue, plainValue);
}
/**
* Find if value needs to be re-hashed as per the default driver.
*/
needsReHash(hashedValue) {
if (this.fakeDriver) {
return this.fakeDriver.needsReHash(hashedValue);
}
const driver = this.use();
if (typeof driver.needsReHash !== 'function') {
return false;
}
return driver.needsReHash(hashedValue);
}
/**
* Pull pre-configured driver instance
*/
use(name) {
if (this.fakeDriver) {
return this.fakeDriver;
}
return (name ? super.use(name) : super.use());
}
}
exports.Hash = Hash;
+4
View File
@@ -0,0 +1,4 @@
/// <reference types="node" />
export declare const kMaxUint24 = 16777215;
export declare const kMaxUint31 = 2147483647;
export declare function randomBytesAsync(size: number): Promise<Buffer>;
+22
View File
@@ -0,0 +1,22 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.randomBytesAsync = exports.kMaxUint31 = exports.kMaxUint24 = void 0;
const crypto_1 = require("crypto");
exports.kMaxUint24 = 16777215; // 2**24 - 1
exports.kMaxUint31 = 2147483647; // 2**31 - 1
function randomBytesAsync(size) {
if (size < 0 || size > exports.kMaxUint31) {
return Promise.reject(new TypeError(`The 'length' parameter must be in the range (0 <= length <= ${exports.kMaxUint31})`));
}
return new Promise((resolve, reject) => {
(0, crypto_1.randomBytes)(size, (error, buffer) => {
if (error) {
reject(error);
}
else {
resolve(buffer);
}
});
});
}
exports.randomBytesAsync = randomBytesAsync;
+1
View File
@@ -0,0 +1 @@
export { Hash } from './src/Hash';
+13
View File
@@ -0,0 +1,13 @@
"use strict";
/*
* @adonisjs/hash
*
* (c) Harminder Virk <virk@adonisjs.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.Hash = void 0;
var Hash_1 = require("./src/Hash");
Object.defineProperty(exports, "Hash", { enumerable: true, get: function () { return Hash_1.Hash; } });
+150
View File
@@ -0,0 +1,150 @@
{
"name": "@adonisjs/hash",
"version": "7.2.2",
"description": "Multi driver hash module with support for PHC string formats",
"main": "build/providers/HashProvider",
"files": [
"build/adonis-typings",
"build/providers",
"build/src",
"build/config.d.ts",
"build/config.js",
"build/standalone.d.ts",
"build/standalone.js"
],
"scripts": {
"mrm": "mrm --preset=@adonisjs/mrm-preset",
"pretest": "npm run lint",
"test": "node -r @adonisjs/require-ts/build/register bin/test.ts",
"clean": "del build",
"compile": "npm run lint && npm run clean && tsc",
"build": "npm run compile",
"commit": "git-cz",
"release": "np --message=\"chore(release): %s\"",
"version": "npm run build",
"format": "prettier --write .",
"prepublishOnly": "npm run build",
"lint": "eslint . --ext=.ts",
"sync-labels": "github-label-sync --labels ./node_modules/@adonisjs/mrm-preset/gh-labels.json adonisjs/hash"
},
"repository": {
"type": "git",
"url": "git+ssh://git@github.com/poppinss/hash.git"
},
"keywords": [
"hash",
"bcrypt",
"argon2"
],
"author": "poppinss,virk",
"license": "MIT",
"bugs": {
"url": "https://github.com/poppinss/hash/issues"
},
"homepage": "https://github.com/poppinss/hash#readme",
"devDependencies": {
"@adonisjs/application": "^5.2.5",
"@adonisjs/mrm-preset": "^5.0.3",
"@adonisjs/require-ts": "^2.0.13",
"@japa/assert": "^1.3.6",
"@japa/run-failed-tests": "^1.1.0",
"@japa/runner": "^2.2.2",
"@japa/spec-reporter": "^1.3.2",
"@poppinss/dev-utils": "^2.0.3",
"@types/node": "^18.11.9",
"argon2": "^0.30.2",
"bcrypt": "^5.0.1",
"commitizen": "^4.2.5",
"cz-conventional-changelog": "^3.3.0",
"del-cli": "^5.0.0",
"eslint": "^8.27.0",
"eslint-config-prettier": "^8.5.0",
"eslint-plugin-adonis": "^2.1.1",
"eslint-plugin-prettier": "^4.2.1",
"github-label-sync": "^2.2.0",
"husky": "^8.0.2",
"mrm": "^4.1.13",
"np": "^7.6.2",
"phc-argon2": "^1.1.3",
"phc-bcrypt": "^1.0.8",
"prettier": "^2.7.1",
"typescript": "^4.8.4"
},
"nyc": {
"exclude": [
"test"
],
"extension": [
".ts"
]
},
"husky": {
"hooks": {
"commit-msg": "node ./node_modules/@adonisjs/mrm-preset/validateCommit/conventional/validate.js"
}
},
"config": {
"commitizen": {
"path": "cz-conventional-changelog"
}
},
"np": {
"contents": ".",
"anyBranch": false
},
"dependencies": {
"@phc/format": "^1.0.0",
"@poppinss/manager": "^5.0.2",
"@poppinss/utils": "^5.0.0"
},
"peerDependencies": {
"@adonisjs/application": "^5.0.0"
},
"publishConfig": {
"access": "public",
"tag": "latest"
},
"mrmConfig": {
"core": true,
"license": "MIT",
"services": [
"github-actions"
],
"minNodeVersion": "14.15.4",
"probotApps": [
"stale",
"lock"
],
"runGhActionsOnWindows": false
},
"eslintConfig": {
"extends": [
"plugin:adonis/typescriptPackage",
"prettier"
],
"plugins": [
"prettier"
],
"rules": {
"prettier/prettier": [
"error",
{
"endOfLine": "auto"
}
]
}
},
"eslintIgnore": [
"build"
],
"prettier": {
"trailingComma": "es5",
"semi": false,
"singleQuote": true,
"useTabs": false,
"quoteProps": "consistent",
"bracketSpacing": true,
"arrowParens": "always",
"printWidth": 100
}
}