@nest-boot/hash 7.0.2 → 7.1.0
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/hash.module.js +13 -1
- package/dist/hash.module.js.map +1 -1
- package/dist/hash.service.d.ts +52 -14
- package/dist/hash.service.js +68 -40
- package/dist/hash.service.js.map +1 -1
- package/dist/hash.service.spec.js +188 -30
- package/dist/hash.service.spec.js.map +1 -1
- package/dist/tsconfig.build.tsbuildinfo +1 -1
- package/package.json +6 -2
package/dist/hash.module.js
CHANGED
|
@@ -49,6 +49,18 @@ let HashModule = class HashModule extends hash_module_definition_1.ConfigurableM
|
|
|
49
49
|
exports.HashModule = HashModule;
|
|
50
50
|
exports.HashModule = HashModule = __decorate([
|
|
51
51
|
(0, common_1.Global)(),
|
|
52
|
-
(0, common_1.Module)({
|
|
52
|
+
(0, common_1.Module)({
|
|
53
|
+
providers: [
|
|
54
|
+
{
|
|
55
|
+
provide: hash_service_1.HashService,
|
|
56
|
+
inject: [{ token: hash_module_definition_1.MODULE_OPTIONS_TOKEN, optional: true }],
|
|
57
|
+
useFactory: (options) => {
|
|
58
|
+
hash_service_1.HashService.init(options.secret ?? process.env.HASH_SECRET ?? process.env.APP_SECRET);
|
|
59
|
+
return hash_service_1.HashService.instance;
|
|
60
|
+
},
|
|
61
|
+
},
|
|
62
|
+
],
|
|
63
|
+
exports: [hash_service_1.HashService],
|
|
64
|
+
})
|
|
53
65
|
], HashModule);
|
|
54
66
|
//# sourceMappingURL=hash.module.js.map
|
package/dist/hash.module.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hash.module.js","sourceRoot":"","sources":["../src/hash.module.ts"],"names":[],"mappings":";;;;;;;;;AAAA,2CAAoE;AAEpE,
|
|
1
|
+
{"version":3,"file":"hash.module.js","sourceRoot":"","sources":["../src/hash.module.ts"],"names":[],"mappings":";;;;;;;;;AAAA,2CAAoE;AAEpE,qEAKkC;AAClC,iDAA6C;AAG7C;;;;;;;;;;;;;;;;;GAiBG;AAkBI,IAAM,UAAU,GAAhB,MAAM,UAAW,SAAQ,gDAAuB;IACrD;;;;OAIG;IACH,MAAM,CAAU,QAAQ,CAAC,OAA4B;QACnD,OAAO,KAAK,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;IACjC,CAAC;IAED;;;;OAIG;IACH,MAAM,CAAU,aAAa,CAC3B,OAAkC;QAElC,OAAO,KAAK,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC;IACtC,CAAC;CACF,CAAA;AApBY,gCAAU;qBAAV,UAAU;IAjBtB,IAAA,eAAM,GAAE;IACR,IAAA,eAAM,EAAC;QACN,SAAS,EAAE;YACT;gBACE,OAAO,EAAE,0BAAW;gBACpB,MAAM,EAAE,CAAC,EAAE,KAAK,EAAE,6CAAoB,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;gBACzD,UAAU,EAAE,CAAC,OAA0B,EAAE,EAAE;oBACzC,0BAAW,CAAC,IAAI,CACd,OAAO,CAAC,MAAM,IAAI,OAAO,CAAC,GAAG,CAAC,WAAW,IAAI,OAAO,CAAC,GAAG,CAAC,UAAU,CACpE,CAAC;oBAEF,OAAO,0BAAW,CAAC,QAAQ,CAAC;gBAC9B,CAAC;aACF;SACF;QACD,OAAO,EAAE,CAAC,0BAAW,CAAC;KACvB,CAAC;GACW,UAAU,CAoBtB"}
|
package/dist/hash.service.d.ts
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { HashModuleOptions } from "./hash-module-options.interface";
|
|
2
1
|
/**
|
|
3
2
|
* Service that provides password hashing and verification using Argon2 algorithm.
|
|
4
3
|
*
|
|
@@ -6,32 +5,71 @@ import { HashModuleOptions } from "./hash-module-options.interface";
|
|
|
6
5
|
* ```typescript
|
|
7
6
|
* import { HashService } from '@nest-boot/hash';
|
|
8
7
|
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
* constructor(private readonly hashService: HashService) {}
|
|
8
|
+
* // Initialize at application startup
|
|
9
|
+
* HashService.init(process.env.HASH_SECRET);
|
|
12
10
|
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
* async verifyPassword(hash: string, password: string): Promise<boolean> {
|
|
18
|
-
* return this.hashService.verify(hash, password);
|
|
19
|
-
* }
|
|
20
|
-
* }
|
|
11
|
+
* // Use static methods
|
|
12
|
+
* const hashed = await HashService.hash(password);
|
|
13
|
+
* const isValid = await HashService.verify(hashed, password);
|
|
21
14
|
* ```
|
|
22
15
|
*/
|
|
23
16
|
export declare class HashService {
|
|
17
|
+
private static _instance?;
|
|
18
|
+
/**
|
|
19
|
+
* Gets the static HashService instance.
|
|
20
|
+
* @throws Error if HashService has not been initialized via `init()`
|
|
21
|
+
* @returns The HashService instance
|
|
22
|
+
*/
|
|
23
|
+
static get instance(): HashService;
|
|
24
|
+
/**
|
|
25
|
+
* Initializes the static HashService instance with the given secret.
|
|
26
|
+
* Call this method at application startup to configure the default secret.
|
|
27
|
+
*
|
|
28
|
+
* @param secret - The secret key to use for hashing
|
|
29
|
+
*
|
|
30
|
+
* @example
|
|
31
|
+
* ```typescript
|
|
32
|
+
* // In your application bootstrap
|
|
33
|
+
* HashService.init(process.env.HASH_SECRET);
|
|
34
|
+
* ```
|
|
35
|
+
*/
|
|
36
|
+
static init(secret?: string): void;
|
|
37
|
+
/**
|
|
38
|
+
* Creates a hash from the given value using the static instance.
|
|
39
|
+
* @param value - The value to hash (password or other sensitive data)
|
|
40
|
+
* @param secret - Optional secret key to use instead of the default
|
|
41
|
+
* @returns The hashed string
|
|
42
|
+
* @throws Error if HashService has not been initialized via `init()`
|
|
43
|
+
*/
|
|
44
|
+
static hash(value: string | Buffer, secret?: string): Promise<string>;
|
|
45
|
+
/**
|
|
46
|
+
* Verifies a value against a hash using the static instance.
|
|
47
|
+
* @param hashed - The hash to verify against
|
|
48
|
+
* @param value - The value to verify
|
|
49
|
+
* @param secret - Optional secret key to use instead of the default
|
|
50
|
+
* @returns True if the value matches the hash, false otherwise
|
|
51
|
+
* @throws Error if HashService has not been initialized via `init()`
|
|
52
|
+
*/
|
|
53
|
+
static verify(hashed: string | Buffer, value: string | Buffer, secret?: string): Promise<boolean>;
|
|
24
54
|
private readonly secret?;
|
|
25
55
|
/**
|
|
26
56
|
* Creates an instance of HashService.
|
|
27
|
-
* @param
|
|
57
|
+
* @param secret - Optional secret key to use for hashing
|
|
58
|
+
*/
|
|
59
|
+
constructor(secret?: string);
|
|
60
|
+
/**
|
|
61
|
+
* Creates a hash from the given value using Argon2.
|
|
62
|
+
* @param value - The value to hash (password or other sensitive data)
|
|
63
|
+
* @param secret - Optional secret key to use instead of the default
|
|
64
|
+
* @returns The hashed string
|
|
28
65
|
*/
|
|
29
|
-
|
|
66
|
+
hash(value: string | Buffer, secret?: string): Promise<string>;
|
|
30
67
|
/**
|
|
31
68
|
* Creates a hash from the given value using Argon2.
|
|
32
69
|
* @param value - The value to hash (password or other sensitive data)
|
|
33
70
|
* @param secret - Optional secret key to use instead of the default
|
|
34
71
|
* @returns The hashed string
|
|
72
|
+
* @deprecated Use `hash` instead
|
|
35
73
|
*/
|
|
36
74
|
create(value: string | Buffer, secret?: string): Promise<string>;
|
|
37
75
|
/**
|
package/dist/hash.service.js
CHANGED
|
@@ -1,21 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
3
|
-
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
4
|
-
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
5
|
-
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
6
|
-
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
7
|
-
};
|
|
8
|
-
var __metadata = (this && this.__metadata) || function (k, v) {
|
|
9
|
-
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
10
|
-
};
|
|
11
|
-
var __param = (this && this.__param) || function (paramIndex, decorator) {
|
|
12
|
-
return function (target, key) { decorator(target, key, paramIndex); }
|
|
13
|
-
};
|
|
14
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
3
|
exports.HashService = void 0;
|
|
16
|
-
const common_1 = require("@nestjs/common");
|
|
17
4
|
const argon2_1 = require("@node-rs/argon2");
|
|
18
|
-
const hash_module_definition_1 = require("./hash.module-definition");
|
|
19
5
|
/**
|
|
20
6
|
* Service that provides password hashing and verification using Argon2 algorithm.
|
|
21
7
|
*
|
|
@@ -23,30 +9,68 @@ const hash_module_definition_1 = require("./hash.module-definition");
|
|
|
23
9
|
* ```typescript
|
|
24
10
|
* import { HashService } from '@nest-boot/hash';
|
|
25
11
|
*
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
-
* constructor(private readonly hashService: HashService) {}
|
|
12
|
+
* // Initialize at application startup
|
|
13
|
+
* HashService.init(process.env.HASH_SECRET);
|
|
29
14
|
*
|
|
30
|
-
*
|
|
31
|
-
*
|
|
32
|
-
*
|
|
33
|
-
*
|
|
34
|
-
* async verifyPassword(hash: string, password: string): Promise<boolean> {
|
|
35
|
-
* return this.hashService.verify(hash, password);
|
|
36
|
-
* }
|
|
37
|
-
* }
|
|
15
|
+
* // Use static methods
|
|
16
|
+
* const hashed = await HashService.hash(password);
|
|
17
|
+
* const isValid = await HashService.verify(hashed, password);
|
|
38
18
|
* ```
|
|
39
19
|
*/
|
|
40
|
-
|
|
20
|
+
class HashService {
|
|
41
21
|
/**
|
|
42
|
-
*
|
|
43
|
-
* @
|
|
22
|
+
* Gets the static HashService instance.
|
|
23
|
+
* @throws Error if HashService has not been initialized via `init()`
|
|
24
|
+
* @returns The HashService instance
|
|
44
25
|
*/
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
this.secret = Buffer.from(secret);
|
|
26
|
+
static get instance() {
|
|
27
|
+
if (!this._instance) {
|
|
28
|
+
throw new Error("HashService not initialized");
|
|
49
29
|
}
|
|
30
|
+
return this._instance;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Initializes the static HashService instance with the given secret.
|
|
34
|
+
* Call this method at application startup to configure the default secret.
|
|
35
|
+
*
|
|
36
|
+
* @param secret - The secret key to use for hashing
|
|
37
|
+
*
|
|
38
|
+
* @example
|
|
39
|
+
* ```typescript
|
|
40
|
+
* // In your application bootstrap
|
|
41
|
+
* HashService.init(process.env.HASH_SECRET);
|
|
42
|
+
* ```
|
|
43
|
+
*/
|
|
44
|
+
static init(secret) {
|
|
45
|
+
this._instance = new HashService(secret);
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Creates a hash from the given value using the static instance.
|
|
49
|
+
* @param value - The value to hash (password or other sensitive data)
|
|
50
|
+
* @param secret - Optional secret key to use instead of the default
|
|
51
|
+
* @returns The hashed string
|
|
52
|
+
* @throws Error if HashService has not been initialized via `init()`
|
|
53
|
+
*/
|
|
54
|
+
static hash(value, secret) {
|
|
55
|
+
return this.instance.hash(value, secret);
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Verifies a value against a hash using the static instance.
|
|
59
|
+
* @param hashed - The hash to verify against
|
|
60
|
+
* @param value - The value to verify
|
|
61
|
+
* @param secret - Optional secret key to use instead of the default
|
|
62
|
+
* @returns True if the value matches the hash, false otherwise
|
|
63
|
+
* @throws Error if HashService has not been initialized via `init()`
|
|
64
|
+
*/
|
|
65
|
+
static verify(hashed, value, secret) {
|
|
66
|
+
return this.instance.verify(hashed, value, secret);
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Creates an instance of HashService.
|
|
70
|
+
* @param secret - Optional secret key to use for hashing
|
|
71
|
+
*/
|
|
72
|
+
constructor(secret) {
|
|
73
|
+
this.secret = secret ? Buffer.from(secret) : undefined;
|
|
50
74
|
}
|
|
51
75
|
/**
|
|
52
76
|
* Creates a hash from the given value using Argon2.
|
|
@@ -54,11 +78,21 @@ let HashService = class HashService {
|
|
|
54
78
|
* @param secret - Optional secret key to use instead of the default
|
|
55
79
|
* @returns The hashed string
|
|
56
80
|
*/
|
|
57
|
-
async
|
|
81
|
+
async hash(value, secret) {
|
|
58
82
|
return await (0, argon2_1.hash)(value, {
|
|
59
83
|
secret: typeof secret !== "undefined" ? Buffer.from(secret) : this.secret,
|
|
60
84
|
});
|
|
61
85
|
}
|
|
86
|
+
/**
|
|
87
|
+
* Creates a hash from the given value using Argon2.
|
|
88
|
+
* @param value - The value to hash (password or other sensitive data)
|
|
89
|
+
* @param secret - Optional secret key to use instead of the default
|
|
90
|
+
* @returns The hashed string
|
|
91
|
+
* @deprecated Use `hash` instead
|
|
92
|
+
*/
|
|
93
|
+
async create(value, secret) {
|
|
94
|
+
return await this.hash(value, secret);
|
|
95
|
+
}
|
|
62
96
|
/**
|
|
63
97
|
* Verifies a value against a hash.
|
|
64
98
|
* @param hashed - The hash to verify against
|
|
@@ -71,12 +105,6 @@ let HashService = class HashService {
|
|
|
71
105
|
secret: typeof secret !== "undefined" ? Buffer.from(secret) : this.secret,
|
|
72
106
|
});
|
|
73
107
|
}
|
|
74
|
-
}
|
|
108
|
+
}
|
|
75
109
|
exports.HashService = HashService;
|
|
76
|
-
exports.HashService = HashService = __decorate([
|
|
77
|
-
(0, common_1.Injectable)(),
|
|
78
|
-
__param(0, (0, common_1.Optional)()),
|
|
79
|
-
__param(0, (0, common_1.Inject)(hash_module_definition_1.MODULE_OPTIONS_TOKEN)),
|
|
80
|
-
__metadata("design:paramtypes", [Object])
|
|
81
|
-
], HashService);
|
|
82
110
|
//# sourceMappingURL=hash.service.js.map
|
package/dist/hash.service.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hash.service.js","sourceRoot":"","sources":["../src/hash.service.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"hash.service.js","sourceRoot":"","sources":["../src/hash.service.ts"],"names":[],"mappings":";;;AAAA,4CAA+C;AAE/C;;;;;;;;;;;;;;GAcG;AAEH,MAAa,WAAW;IAGtB;;;;OAIG;IACH,MAAM,KAAK,QAAQ;QACjB,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,CAAC;YACpB,MAAM,IAAI,KAAK,CAAC,6BAA6B,CAAC,CAAC;QACjD,CAAC;QAED,OAAO,IAAI,CAAC,SAAS,CAAC;IACxB,CAAC;IAED;;;;;;;;;;;OAWG;IACH,MAAM,CAAC,IAAI,CAAC,MAAe;QACzB,IAAI,CAAC,SAAS,GAAG,IAAI,WAAW,CAAC,MAAM,CAAC,CAAC;IAC3C,CAAC;IAED;;;;;;OAMG;IACH,MAAM,CAAC,IAAI,CAAC,KAAsB,EAAE,MAAe;QACjD,OAAO,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;IAC3C,CAAC;IAED;;;;;;;OAOG;IACH,MAAM,CAAC,MAAM,CACX,MAAuB,EACvB,KAAsB,EACtB,MAAe;QAEf,OAAO,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,KAAK,EAAE,MAAM,CAAC,CAAC;IACrD,CAAC;IAID;;;OAGG;IACH,YAAY,MAAe;QACzB,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;IACzD,CAAC;IAED;;;;;OAKG;IACH,KAAK,CAAC,IAAI,CAAC,KAAsB,EAAE,MAAe;QAChD,OAAO,MAAM,IAAA,aAAI,EAAC,KAAK,EAAE;YACvB,MAAM,EAAE,OAAO,MAAM,KAAK,WAAW,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM;SAC1E,CAAC,CAAC;IACL,CAAC;IAED;;;;;;OAMG;IACH,KAAK,CAAC,MAAM,CAAC,KAAsB,EAAE,MAAe;QAClD,OAAO,MAAM,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;IACxC,CAAC;IAED;;;;;;OAMG;IACH,KAAK,CAAC,MAAM,CACV,MAAuB,EACvB,KAAsB,EACtB,MAAe;QAEf,OAAO,MAAM,IAAA,eAAM,EAAC,MAAM,EAAE,KAAK,EAAE;YACjC,MAAM,EAAE,OAAO,MAAM,KAAK,WAAW,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM;SAC1E,CAAC,CAAC;IACL,CAAC;CACF;AA5GD,kCA4GC"}
|
|
@@ -1,42 +1,200 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
/* eslint-disable @typescript-eslint/no-deprecated */
|
|
2
3
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
4
|
const testing_1 = require("@nestjs/testing");
|
|
4
5
|
const _1 = require(".");
|
|
5
6
|
describe("HashService", () => {
|
|
6
7
|
const globalSecret = "myGlobalSecret";
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
8
|
+
describe("instance methods (via HashModule.register)", () => {
|
|
9
|
+
let hashService;
|
|
10
|
+
beforeEach(async () => {
|
|
11
|
+
const moduleRef = await testing_1.Test.createTestingModule({
|
|
12
|
+
imports: [_1.HashModule.register({ secret: globalSecret })],
|
|
13
|
+
}).compile();
|
|
14
|
+
hashService = moduleRef.get(_1.HashService);
|
|
15
|
+
});
|
|
16
|
+
describe("hash", () => {
|
|
17
|
+
it("should create a hash with the provided value and secret", async () => {
|
|
18
|
+
const value = "password";
|
|
19
|
+
const secret = "mySecret";
|
|
20
|
+
const result = await hashService.hash(value, secret);
|
|
21
|
+
expect(result).toBeDefined();
|
|
22
|
+
expect(result).toContain("$argon2");
|
|
23
|
+
});
|
|
24
|
+
it("should create a hash with the provided value and default secret", async () => {
|
|
25
|
+
const value = "password";
|
|
26
|
+
const result = await hashService.hash(value);
|
|
27
|
+
expect(result).toBeDefined();
|
|
28
|
+
expect(result).toContain("$argon2");
|
|
29
|
+
});
|
|
30
|
+
});
|
|
31
|
+
describe("create (deprecated)", () => {
|
|
32
|
+
it("should create a hash with the provided value and secret", async () => {
|
|
33
|
+
const value = "password";
|
|
34
|
+
const secret = "mySecret";
|
|
35
|
+
const result = await hashService.create(value, secret);
|
|
36
|
+
expect(result).toBeDefined();
|
|
37
|
+
expect(result).toContain("$argon2");
|
|
38
|
+
});
|
|
39
|
+
it("should create a hash with the provided value and default secret", async () => {
|
|
40
|
+
const value = "password";
|
|
41
|
+
const result = await hashService.create(value);
|
|
42
|
+
expect(result).toBeDefined();
|
|
43
|
+
expect(result).toContain("$argon2");
|
|
44
|
+
});
|
|
45
|
+
});
|
|
46
|
+
describe("verify", () => {
|
|
47
|
+
it("should verify the hashed value with the provided value and secret", async () => {
|
|
48
|
+
const value = "password";
|
|
49
|
+
const secret = "mySecret";
|
|
50
|
+
const hashed = await hashService.hash(value, secret);
|
|
51
|
+
const result = await hashService.verify(hashed, value, secret);
|
|
52
|
+
expect(result).toBe(true);
|
|
53
|
+
});
|
|
54
|
+
it("should verify the hashed value with the provided value and default secret", async () => {
|
|
55
|
+
const value = "password";
|
|
56
|
+
const hashed = await hashService.hash(value);
|
|
57
|
+
const result = await hashService.verify(hashed, value);
|
|
58
|
+
expect(result).toBe(true);
|
|
59
|
+
});
|
|
60
|
+
it("should return false for incorrect password", async () => {
|
|
61
|
+
const value = "password";
|
|
62
|
+
const hashed = await hashService.hash(value);
|
|
63
|
+
const result = await hashService.verify(hashed, "wrongpassword");
|
|
64
|
+
expect(result).toBe(false);
|
|
65
|
+
});
|
|
66
|
+
});
|
|
67
|
+
});
|
|
68
|
+
describe("static methods", () => {
|
|
69
|
+
beforeEach(() => {
|
|
70
|
+
// Reset static instance before each test
|
|
71
|
+
_1.HashService._instance =
|
|
72
|
+
undefined;
|
|
73
|
+
});
|
|
74
|
+
describe("instance getter", () => {
|
|
75
|
+
it("should throw error when not initialized", () => {
|
|
76
|
+
expect(() => _1.HashService.instance).toThrow("HashService not initialized");
|
|
77
|
+
});
|
|
78
|
+
it("should return instance after initialization", () => {
|
|
79
|
+
_1.HashService.init("secret");
|
|
80
|
+
expect(_1.HashService.instance).toBeInstanceOf(_1.HashService);
|
|
81
|
+
});
|
|
82
|
+
});
|
|
83
|
+
describe("init", () => {
|
|
84
|
+
it("should initialize with secret", () => {
|
|
85
|
+
_1.HashService.init("mySecret");
|
|
86
|
+
expect(_1.HashService.instance).toBeDefined();
|
|
87
|
+
});
|
|
88
|
+
it("should initialize without secret", () => {
|
|
89
|
+
_1.HashService.init();
|
|
90
|
+
expect(_1.HashService.instance).toBeDefined();
|
|
91
|
+
});
|
|
92
|
+
});
|
|
93
|
+
describe("hash (static)", () => {
|
|
94
|
+
it("should create a hash using static method", async () => {
|
|
95
|
+
_1.HashService.init("mySecret");
|
|
96
|
+
const value = "password";
|
|
97
|
+
const result = await _1.HashService.hash(value);
|
|
98
|
+
expect(result).toBeDefined();
|
|
99
|
+
expect(result).toContain("$argon2");
|
|
100
|
+
});
|
|
101
|
+
it("should create a hash with custom secret using static method", async () => {
|
|
102
|
+
_1.HashService.init();
|
|
103
|
+
const value = "password";
|
|
104
|
+
const secret = "customSecret";
|
|
105
|
+
const result = await _1.HashService.hash(value, secret);
|
|
106
|
+
expect(result).toBeDefined();
|
|
107
|
+
expect(result).toContain("$argon2");
|
|
108
|
+
});
|
|
109
|
+
});
|
|
110
|
+
describe("verify (static)", () => {
|
|
111
|
+
it("should verify using static method", async () => {
|
|
112
|
+
_1.HashService.init("mySecret");
|
|
113
|
+
const value = "password";
|
|
114
|
+
const hashed = await _1.HashService.hash(value);
|
|
115
|
+
const result = await _1.HashService.verify(hashed, value);
|
|
116
|
+
expect(result).toBe(true);
|
|
117
|
+
});
|
|
118
|
+
it("should verify with custom secret using static method", async () => {
|
|
119
|
+
_1.HashService.init();
|
|
120
|
+
const value = "password";
|
|
121
|
+
const secret = "customSecret";
|
|
122
|
+
const hashed = await _1.HashService.hash(value, secret);
|
|
123
|
+
const result = await _1.HashService.verify(hashed, value, secret);
|
|
124
|
+
expect(result).toBe(true);
|
|
125
|
+
});
|
|
126
|
+
});
|
|
13
127
|
});
|
|
14
|
-
describe("
|
|
15
|
-
it("should create
|
|
16
|
-
const
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
const value = "password";
|
|
23
|
-
const result = await hashService.create(value);
|
|
24
|
-
expect(result).toBeDefined();
|
|
128
|
+
describe("constructor", () => {
|
|
129
|
+
it("should create instance with secret", () => {
|
|
130
|
+
const service = new _1.HashService("mySecret");
|
|
131
|
+
expect(service).toBeDefined();
|
|
132
|
+
});
|
|
133
|
+
it("should create instance without secret", () => {
|
|
134
|
+
const service = new _1.HashService();
|
|
135
|
+
expect(service).toBeDefined();
|
|
25
136
|
});
|
|
26
137
|
});
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
138
|
+
});
|
|
139
|
+
describe("HashModule", () => {
|
|
140
|
+
const originalEnv = process.env;
|
|
141
|
+
beforeEach(() => {
|
|
142
|
+
// Reset static instance before each test
|
|
143
|
+
_1.HashService._instance = undefined;
|
|
144
|
+
// Reset environment variables
|
|
145
|
+
process.env = { ...originalEnv };
|
|
146
|
+
delete process.env.HASH_SECRET;
|
|
147
|
+
delete process.env.APP_SECRET;
|
|
148
|
+
});
|
|
149
|
+
afterAll(() => {
|
|
150
|
+
process.env = originalEnv;
|
|
151
|
+
});
|
|
152
|
+
describe("registerAsync", () => {
|
|
153
|
+
it("should register module with async factory", async () => {
|
|
154
|
+
const moduleRef = await testing_1.Test.createTestingModule({
|
|
155
|
+
imports: [
|
|
156
|
+
_1.HashModule.registerAsync({
|
|
157
|
+
useFactory: () => ({
|
|
158
|
+
secret: "asyncSecret",
|
|
159
|
+
}),
|
|
160
|
+
}),
|
|
161
|
+
],
|
|
162
|
+
}).compile();
|
|
163
|
+
const hashService = moduleRef.get(_1.HashService);
|
|
164
|
+
expect(hashService).toBeDefined();
|
|
165
|
+
const hashed = await hashService.hash("password");
|
|
166
|
+
expect(hashed).toContain("$argon2");
|
|
167
|
+
});
|
|
168
|
+
});
|
|
169
|
+
describe("register with fallback secrets", () => {
|
|
170
|
+
it("should use HASH_SECRET env when no secret provided", async () => {
|
|
171
|
+
process.env.HASH_SECRET = "envHashSecret";
|
|
172
|
+
const moduleRef = await testing_1.Test.createTestingModule({
|
|
173
|
+
imports: [_1.HashModule.register({})],
|
|
174
|
+
}).compile();
|
|
175
|
+
const hashService = moduleRef.get(_1.HashService);
|
|
176
|
+
expect(hashService).toBeDefined();
|
|
177
|
+
const hashed = await hashService.hash("password");
|
|
178
|
+
expect(hashed).toContain("$argon2");
|
|
179
|
+
});
|
|
180
|
+
it("should use APP_SECRET env when no secret or HASH_SECRET provided", async () => {
|
|
181
|
+
process.env.APP_SECRET = "envAppSecret";
|
|
182
|
+
const moduleRef = await testing_1.Test.createTestingModule({
|
|
183
|
+
imports: [_1.HashModule.register({})],
|
|
184
|
+
}).compile();
|
|
185
|
+
const hashService = moduleRef.get(_1.HashService);
|
|
186
|
+
expect(hashService).toBeDefined();
|
|
187
|
+
const hashed = await hashService.hash("password");
|
|
188
|
+
expect(hashed).toContain("$argon2");
|
|
189
|
+
});
|
|
190
|
+
it("should work without any secret", async () => {
|
|
191
|
+
const moduleRef = await testing_1.Test.createTestingModule({
|
|
192
|
+
imports: [_1.HashModule.register({})],
|
|
193
|
+
}).compile();
|
|
194
|
+
const hashService = moduleRef.get(_1.HashService);
|
|
195
|
+
expect(hashService).toBeDefined();
|
|
196
|
+
const hashed = await hashService.hash("password");
|
|
197
|
+
expect(hashed).toContain("$argon2");
|
|
40
198
|
});
|
|
41
199
|
});
|
|
42
200
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hash.service.spec.js","sourceRoot":"","sources":["../src/hash.service.spec.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"hash.service.spec.js","sourceRoot":"","sources":["../src/hash.service.spec.ts"],"names":[],"mappings":"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"}
|