@h3ravel/hashing 1.29.0-alpha.15 → 2.0.0-alpha.16
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +2 -2
- package/dist/index.js +3 -3
- package/package.json +8 -10
- package/dist/index.cjs +0 -669
package/dist/index.d.ts
CHANGED
|
@@ -183,7 +183,7 @@ declare abstract class Manager extends IBaseHashManager {
|
|
|
183
183
|
* @return string
|
|
184
184
|
*/
|
|
185
185
|
getDefaultDriver(): HashAlgorithm;
|
|
186
|
-
protected createDriver(driver: HashAlgorithm):
|
|
186
|
+
protected createDriver(driver: HashAlgorithm): Argon2idHasher | ArgonHasher | BcryptHasher;
|
|
187
187
|
/**
|
|
188
188
|
* Determine if a given string is already hashed.
|
|
189
189
|
*
|
|
@@ -279,7 +279,7 @@ declare class HashManager extends HashManager_base {
|
|
|
279
279
|
*
|
|
280
280
|
* @throws InvalidArgumentException
|
|
281
281
|
*/
|
|
282
|
-
driver(driver?: HashAlgorithm):
|
|
282
|
+
driver(driver?: HashAlgorithm): Argon2idHasher | ArgonHasher | BcryptHasher;
|
|
283
283
|
}
|
|
284
284
|
declare const defineConfig: (config: HashConfiguration) => HashConfiguration;
|
|
285
285
|
//#endregion
|
package/dist/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { IAbstractHasher, IArgon2idHasher, IArgonHasher, IBaseHashManager, IBcryptHasher, IHashManager } from "@h3ravel/contracts";
|
|
2
2
|
import { InvalidArgumentException, RuntimeException, ServiceProvider, Str } from "@h3ravel/support";
|
|
3
3
|
import argon from "argon2";
|
|
4
|
-
import { mix } from "@h3ravel/shared";
|
|
4
|
+
import { importFile, mix } from "@h3ravel/shared";
|
|
5
5
|
import bcrypt from "bcryptjs";
|
|
6
6
|
import path from "node:path";
|
|
7
7
|
import { existsSync } from "node:fs";
|
|
@@ -416,11 +416,11 @@ var Manager = class extends IBaseHashManager {
|
|
|
416
416
|
const jsPath = path.resolve(basePath, "hashing.config.js");
|
|
417
417
|
const tsPath = path.resolve(basePath, "hashing.config.ts");
|
|
418
418
|
if (existsSync(jsPath)) {
|
|
419
|
-
this.config = (await
|
|
419
|
+
this.config = (await importFile(jsPath)).default ?? {};
|
|
420
420
|
return this;
|
|
421
421
|
}
|
|
422
422
|
if (existsSync(tsPath)) if (process.env.NODE_ENV !== "production") {
|
|
423
|
-
this.config = (await
|
|
423
|
+
this.config = (await importFile(tsPath)).default ?? {};
|
|
424
424
|
return this;
|
|
425
425
|
} else throw new ConfigException("hashing.config.ts found in production without build step");
|
|
426
426
|
return this;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@h3ravel/hashing",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "2.0.0-alpha.16",
|
|
4
4
|
"description": "Secure framework-agnostic Bcrypt and Argon2 hashing for storing user passwords in H3ravel and node Apps.",
|
|
5
5
|
"h3ravel": {
|
|
6
6
|
"providers": [
|
|
@@ -8,9 +8,7 @@
|
|
|
8
8
|
]
|
|
9
9
|
},
|
|
10
10
|
"type": "module",
|
|
11
|
-
"main": "./dist/index.cjs",
|
|
12
11
|
"types": "./dist/index.d.ts",
|
|
13
|
-
"module": "./dist/index.js",
|
|
14
12
|
"exports": {
|
|
15
13
|
".": {
|
|
16
14
|
"import": "./dist/index.js",
|
|
@@ -47,10 +45,10 @@
|
|
|
47
45
|
"typescript": "^6.0.0"
|
|
48
46
|
},
|
|
49
47
|
"peerDependencies": {
|
|
50
|
-
"@h3ravel/core": "^
|
|
51
|
-
"@h3ravel/foundation": "^
|
|
52
|
-
"@h3ravel/shared": "^
|
|
53
|
-
"@h3ravel/support": "^
|
|
48
|
+
"@h3ravel/core": "^2.0.0-alpha.16",
|
|
49
|
+
"@h3ravel/foundation": "^2.0.0-alpha.16",
|
|
50
|
+
"@h3ravel/shared": "^2.0.0-alpha.16",
|
|
51
|
+
"@h3ravel/support": "^2.0.0-alpha.16"
|
|
54
52
|
},
|
|
55
53
|
"peerDependenciesMeta": {
|
|
56
54
|
"@h3ravel/core": {
|
|
@@ -60,12 +58,12 @@
|
|
|
60
58
|
"dependencies": {
|
|
61
59
|
"argon2": "^0.44.0",
|
|
62
60
|
"bcryptjs": "3.0.3",
|
|
63
|
-
"@h3ravel/contracts": "^
|
|
64
|
-
"@h3ravel/foundation": "^
|
|
61
|
+
"@h3ravel/contracts": "^2.0.0-alpha.16",
|
|
62
|
+
"@h3ravel/foundation": "^2.0.0-alpha.16"
|
|
65
63
|
},
|
|
66
64
|
"scripts": {
|
|
67
65
|
"build": "tsdown --config-loader unrun",
|
|
68
|
-
"dev": "
|
|
66
|
+
"dev": "tsdown --watch --config-loader unrun",
|
|
69
67
|
"start": "node dist/index.js",
|
|
70
68
|
"lint": "eslint . --ext .ts",
|
|
71
69
|
"test": "jest --passWithNoTests",
|
package/dist/index.cjs
DELETED
|
@@ -1,669 +0,0 @@
|
|
|
1
|
-
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
-
//#region \0rolldown/runtime.js
|
|
3
|
-
var __create = Object.create;
|
|
4
|
-
var __defProp = Object.defineProperty;
|
|
5
|
-
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
6
|
-
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
7
|
-
var __getProtoOf = Object.getPrototypeOf;
|
|
8
|
-
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
9
|
-
var __copyProps = (to, from, except, desc) => {
|
|
10
|
-
if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
|
|
11
|
-
key = keys[i];
|
|
12
|
-
if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, {
|
|
13
|
-
get: ((k) => from[k]).bind(null, key),
|
|
14
|
-
enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
|
|
15
|
-
});
|
|
16
|
-
}
|
|
17
|
-
return to;
|
|
18
|
-
};
|
|
19
|
-
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
|
|
20
|
-
value: mod,
|
|
21
|
-
enumerable: true
|
|
22
|
-
}) : target, mod));
|
|
23
|
-
//#endregion
|
|
24
|
-
let _h3ravel_contracts = require("@h3ravel/contracts");
|
|
25
|
-
let _h3ravel_support = require("@h3ravel/support");
|
|
26
|
-
let argon2 = require("argon2");
|
|
27
|
-
argon2 = __toESM(argon2, 1);
|
|
28
|
-
let _h3ravel_shared = require("@h3ravel/shared");
|
|
29
|
-
let bcryptjs = require("bcryptjs");
|
|
30
|
-
bcryptjs = __toESM(bcryptjs, 1);
|
|
31
|
-
let node_path = require("node:path");
|
|
32
|
-
node_path = __toESM(node_path, 1);
|
|
33
|
-
let node_fs = require("node:fs");
|
|
34
|
-
let _h3ravel_foundation = require("@h3ravel/foundation");
|
|
35
|
-
let _h3ravel_support_facades = require("@h3ravel/support/facades");
|
|
36
|
-
//#region src/Utils/ParseInfo.ts
|
|
37
|
-
var ParseInfo = class {
|
|
38
|
-
static getInfo(hashed, algo = "bcrypt") {
|
|
39
|
-
if (algo === "bcrypt") return this.bcrypt(hashed);
|
|
40
|
-
return this.argon2(hashed);
|
|
41
|
-
}
|
|
42
|
-
static argon2(hashed) {
|
|
43
|
-
const info = {};
|
|
44
|
-
const parts = hashed.split("$");
|
|
45
|
-
const params = parts[3];
|
|
46
|
-
const versionPart = parts[2];
|
|
47
|
-
if (versionPart && versionPart.startsWith("v=")) {
|
|
48
|
-
const version = parseInt(versionPart.split("=")[1], 10);
|
|
49
|
-
if (!isNaN(version)) info.algo = version;
|
|
50
|
-
}
|
|
51
|
-
if (!params) return info;
|
|
52
|
-
for (const part of params.split(",")) {
|
|
53
|
-
const [key, value] = part.split("=");
|
|
54
|
-
info[key === "m" ? "memoryCost" : key === "t" ? "timeCost" : key === "p" ? "threads" : key] = parseInt(value, 10);
|
|
55
|
-
}
|
|
56
|
-
return info;
|
|
57
|
-
}
|
|
58
|
-
static bcrypt(hashed) {
|
|
59
|
-
const match = hashed.match(/^\$2[aby]?\$(\d+)\$/);
|
|
60
|
-
return { cost: match ? parseInt(match[1], 10) : void 0 };
|
|
61
|
-
}
|
|
62
|
-
};
|
|
63
|
-
//#endregion
|
|
64
|
-
//#region src/Drivers/AbstractHasher.ts
|
|
65
|
-
var AbstractHasher = class extends _h3ravel_contracts.IAbstractHasher {
|
|
66
|
-
/**
|
|
67
|
-
* Get information about the given hashed value.
|
|
68
|
-
*
|
|
69
|
-
* @param hashedValue
|
|
70
|
-
* @returns
|
|
71
|
-
*/
|
|
72
|
-
info(hashedValue) {
|
|
73
|
-
let algoName = "unknown";
|
|
74
|
-
if (hashedValue.startsWith("$2")) algoName = "bcrypt";
|
|
75
|
-
if (hashedValue.startsWith("$argon2id$")) algoName = "argon2id";
|
|
76
|
-
if (hashedValue.startsWith("$argon2i$")) algoName = "argon";
|
|
77
|
-
const options = ParseInfo.getInfo(hashedValue, algoName);
|
|
78
|
-
const algo = options.algo;
|
|
79
|
-
delete options.algo;
|
|
80
|
-
return {
|
|
81
|
-
algo,
|
|
82
|
-
algoName,
|
|
83
|
-
options
|
|
84
|
-
};
|
|
85
|
-
}
|
|
86
|
-
};
|
|
87
|
-
//#endregion
|
|
88
|
-
//#region src/Drivers/Argon2idHasher.ts
|
|
89
|
-
var Argon2idHasher = class extends (0, _h3ravel_shared.mix)(AbstractHasher, _h3ravel_contracts.IArgon2idHasher) {
|
|
90
|
-
memory = 65536;
|
|
91
|
-
verifyAlgorithm = true;
|
|
92
|
-
threads = 1;
|
|
93
|
-
time = 4;
|
|
94
|
-
constructor(options = {}) {
|
|
95
|
-
super();
|
|
96
|
-
this.memory = options.memory ?? this.memory;
|
|
97
|
-
this.verifyAlgorithm = options.verify ?? process.env.HASH_VERIFY ?? this.verifyAlgorithm;
|
|
98
|
-
this.threads = options.threads ?? this.threads;
|
|
99
|
-
this.time = options.time ?? this.time;
|
|
100
|
-
}
|
|
101
|
-
/**
|
|
102
|
-
* Hash the given value using Argon2id.
|
|
103
|
-
*/
|
|
104
|
-
async make(value, options = {}) {
|
|
105
|
-
try {
|
|
106
|
-
return await argon2.default.hash(value, {
|
|
107
|
-
type: argon2.default.argon2id,
|
|
108
|
-
memoryCost: options.memory ?? this.memory,
|
|
109
|
-
timeCost: options.time ?? this.time,
|
|
110
|
-
parallelism: options.threads ?? this.threads
|
|
111
|
-
});
|
|
112
|
-
} catch {
|
|
113
|
-
throw new _h3ravel_support.RuntimeException("Argon2id hashing not supported.");
|
|
114
|
-
}
|
|
115
|
-
}
|
|
116
|
-
/**
|
|
117
|
-
* Check the given plain value against a hash.
|
|
118
|
-
*/
|
|
119
|
-
async check(value, hashedValue, _options = {}) {
|
|
120
|
-
if (!hashedValue || hashedValue.length === 0) return false;
|
|
121
|
-
if (this.verifyAlgorithm && !this.isUsingCorrectAlgorithm(hashedValue)) throw new _h3ravel_support.RuntimeException("This password does not use the Argon2id algorithm.");
|
|
122
|
-
try {
|
|
123
|
-
return await argon2.default.verify(hashedValue, value);
|
|
124
|
-
} catch {
|
|
125
|
-
return false;
|
|
126
|
-
}
|
|
127
|
-
}
|
|
128
|
-
/**
|
|
129
|
-
* Get information about the given hashed value.
|
|
130
|
-
*/
|
|
131
|
-
info(hashedValue) {
|
|
132
|
-
return super.info(hashedValue);
|
|
133
|
-
}
|
|
134
|
-
/**
|
|
135
|
-
* Check if the given hash needs to be rehashed based on current options.
|
|
136
|
-
*/
|
|
137
|
-
needsRehash(hashedValue, options = {}) {
|
|
138
|
-
const parsed = this.parseInfo(hashedValue);
|
|
139
|
-
if (!parsed) return true;
|
|
140
|
-
const { memoryCost, timeCost, threads } = parsed;
|
|
141
|
-
return memoryCost !== (options.memory ?? this.memory) || timeCost !== (options.time ?? this.time) || threads !== (options.threads ?? this.threads);
|
|
142
|
-
}
|
|
143
|
-
/**
|
|
144
|
-
* Verify that the hash configuration does not exceed the configured limits.
|
|
145
|
-
*/
|
|
146
|
-
verifyConfiguration(hashedValue) {
|
|
147
|
-
return this.isUsingCorrectAlgorithm(hashedValue) && this.isUsingValidOptions(hashedValue);
|
|
148
|
-
}
|
|
149
|
-
/**
|
|
150
|
-
* Verify the hashed value's options.
|
|
151
|
-
*/
|
|
152
|
-
isUsingValidOptions(hashedValue) {
|
|
153
|
-
const { options } = this.info(hashedValue);
|
|
154
|
-
if (!options.memoryCost || !options.timeCost || !options.threads) return false;
|
|
155
|
-
return options.memoryCost <= this.memory && options.timeCost <= this.time && options.threads <= this.threads;
|
|
156
|
-
}
|
|
157
|
-
/**
|
|
158
|
-
* Verify the hashed value's algorithm.
|
|
159
|
-
*/
|
|
160
|
-
isUsingCorrectAlgorithm(hashedValue) {
|
|
161
|
-
return this.info(hashedValue).algoName === "argon2id";
|
|
162
|
-
}
|
|
163
|
-
/**
|
|
164
|
-
* Extract Argon parameters from the hash.
|
|
165
|
-
*/
|
|
166
|
-
parseInfo(hashedValue) {
|
|
167
|
-
const parts = hashedValue.split("$");
|
|
168
|
-
const versionPart = parts[2];
|
|
169
|
-
const paramsPart = parts[3];
|
|
170
|
-
const info = {};
|
|
171
|
-
if (versionPart && versionPart.startsWith("v=")) {
|
|
172
|
-
const version = parseInt(versionPart.split("=")[1], 10);
|
|
173
|
-
if (!isNaN(version)) info.algo = version;
|
|
174
|
-
}
|
|
175
|
-
if (paramsPart) for (const param of paramsPart.split(",")) {
|
|
176
|
-
const [key, value] = param.split("=");
|
|
177
|
-
const val = parseInt(value, 10);
|
|
178
|
-
switch (key) {
|
|
179
|
-
case "m":
|
|
180
|
-
info.memoryCost = val;
|
|
181
|
-
break;
|
|
182
|
-
case "t":
|
|
183
|
-
info.timeCost = val;
|
|
184
|
-
break;
|
|
185
|
-
case "p":
|
|
186
|
-
info.threads = val;
|
|
187
|
-
break;
|
|
188
|
-
default: info[key] = val;
|
|
189
|
-
}
|
|
190
|
-
}
|
|
191
|
-
return info;
|
|
192
|
-
}
|
|
193
|
-
};
|
|
194
|
-
//#endregion
|
|
195
|
-
//#region src/Drivers/ArgonHasher.ts
|
|
196
|
-
var ArgonHasher = class extends (0, _h3ravel_shared.mix)(AbstractHasher, _h3ravel_contracts.IArgonHasher) {
|
|
197
|
-
memory = 65536;
|
|
198
|
-
verifyAlgorithm = true;
|
|
199
|
-
threads = 1;
|
|
200
|
-
time = 4;
|
|
201
|
-
constructor(options = {}) {
|
|
202
|
-
super();
|
|
203
|
-
this.memory = options.memory ?? this.memory;
|
|
204
|
-
this.verifyAlgorithm = options.verify ?? process.env.HASH_VERIFY ?? this.verifyAlgorithm;
|
|
205
|
-
this.threads = options.threads ?? this.threads;
|
|
206
|
-
this.time = options.time ?? this.time;
|
|
207
|
-
}
|
|
208
|
-
/**
|
|
209
|
-
* Hash the given value using Argon2i.
|
|
210
|
-
*/
|
|
211
|
-
async make(value, options = {}) {
|
|
212
|
-
try {
|
|
213
|
-
return await argon2.default.hash(value, {
|
|
214
|
-
type: argon2.default.argon2i,
|
|
215
|
-
memoryCost: options.memory ?? this.memory,
|
|
216
|
-
timeCost: options.time ?? this.time,
|
|
217
|
-
parallelism: options.threads ?? this.threads
|
|
218
|
-
});
|
|
219
|
-
} catch {
|
|
220
|
-
throw new _h3ravel_support.RuntimeException("Argon2 hashing not supported.");
|
|
221
|
-
}
|
|
222
|
-
}
|
|
223
|
-
/**
|
|
224
|
-
* Check the given plain value against a hash.
|
|
225
|
-
*/
|
|
226
|
-
async check(value, hashedValue, _options = {}) {
|
|
227
|
-
if (!hashedValue || hashedValue.length === 0) return false;
|
|
228
|
-
if (this.verifyAlgorithm && !this.isUsingCorrectAlgorithm(hashedValue)) throw new _h3ravel_support.RuntimeException("This password does not use the Argon2 algorithm.");
|
|
229
|
-
try {
|
|
230
|
-
return await argon2.default.verify(hashedValue, value);
|
|
231
|
-
} catch {
|
|
232
|
-
return false;
|
|
233
|
-
}
|
|
234
|
-
}
|
|
235
|
-
/**
|
|
236
|
-
* Get information about the given hashed value.
|
|
237
|
-
*/
|
|
238
|
-
info(hashedValue) {
|
|
239
|
-
return super.info(hashedValue);
|
|
240
|
-
}
|
|
241
|
-
/**
|
|
242
|
-
* Check if the given hash needs to be rehashed based on current options.
|
|
243
|
-
*/
|
|
244
|
-
needsRehash(hashedValue, options = {}) {
|
|
245
|
-
const parsed = this.parseInfo(hashedValue);
|
|
246
|
-
if (!parsed) return true;
|
|
247
|
-
const { memoryCost, timeCost, threads } = parsed;
|
|
248
|
-
return memoryCost !== (options.memory ?? this.memory) || timeCost !== (options.time ?? this.time) || threads !== (options.threads ?? this.threads);
|
|
249
|
-
}
|
|
250
|
-
/**
|
|
251
|
-
* Verify that the hash configuration does not exceed the configured limits.
|
|
252
|
-
*/
|
|
253
|
-
verifyConfiguration(hashedValue) {
|
|
254
|
-
return this.isUsingCorrectAlgorithm(hashedValue) && this.isUsingValidOptions(hashedValue);
|
|
255
|
-
}
|
|
256
|
-
/**
|
|
257
|
-
* Verify the hashed value's options.
|
|
258
|
-
*/
|
|
259
|
-
isUsingValidOptions(hashedValue) {
|
|
260
|
-
const { options } = this.info(hashedValue);
|
|
261
|
-
if (!options.memoryCost || !options.timeCost || !options.threads) return false;
|
|
262
|
-
return options.memoryCost <= this.memory && options.timeCost <= this.time && options.threads <= this.threads;
|
|
263
|
-
}
|
|
264
|
-
/**
|
|
265
|
-
* Verify the hashed value's algorithm.
|
|
266
|
-
*/
|
|
267
|
-
isUsingCorrectAlgorithm(hashedValue) {
|
|
268
|
-
return this.info(hashedValue).algoName === "argon";
|
|
269
|
-
}
|
|
270
|
-
/**
|
|
271
|
-
* Extract Argon parameters from the hash.
|
|
272
|
-
*/
|
|
273
|
-
parseInfo(hashedValue) {
|
|
274
|
-
const parts = hashedValue.split("$");
|
|
275
|
-
const versionPart = parts[2];
|
|
276
|
-
const paramsPart = parts[3];
|
|
277
|
-
const info = {};
|
|
278
|
-
if (versionPart && versionPart.startsWith("v=")) {
|
|
279
|
-
const version = parseInt(versionPart.split("=")[1], 10);
|
|
280
|
-
if (!isNaN(version)) info.algo = version;
|
|
281
|
-
}
|
|
282
|
-
if (paramsPart) for (const param of paramsPart.split(",")) {
|
|
283
|
-
const [key, value] = param.split("=");
|
|
284
|
-
const val = parseInt(value, 10);
|
|
285
|
-
switch (key) {
|
|
286
|
-
case "m":
|
|
287
|
-
info.memoryCost = val;
|
|
288
|
-
break;
|
|
289
|
-
case "t":
|
|
290
|
-
info.timeCost = val;
|
|
291
|
-
break;
|
|
292
|
-
case "p":
|
|
293
|
-
info.threads = val;
|
|
294
|
-
break;
|
|
295
|
-
default: info[key] = val;
|
|
296
|
-
}
|
|
297
|
-
}
|
|
298
|
-
return info;
|
|
299
|
-
}
|
|
300
|
-
};
|
|
301
|
-
//#endregion
|
|
302
|
-
//#region src/Drivers/BcryptHasher.ts
|
|
303
|
-
var BcryptHasher = class extends (0, _h3ravel_shared.mix)(AbstractHasher, _h3ravel_contracts.IBcryptHasher) {
|
|
304
|
-
rounds = 12;
|
|
305
|
-
verifyAlgorithm = true;
|
|
306
|
-
limit = null;
|
|
307
|
-
constructor(options = {}) {
|
|
308
|
-
super();
|
|
309
|
-
this.rounds = options.rounds ?? this.rounds;
|
|
310
|
-
this.verifyAlgorithm = options.verify ?? process.env.HASH_VERIFY ?? this.verifyAlgorithm;
|
|
311
|
-
this.limit = options.limit ?? this.limit;
|
|
312
|
-
}
|
|
313
|
-
/**
|
|
314
|
-
* Hash the given value.
|
|
315
|
-
*
|
|
316
|
-
* @param value
|
|
317
|
-
* @param options
|
|
318
|
-
*
|
|
319
|
-
* @return {String}
|
|
320
|
-
*/
|
|
321
|
-
async make(value, options = {}) {
|
|
322
|
-
if (this.limit && value.length > this.limit) throw new _h3ravel_support.InvalidArgumentException(`Value is too long to hash. Value must be less than ${this.limit} bytes`);
|
|
323
|
-
try {
|
|
324
|
-
const salt = await bcryptjs.default.genSalt(this.cost(options));
|
|
325
|
-
return await bcryptjs.default.hash(value, salt);
|
|
326
|
-
} catch {
|
|
327
|
-
throw new _h3ravel_support.RuntimeException("Bcrypt hashing not supported.");
|
|
328
|
-
}
|
|
329
|
-
}
|
|
330
|
-
/**
|
|
331
|
-
* Check the given plain value against a hash.
|
|
332
|
-
*
|
|
333
|
-
* @param value
|
|
334
|
-
* @param hashedValue
|
|
335
|
-
* @param options
|
|
336
|
-
* @returns
|
|
337
|
-
*/
|
|
338
|
-
async check(value, hashedValue, _options = {}) {
|
|
339
|
-
if (!hashedValue || hashedValue.length === 0) return false;
|
|
340
|
-
if (this.verifyAlgorithm && !this.isUsingCorrectAlgorithm(hashedValue)) throw new _h3ravel_support.RuntimeException("This password does not use the Bcrypt algorithm.");
|
|
341
|
-
return bcryptjs.default.compare(value, hashedValue);
|
|
342
|
-
}
|
|
343
|
-
/**
|
|
344
|
-
* Get information about the given hashed value.
|
|
345
|
-
*
|
|
346
|
-
* @param hashedValue
|
|
347
|
-
*
|
|
348
|
-
* @return {Object}
|
|
349
|
-
*/
|
|
350
|
-
info(hashedValue) {
|
|
351
|
-
return super.info(hashedValue);
|
|
352
|
-
}
|
|
353
|
-
/**
|
|
354
|
-
* Check if the given hash has been hashed using the given options.
|
|
355
|
-
*
|
|
356
|
-
* @param hashedValue
|
|
357
|
-
* @param options
|
|
358
|
-
*
|
|
359
|
-
* @return {Boolean}
|
|
360
|
-
*/
|
|
361
|
-
needsRehash(hashedValue, options = {}) {
|
|
362
|
-
const match = hashedValue.match(/^\$2[aby]?\$(\d+)\$/);
|
|
363
|
-
if (!match) return true;
|
|
364
|
-
return parseInt(match[1], 10) !== this.cost(options);
|
|
365
|
-
}
|
|
366
|
-
/**
|
|
367
|
-
* Verify the hashed value's options.
|
|
368
|
-
*
|
|
369
|
-
* @param hashedValue
|
|
370
|
-
* @return
|
|
371
|
-
*/
|
|
372
|
-
isUsingValidOptions(hashedValue) {
|
|
373
|
-
const { options } = this.info(hashedValue);
|
|
374
|
-
if (!options.cost || !Number.isInteger(options.cost ?? null)) return false;
|
|
375
|
-
if (options.cost > this.rounds) return false;
|
|
376
|
-
return true;
|
|
377
|
-
}
|
|
378
|
-
/**
|
|
379
|
-
* Verifies that the configuration is less than or equal to what is configured.
|
|
380
|
-
*
|
|
381
|
-
* @private
|
|
382
|
-
*/
|
|
383
|
-
verifyConfiguration(value) {
|
|
384
|
-
return this.isUsingCorrectAlgorithm(value) && this.isUsingValidOptions(value);
|
|
385
|
-
}
|
|
386
|
-
/**
|
|
387
|
-
* Verify the hashed value's algorithm.
|
|
388
|
-
*
|
|
389
|
-
* @param hashedValue
|
|
390
|
-
*
|
|
391
|
-
* @returns
|
|
392
|
-
*/
|
|
393
|
-
isUsingCorrectAlgorithm(hashedValue) {
|
|
394
|
-
return this.info(hashedValue)["algoName"] === "bcrypt";
|
|
395
|
-
}
|
|
396
|
-
/**
|
|
397
|
-
* Extract the cost value from the options object.
|
|
398
|
-
*
|
|
399
|
-
* @param options
|
|
400
|
-
* @return int
|
|
401
|
-
*/
|
|
402
|
-
cost(options = {}) {
|
|
403
|
-
return options.rounds ?? this.rounds;
|
|
404
|
-
}
|
|
405
|
-
};
|
|
406
|
-
//#endregion
|
|
407
|
-
//#region src/Utils/Manager.ts
|
|
408
|
-
var Manager = class extends _h3ravel_contracts.IBaseHashManager {
|
|
409
|
-
config;
|
|
410
|
-
constructor(config = {}) {
|
|
411
|
-
super();
|
|
412
|
-
this.config = config;
|
|
413
|
-
}
|
|
414
|
-
/**
|
|
415
|
-
* Get the default driver name.
|
|
416
|
-
*
|
|
417
|
-
* @return string
|
|
418
|
-
*/
|
|
419
|
-
getDefaultDriver() {
|
|
420
|
-
return this.config.driver ?? process.env.HASH_DRIVER ?? "bcrypt";
|
|
421
|
-
}
|
|
422
|
-
createDriver(driver) {
|
|
423
|
-
const method = "create" + _h3ravel_support.Str.studly(driver) + "Driver";
|
|
424
|
-
if (typeof this[method] !== "undefined") return this[method]();
|
|
425
|
-
throw new _h3ravel_support.InvalidArgumentException(`Driver [${driver}] not supported.`);
|
|
426
|
-
}
|
|
427
|
-
/**
|
|
428
|
-
* Determine if a given string is already hashed.
|
|
429
|
-
*
|
|
430
|
-
* @param value
|
|
431
|
-
* @returns
|
|
432
|
-
*/
|
|
433
|
-
isHashed(value) {
|
|
434
|
-
return this.driver().info(value).algo !== null;
|
|
435
|
-
}
|
|
436
|
-
/**
|
|
437
|
-
* Autoload config and initialize library
|
|
438
|
-
*
|
|
439
|
-
* @returns
|
|
440
|
-
*/
|
|
441
|
-
async init(basePath = process.cwd()) {
|
|
442
|
-
const jsPath = node_path.default.resolve(basePath, "hashing.config.js");
|
|
443
|
-
const tsPath = node_path.default.resolve(basePath, "hashing.config.ts");
|
|
444
|
-
if ((0, node_fs.existsSync)(jsPath)) {
|
|
445
|
-
this.config = (await import(jsPath)).default ?? {};
|
|
446
|
-
return this;
|
|
447
|
-
}
|
|
448
|
-
if ((0, node_fs.existsSync)(tsPath)) if (process.env.NODE_ENV !== "production") {
|
|
449
|
-
this.config = (await import(tsPath)).default ?? {};
|
|
450
|
-
return this;
|
|
451
|
-
} else throw new _h3ravel_foundation.ConfigException("hashing.config.ts found in production without build step");
|
|
452
|
-
return this;
|
|
453
|
-
}
|
|
454
|
-
};
|
|
455
|
-
//#endregion
|
|
456
|
-
//#region src/HashManager.ts
|
|
457
|
-
var HashManager = class extends (0, _h3ravel_shared.mix)(Manager, _h3ravel_contracts.IHashManager) {
|
|
458
|
-
drivers = {};
|
|
459
|
-
/**
|
|
460
|
-
* Create an instance of the Bcrypt hash Driver.
|
|
461
|
-
*
|
|
462
|
-
* @return BcryptHasher
|
|
463
|
-
*/
|
|
464
|
-
createBcryptDriver() {
|
|
465
|
-
return new BcryptHasher(this.config[this.config.driver]);
|
|
466
|
-
}
|
|
467
|
-
/**
|
|
468
|
-
* Create an instance of the Argon hash Driver.
|
|
469
|
-
*
|
|
470
|
-
* @return ArgonHasher
|
|
471
|
-
*/
|
|
472
|
-
createArgonDriver() {
|
|
473
|
-
return new ArgonHasher(this.config[this.config.driver]);
|
|
474
|
-
}
|
|
475
|
-
/**
|
|
476
|
-
* Create an instance of the Argon2id hash Driver.
|
|
477
|
-
*
|
|
478
|
-
* @return Argon2idHasher
|
|
479
|
-
*/
|
|
480
|
-
createArgon2idDriver() {
|
|
481
|
-
return new Argon2idHasher(this.config[this.config.driver]);
|
|
482
|
-
}
|
|
483
|
-
/**
|
|
484
|
-
* Hash the given value.
|
|
485
|
-
*
|
|
486
|
-
* @param value
|
|
487
|
-
* @param options
|
|
488
|
-
*
|
|
489
|
-
* @returns
|
|
490
|
-
*/
|
|
491
|
-
make(value, options = {}) {
|
|
492
|
-
return this.driver().make(value, options);
|
|
493
|
-
}
|
|
494
|
-
/**
|
|
495
|
-
* Get information about the given hashed value.
|
|
496
|
-
*
|
|
497
|
-
* @param hashedValue
|
|
498
|
-
* @returns
|
|
499
|
-
*/
|
|
500
|
-
info(hashedValue) {
|
|
501
|
-
return this.driver().info(hashedValue);
|
|
502
|
-
}
|
|
503
|
-
/**
|
|
504
|
-
* Check the given plain value against a hash.
|
|
505
|
-
*
|
|
506
|
-
* @param value
|
|
507
|
-
* @param hashedValue
|
|
508
|
-
* @param options
|
|
509
|
-
* @returns
|
|
510
|
-
*/
|
|
511
|
-
check(value, hashedValue, options = {}) {
|
|
512
|
-
return this.driver().check(value, hashedValue, options);
|
|
513
|
-
}
|
|
514
|
-
/**
|
|
515
|
-
* Check if the given hash has been hashed using the given options.
|
|
516
|
-
*
|
|
517
|
-
* @param hashedValue
|
|
518
|
-
* @param options
|
|
519
|
-
* @returns
|
|
520
|
-
*/
|
|
521
|
-
needsRehash(hashedValue, options = {}) {
|
|
522
|
-
return this.driver().needsRehash(hashedValue, options);
|
|
523
|
-
}
|
|
524
|
-
/**
|
|
525
|
-
* Determine if a given string is already hashed.
|
|
526
|
-
*
|
|
527
|
-
* @param string value
|
|
528
|
-
* @returns
|
|
529
|
-
*/
|
|
530
|
-
isHashed(value) {
|
|
531
|
-
return this.driver().info(value)["algo"] !== null;
|
|
532
|
-
}
|
|
533
|
-
/**
|
|
534
|
-
* Verifies that the configuration is less than or equal to what is configured.
|
|
535
|
-
*
|
|
536
|
-
* @param value
|
|
537
|
-
* @return bool
|
|
538
|
-
*
|
|
539
|
-
* @internal
|
|
540
|
-
*/
|
|
541
|
-
verifyConfiguration(value) {
|
|
542
|
-
const driver = this.driver();
|
|
543
|
-
if (typeof driver.verifyConfiguration !== "undefined") return driver.verifyConfiguration(value);
|
|
544
|
-
return true;
|
|
545
|
-
}
|
|
546
|
-
/**
|
|
547
|
-
* Get a driver instance.
|
|
548
|
-
*
|
|
549
|
-
* @param driver
|
|
550
|
-
*
|
|
551
|
-
* @returns
|
|
552
|
-
*
|
|
553
|
-
* @throws InvalidArgumentException
|
|
554
|
-
*/
|
|
555
|
-
driver(driver) {
|
|
556
|
-
driver = driver ?? this.getDefaultDriver();
|
|
557
|
-
if (!driver) throw new _h3ravel_support.InvalidArgumentException(`Unable to resolve NULL driver for ${this.constructor.name}.'`);
|
|
558
|
-
return this.drivers[driver] ??= this.createDriver(driver);
|
|
559
|
-
}
|
|
560
|
-
};
|
|
561
|
-
const defineConfig = (config) => {
|
|
562
|
-
return config;
|
|
563
|
-
};
|
|
564
|
-
//#endregion
|
|
565
|
-
//#region src/Helpers.ts
|
|
566
|
-
var Hash = class Hash {
|
|
567
|
-
/**
|
|
568
|
-
* Hash the given value.
|
|
569
|
-
*
|
|
570
|
-
* @param value
|
|
571
|
-
* @param options
|
|
572
|
-
*
|
|
573
|
-
* @returns
|
|
574
|
-
*/
|
|
575
|
-
static make(value, options = {}) {
|
|
576
|
-
return this.driver().make(value, options);
|
|
577
|
-
}
|
|
578
|
-
/**
|
|
579
|
-
* Get information about the given hashed value.
|
|
580
|
-
*
|
|
581
|
-
* @param hashedValue
|
|
582
|
-
* @returns
|
|
583
|
-
*/
|
|
584
|
-
static info(hashedValue) {
|
|
585
|
-
return this.driver().info(hashedValue);
|
|
586
|
-
}
|
|
587
|
-
/**
|
|
588
|
-
* Check the given plain value against a hash.
|
|
589
|
-
*
|
|
590
|
-
* @param value
|
|
591
|
-
* @param hashedValue
|
|
592
|
-
* @param options
|
|
593
|
-
* @returns
|
|
594
|
-
*/
|
|
595
|
-
static check(value, hashedValue, options = {}) {
|
|
596
|
-
return this.driver().check(value, hashedValue, options);
|
|
597
|
-
}
|
|
598
|
-
/**
|
|
599
|
-
* Check if the given hash has been hashed using the given options.
|
|
600
|
-
*
|
|
601
|
-
* @param hashedValue
|
|
602
|
-
* @param options
|
|
603
|
-
* @returns
|
|
604
|
-
*/
|
|
605
|
-
static needsRehash(hashedValue, options = {}) {
|
|
606
|
-
return this.driver().needsRehash(hashedValue, options);
|
|
607
|
-
}
|
|
608
|
-
/**
|
|
609
|
-
* Determine if a given string is already hashed.
|
|
610
|
-
*
|
|
611
|
-
* @param string value
|
|
612
|
-
* @returns
|
|
613
|
-
*/
|
|
614
|
-
static isHashed(value) {
|
|
615
|
-
return this.driver().isHashed(value);
|
|
616
|
-
}
|
|
617
|
-
/**
|
|
618
|
-
* Verifies that the configuration is less than or equal to what is configured.
|
|
619
|
-
*
|
|
620
|
-
* @param value
|
|
621
|
-
* @return bool
|
|
622
|
-
*
|
|
623
|
-
* @internal
|
|
624
|
-
*/
|
|
625
|
-
static verifyConfiguration(value) {
|
|
626
|
-
return this.driver().verifyConfiguration(value);
|
|
627
|
-
}
|
|
628
|
-
/**
|
|
629
|
-
* Get a driver instance.
|
|
630
|
-
*
|
|
631
|
-
* @param driver
|
|
632
|
-
*
|
|
633
|
-
* @returns
|
|
634
|
-
*
|
|
635
|
-
* @throws {RuntimeException}
|
|
636
|
-
*/
|
|
637
|
-
static driver() {
|
|
638
|
-
if (typeof Hash === "undefined") throw new _h3ravel_support.RuntimeException("The Hash helper is only available on H3ravel, use the HashManager class instead.");
|
|
639
|
-
return _h3ravel_support_facades.Hash;
|
|
640
|
-
}
|
|
641
|
-
};
|
|
642
|
-
//#endregion
|
|
643
|
-
//#region src/Providers/HashingServiceProvider.ts
|
|
644
|
-
/**
|
|
645
|
-
* Register HashManager.
|
|
646
|
-
*/
|
|
647
|
-
var HashingServiceProvider = class extends _h3ravel_support.ServiceProvider {
|
|
648
|
-
static priority = 991;
|
|
649
|
-
register() {
|
|
650
|
-
const manager = new HashManager(this.app.make("config").get("hashing"));
|
|
651
|
-
this.app.singleton("hash", () => {
|
|
652
|
-
return manager;
|
|
653
|
-
});
|
|
654
|
-
this.app.singleton("hash.driver", () => {
|
|
655
|
-
return manager.driver();
|
|
656
|
-
});
|
|
657
|
-
}
|
|
658
|
-
};
|
|
659
|
-
//#endregion
|
|
660
|
-
exports.AbstractHasher = AbstractHasher;
|
|
661
|
-
exports.Argon2idHasher = Argon2idHasher;
|
|
662
|
-
exports.ArgonHasher = ArgonHasher;
|
|
663
|
-
exports.BcryptHasher = BcryptHasher;
|
|
664
|
-
exports.Hash = Hash;
|
|
665
|
-
exports.HashManager = HashManager;
|
|
666
|
-
exports.HashingServiceProvider = HashingServiceProvider;
|
|
667
|
-
exports.Manager = Manager;
|
|
668
|
-
exports.ParseInfo = ParseInfo;
|
|
669
|
-
exports.defineConfig = defineConfig;
|