@nest-boot/crypt 7.0.1 → 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.
Files changed (35) hide show
  1. package/dist/crypt-module-options.interface.d.ts +7 -0
  2. package/dist/crypt.module-definition.d.ts +1 -7
  3. package/dist/crypt.module-definition.js +1 -8
  4. package/dist/crypt.module-definition.js.map +1 -1
  5. package/dist/crypt.module.d.ts +38 -1
  6. package/dist/crypt.module.js +74 -1
  7. package/dist/crypt.module.js.map +1 -1
  8. package/dist/crypt.module.spec.d.ts +1 -0
  9. package/dist/crypt.module.spec.js +73 -0
  10. package/dist/crypt.module.spec.js.map +1 -0
  11. package/dist/crypt.service.d.ts +77 -6
  12. package/dist/crypt.service.js +101 -84
  13. package/dist/crypt.service.js.map +1 -1
  14. package/dist/crypt.service.spec.js +77 -38
  15. package/dist/crypt.service.spec.js.map +1 -1
  16. package/dist/index.d.ts +2 -0
  17. package/dist/index.js +2 -0
  18. package/dist/index.js.map +1 -1
  19. package/dist/tsconfig.build.tsbuildinfo +1 -1
  20. package/dist/utils/derive-key.d.ts +7 -0
  21. package/dist/utils/derive-key.js +22 -0
  22. package/dist/utils/derive-key.js.map +1 -0
  23. package/dist/utils/estimate-entropy.d.ts +8 -0
  24. package/dist/utils/estimate-entropy.js +17 -0
  25. package/dist/utils/estimate-entropy.js.map +1 -0
  26. package/dist/utils/estimate-entropy.spec.d.ts +1 -0
  27. package/dist/utils/estimate-entropy.spec.js +17 -0
  28. package/dist/utils/estimate-entropy.spec.js.map +1 -0
  29. package/dist/utils/is-jwe.d.ts +14 -0
  30. package/dist/utils/is-jwe.js +38 -0
  31. package/dist/utils/is-jwe.js.map +1 -0
  32. package/dist/utils/is-jwe.spec.d.ts +1 -0
  33. package/dist/utils/is-jwe.spec.js +50 -0
  34. package/dist/utils/is-jwe.spec.js.map +1 -0
  35. package/package.json +13 -6
@@ -1,3 +1,10 @@
1
+ /**
2
+ * Configuration options for the CryptModule.
3
+ */
1
4
  export interface CryptModuleOptions {
5
+ /**
6
+ * The secret key used for encryption and decryption.
7
+ * If not provided, falls back to CRYPT_SECRET or APP_SECRET environment variables.
8
+ */
2
9
  secret?: string;
3
10
  }
@@ -1,8 +1,2 @@
1
1
  import { type CryptModuleOptions } from "./crypt-module-options.interface";
2
- export declare const ConfigurableModuleClass: import("@nestjs/common").ConfigurableModuleCls<CryptModuleOptions, "register", "create", {
3
- isGlobal: boolean;
4
- }>, MODULE_OPTIONS_TOKEN: string | symbol, OPTIONS_TYPE: CryptModuleOptions & Partial<{
5
- isGlobal: boolean;
6
- }>, ASYNC_OPTIONS_TYPE: import("@nestjs/common").ConfigurableModuleAsyncOptions<CryptModuleOptions, "create"> & Partial<{
7
- isGlobal: boolean;
8
- }>;
2
+ export declare const ConfigurableModuleClass: import("@nestjs/common").ConfigurableModuleCls<CryptModuleOptions, "register", "create", {}>, MODULE_OPTIONS_TOKEN: string | symbol, OPTIONS_TYPE: CryptModuleOptions & Partial<{}>, ASYNC_OPTIONS_TYPE: import("@nestjs/common").ConfigurableModuleAsyncOptions<CryptModuleOptions, "create"> & Partial<{}>;
@@ -3,12 +3,5 @@ var _a;
3
3
  Object.defineProperty(exports, "__esModule", { value: true });
4
4
  exports.ASYNC_OPTIONS_TYPE = exports.OPTIONS_TYPE = exports.MODULE_OPTIONS_TOKEN = exports.ConfigurableModuleClass = void 0;
5
5
  const common_1 = require("@nestjs/common");
6
- _a = new common_1.ConfigurableModuleBuilder()
7
- .setExtras({
8
- isGlobal: false,
9
- }, (definition, extras) => ({
10
- ...definition,
11
- global: extras.isGlobal,
12
- }))
13
- .build(), exports.ConfigurableModuleClass = _a.ConfigurableModuleClass, exports.MODULE_OPTIONS_TOKEN = _a.MODULE_OPTIONS_TOKEN, exports.OPTIONS_TYPE = _a.OPTIONS_TYPE, exports.ASYNC_OPTIONS_TYPE = _a.ASYNC_OPTIONS_TYPE;
6
+ _a = new common_1.ConfigurableModuleBuilder().build(), exports.ConfigurableModuleClass = _a.ConfigurableModuleClass, exports.MODULE_OPTIONS_TOKEN = _a.MODULE_OPTIONS_TOKEN, exports.OPTIONS_TYPE = _a.OPTIONS_TYPE, exports.ASYNC_OPTIONS_TYPE = _a.ASYNC_OPTIONS_TYPE;
14
7
  //# sourceMappingURL=crypt.module-definition.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"crypt.module-definition.js","sourceRoot":"","sources":["../src/crypt.module-definition.ts"],"names":[],"mappings":";;;;AAAA,2CAA2D;AAI9C,KAKT,IAAI,kCAAyB,EAAsB;KACpD,SAAS,CACR;IACE,QAAQ,EAAE,KAAK;CAChB,EACD,CAAC,UAAU,EAAE,MAAM,EAAE,EAAE,CAAC,CAAC;IACvB,GAAG,UAAU;IACb,MAAM,EAAE,MAAM,CAAC,QAAQ;CACxB,CAAC,CACH;KACA,KAAK,EAAE,EAdR,+BAAuB,+BACvB,4BAAoB,4BACpB,oBAAY,oBACZ,0BAAkB,yBAWT"}
1
+ {"version":3,"file":"crypt.module-definition.js","sourceRoot":"","sources":["../src/crypt.module-definition.ts"],"names":[],"mappings":";;;;AAAA,2CAA2D;AAI9C,KAKT,IAAI,kCAAyB,EAAsB,CAAC,KAAK,EAAE,EAJ7D,+BAAuB,+BACvB,4BAAoB,4BACpB,oBAAY,oBACZ,0BAAkB,yBAC4C"}
@@ -1,3 +1,40 @@
1
- import { ConfigurableModuleClass } from "./crypt.module-definition";
1
+ import { type DynamicModule } from "@nestjs/common";
2
+ import { ASYNC_OPTIONS_TYPE, ConfigurableModuleClass, OPTIONS_TYPE } from "./crypt.module-definition";
3
+ /**
4
+ * Module that provides encryption and decryption services using JWE (A256GCMKW + A256GCM).
5
+ *
6
+ * Uses HKDF to derive a 32-byte key from the secret, so secrets of any length are accepted.
7
+ *
8
+ * @example
9
+ * ```typescript
10
+ * import { CryptModule } from '@nest-boot/crypt';
11
+ *
12
+ * @Module({
13
+ * imports: [
14
+ * CryptModule.register({
15
+ * secret: process.env.CRYPT_SECRET
16
+ * }),
17
+ * ],
18
+ * })
19
+ * export class AppModule {}
20
+ * ```
21
+ *
22
+ * Generate a secure secret:
23
+ * ```bash
24
+ * node -e "console.log(require('crypto').randomBytes(32).toString('base64url'))"
25
+ * ```
26
+ */
2
27
  export declare class CryptModule extends ConfigurableModuleClass {
28
+ /**
29
+ * Registers the CryptModule with the given options.
30
+ * @param options - Configuration options including secret and isGlobal
31
+ * @returns Dynamic module configuration
32
+ */
33
+ static register(options: typeof OPTIONS_TYPE): DynamicModule;
34
+ /**
35
+ * Registers the CryptModule asynchronously with factory functions.
36
+ * @param options - Async configuration options
37
+ * @returns Dynamic module configuration
38
+ */
39
+ static registerAsync(options: typeof ASYNC_OPTIONS_TYPE): DynamicModule;
3
40
  }
@@ -10,10 +10,83 @@ exports.CryptModule = void 0;
10
10
  const common_1 = require("@nestjs/common");
11
11
  const crypt_module_definition_1 = require("./crypt.module-definition");
12
12
  const crypt_service_1 = require("./crypt.service");
13
+ const estimate_entropy_1 = require("./utils/estimate-entropy");
14
+ /**
15
+ * Module that provides encryption and decryption services using JWE (A256GCMKW + A256GCM).
16
+ *
17
+ * Uses HKDF to derive a 32-byte key from the secret, so secrets of any length are accepted.
18
+ *
19
+ * @example
20
+ * ```typescript
21
+ * import { CryptModule } from '@nest-boot/crypt';
22
+ *
23
+ * @Module({
24
+ * imports: [
25
+ * CryptModule.register({
26
+ * secret: process.env.CRYPT_SECRET
27
+ * }),
28
+ * ],
29
+ * })
30
+ * export class AppModule {}
31
+ * ```
32
+ *
33
+ * Generate a secure secret:
34
+ * ```bash
35
+ * node -e "console.log(require('crypto').randomBytes(32).toString('base64url'))"
36
+ * ```
37
+ */
13
38
  let CryptModule = class CryptModule extends crypt_module_definition_1.ConfigurableModuleClass {
39
+ /**
40
+ * Registers the CryptModule with the given options.
41
+ * @param options - Configuration options including secret and isGlobal
42
+ * @returns Dynamic module configuration
43
+ */
44
+ static register(options) {
45
+ return super.register(options);
46
+ }
47
+ /**
48
+ * Registers the CryptModule asynchronously with factory functions.
49
+ * @param options - Async configuration options
50
+ * @returns Dynamic module configuration
51
+ */
52
+ static registerAsync(options) {
53
+ return super.registerAsync(options);
54
+ }
14
55
  };
15
56
  exports.CryptModule = CryptModule;
16
57
  exports.CryptModule = CryptModule = __decorate([
17
- (0, common_1.Module)({ providers: [crypt_service_1.CryptService], exports: [crypt_service_1.CryptService] })
58
+ (0, common_1.Global)(),
59
+ (0, common_1.Module)({
60
+ providers: [
61
+ {
62
+ provide: crypt_service_1.CryptService,
63
+ inject: [{ token: crypt_module_definition_1.MODULE_OPTIONS_TOKEN, optional: true }],
64
+ useFactory: (options) => {
65
+ const secret = options.secret ?? process.env.CRYPT_SECRET ?? process.env.APP_SECRET;
66
+ if (!secret) {
67
+ throw new Error("Crypt secret is required.\n" +
68
+ "Set CRYPT_SECRET or APP_SECRET environment variable, or pass a secret option.\n" +
69
+ "Generate a secure secret with:\n" +
70
+ " node -e \"console.log(require('crypto').randomBytes(32).toString('base64url'))\"");
71
+ }
72
+ if (secret.length < 32) {
73
+ throw new Error("Crypt secret must be at least 32 characters long.\n" +
74
+ "Set CRYPT_SECRET or APP_SECRET environment variable, or pass a secret option.\n" +
75
+ "Generate a secure secret with:\n" +
76
+ " node -e \"console.log(require('crypto').randomBytes(32).toString('base64url'))\"");
77
+ }
78
+ if ((0, estimate_entropy_1.estimateEntropy)(secret) < 120) {
79
+ throw new Error("Crypt secret appears low-entropy.\n" +
80
+ "Use a randomly generated secret for production.\n" +
81
+ "Generate a secure secret with:\n" +
82
+ " node -e \"console.log(require('crypto').randomBytes(32).toString('base64url'))\"");
83
+ }
84
+ crypt_service_1.CryptService.init(secret);
85
+ return crypt_service_1.CryptService.instance;
86
+ },
87
+ },
88
+ ],
89
+ exports: [crypt_service_1.CryptService],
90
+ })
18
91
  ], CryptModule);
19
92
  //# sourceMappingURL=crypt.module.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"crypt.module.js","sourceRoot":"","sources":["../src/crypt.module.ts"],"names":[],"mappings":";;;;;;;;;AAAA,2CAAwC;AAExC,uEAAoE;AACpE,mDAA+C;AAGxC,IAAM,WAAW,GAAjB,MAAM,WAAY,SAAQ,iDAAuB;CAAG,CAAA;AAA9C,kCAAW;sBAAX,WAAW;IADvB,IAAA,eAAM,EAAC,EAAE,SAAS,EAAE,CAAC,4BAAY,CAAC,EAAE,OAAO,EAAE,CAAC,4BAAY,CAAC,EAAE,CAAC;GAClD,WAAW,CAAmC"}
1
+ {"version":3,"file":"crypt.module.js","sourceRoot":"","sources":["../src/crypt.module.ts"],"names":[],"mappings":";;;;;;;;;AAAA,2CAAoE;AAEpE,uEAKmC;AACnC,mDAA+C;AAE/C,+DAA2D;AAE3D;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AA8CI,IAAM,WAAW,GAAjB,MAAM,WAAY,SAAQ,iDAAuB;IACtD;;;;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,kCAAW;sBAAX,WAAW;IA7CvB,IAAA,eAAM,GAAE;IACR,IAAA,eAAM,EAAC;QACN,SAAS,EAAE;YACT;gBACE,OAAO,EAAE,4BAAY;gBACrB,MAAM,EAAE,CAAC,EAAE,KAAK,EAAE,8CAAoB,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;gBACzD,UAAU,EAAE,CAAC,OAA2B,EAAE,EAAE;oBAC1C,MAAM,MAAM,GACV,OAAO,CAAC,MAAM,IAAI,OAAO,CAAC,GAAG,CAAC,YAAY,IAAI,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC;oBAEvE,IAAI,CAAC,MAAM,EAAE,CAAC;wBACZ,MAAM,IAAI,KAAK,CACb,6BAA6B;4BAC3B,iFAAiF;4BACjF,kCAAkC;4BAClC,oFAAoF,CACvF,CAAC;oBACJ,CAAC;oBAED,IAAI,MAAM,CAAC,MAAM,GAAG,EAAE,EAAE,CAAC;wBACvB,MAAM,IAAI,KAAK,CACb,qDAAqD;4BACnD,iFAAiF;4BACjF,kCAAkC;4BAClC,oFAAoF,CACvF,CAAC;oBACJ,CAAC;oBAED,IAAI,IAAA,kCAAe,EAAC,MAAM,CAAC,GAAG,GAAG,EAAE,CAAC;wBAClC,MAAM,IAAI,KAAK,CACb,qCAAqC;4BACnC,mDAAmD;4BACnD,kCAAkC;4BAClC,oFAAoF,CACvF,CAAC;oBACJ,CAAC;oBAED,4BAAY,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;oBAE1B,OAAO,4BAAY,CAAC,QAAQ,CAAC;gBAC/B,CAAC;aACF;SACF;QACD,OAAO,EAAE,CAAC,4BAAY,CAAC;KACxB,CAAC;GACW,WAAW,CAoBvB"}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,73 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const testing_1 = require("@nestjs/testing");
4
+ const _1 = require(".");
5
+ const TEST_SECRET = "myTestSecretThatIsAtLeast32Chars!";
6
+ describe("CryptModule", () => {
7
+ const originalEnv = process.env;
8
+ beforeEach(() => {
9
+ // Reset static instance before each test
10
+ _1.CryptService._instance = undefined;
11
+ // Reset environment variables
12
+ process.env = { ...originalEnv };
13
+ delete process.env.CRYPT_SECRET;
14
+ delete process.env.APP_SECRET;
15
+ });
16
+ afterAll(() => {
17
+ process.env = originalEnv;
18
+ });
19
+ describe("register", () => {
20
+ it("should throw error when secret is missing", async () => {
21
+ await expect(testing_1.Test.createTestingModule({
22
+ imports: [_1.CryptModule.register({})],
23
+ }).compile()).rejects.toThrow("Crypt secret is required.");
24
+ });
25
+ it("should use CRYPT_SECRET env when no secret option provided", async () => {
26
+ process.env.CRYPT_SECRET = TEST_SECRET;
27
+ const moduleRef = await testing_1.Test.createTestingModule({
28
+ imports: [_1.CryptModule.register({})],
29
+ }).compile();
30
+ const cryptService = moduleRef.get(_1.CryptService);
31
+ expect(cryptService).toBeDefined();
32
+ });
33
+ it("should use APP_SECRET env when no secret or CRYPT_SECRET provided", async () => {
34
+ process.env.APP_SECRET = TEST_SECRET;
35
+ const moduleRef = await testing_1.Test.createTestingModule({
36
+ imports: [_1.CryptModule.register({})],
37
+ }).compile();
38
+ const cryptService = moduleRef.get(_1.CryptService);
39
+ expect(cryptService).toBeDefined();
40
+ });
41
+ it("should throw error when secret is too short", async () => {
42
+ await expect(testing_1.Test.createTestingModule({
43
+ imports: [_1.CryptModule.register({ secret: "short" })],
44
+ }).compile()).rejects.toThrow("Crypt secret must be at least 32 characters long.");
45
+ });
46
+ it("should throw error when secret has low entropy", async () => {
47
+ // A secret that is 32 chars but low entropy (all same character)
48
+ const lowEntropySecret = "a".repeat(32);
49
+ await expect(testing_1.Test.createTestingModule({
50
+ imports: [_1.CryptModule.register({ secret: lowEntropySecret })],
51
+ }).compile()).rejects.toThrow("Crypt secret appears low-entropy.");
52
+ });
53
+ });
54
+ describe("registerAsync", () => {
55
+ it("should register module with async factory", async () => {
56
+ const moduleRef = await testing_1.Test.createTestingModule({
57
+ imports: [
58
+ _1.CryptModule.registerAsync({
59
+ useFactory: () => ({
60
+ secret: TEST_SECRET,
61
+ }),
62
+ }),
63
+ ],
64
+ }).compile();
65
+ const cryptService = moduleRef.get(_1.CryptService);
66
+ expect(cryptService).toBeDefined();
67
+ const encrypted = await cryptService.encrypt("password");
68
+ const decrypted = await cryptService.decrypt(encrypted);
69
+ expect(decrypted).toBe("password");
70
+ });
71
+ });
72
+ });
73
+ //# sourceMappingURL=crypt.module.spec.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"crypt.module.spec.js","sourceRoot":"","sources":["../src/crypt.module.spec.ts"],"names":[],"mappings":"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"}
@@ -1,8 +1,79 @@
1
- import { CryptModuleOptions } from "./crypt-module-options.interface";
1
+ /**
2
+ * Service that provides encryption and decryption functionality using JWE (JSON Web Encryption).
3
+ *
4
+ * Uses HKDF to derive a 32-byte key from the secret, then A256GCMKW for key management
5
+ * and A256GCM for content encryption. Accepts secrets of any length.
6
+ *
7
+ * @example
8
+ * ```typescript
9
+ * import { CryptService } from '@nest-boot/crypt';
10
+ *
11
+ * // Initialize at application startup for static usage
12
+ * CryptService.init(process.env.CRYPT_SECRET);
13
+ *
14
+ * // Use static methods
15
+ * const encrypted = await CryptService.encrypt(data);
16
+ * const decrypted = await CryptService.decrypt(encrypted);
17
+ * ```
18
+ */
2
19
  export declare class CryptService {
3
- #private;
4
- private readonly options;
5
- constructor(options?: CryptModuleOptions);
6
- encrypt(value: string, secret?: string): Promise<string>;
7
- decrypt(value: string, secret?: string): Promise<string>;
20
+ private static _instance?;
21
+ /**
22
+ * Gets the static CryptService instance.
23
+ * @throws Error if CryptService has not been initialized via `init()`
24
+ * @returns The CryptService instance
25
+ */
26
+ static get instance(): CryptService;
27
+ /**
28
+ * Initializes the static CryptService instance with the given secret.
29
+ * Call this method at application startup to configure the default secret.
30
+ *
31
+ * @param secret - The secret key to use for encryption/decryption
32
+ *
33
+ * @example
34
+ * ```typescript
35
+ * // In your application bootstrap
36
+ * CryptService.init(process.env.CRYPT_SECRET);
37
+ * ```
38
+ */
39
+ static init(secret: string): void;
40
+ /**
41
+ * Encrypts a string value using the static instance.
42
+ * @param value - The plaintext string to encrypt
43
+ * @returns A JWE compact serialization string
44
+ * @throws Error if CryptService has not been initialized via `init()`
45
+ */
46
+ static encrypt(value: string): Promise<string>;
47
+ /**
48
+ * Decrypts a JWE string using the static instance.
49
+ * @param value - The JWE compact serialization string to decrypt
50
+ * @returns The decrypted plaintext string
51
+ * @throws Error if CryptService has not been initialized via `init()`
52
+ */
53
+ static decrypt(value: string): Promise<string>;
54
+ private readonly secret;
55
+ private derivedKeyPromise?;
56
+ /**
57
+ * Creates an instance of CryptService.
58
+ * @param secret - The secret key to use for encryption/decryption
59
+ */
60
+ constructor(secret: string);
61
+ /**
62
+ * Gets or creates the derived key asynchronously.
63
+ */
64
+ private getDerivedKey;
65
+ /**
66
+ * Encrypts a string value using JWE with A256GCMKW and A256GCM.
67
+ * The secret is first derived using HKDF-SHA256.
68
+ * @param value - The plaintext string to encrypt
69
+ * @returns A JWE compact serialization string
70
+ */
71
+ encrypt(value: string): Promise<string>;
72
+ /**
73
+ * Decrypts a JWE compact serialization string.
74
+ * The secret is first derived using HKDF-SHA256.
75
+ * @param value - The JWE string to decrypt
76
+ * @returns The decrypted plaintext string
77
+ */
78
+ decrypt(value: string): Promise<string>;
8
79
  }
@@ -1,93 +1,110 @@
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
- var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
15
- if (kind === "m") throw new TypeError("Private method is not writable");
16
- if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
17
- if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
18
- return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
19
- };
20
- var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
21
- if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
22
- if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
23
- return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
24
- };
25
- var _CryptService_instances, _CryptService_algorithm, _CryptService_encoding, _CryptService_keyByteLength, _CryptService_saltByteLength, _CryptService_viByteLength, _CryptService_secret, _CryptService_getKeyAndSalt;
26
2
  Object.defineProperty(exports, "__esModule", { value: true });
27
3
  exports.CryptService = void 0;
28
- const common_1 = require("@nestjs/common");
29
- const crypto_1 = require("crypto");
30
- const util_1 = require("util");
31
- const crypt_module_definition_1 = require("./crypt.module-definition");
32
- let CryptService = class CryptService {
33
- constructor(options = {}) {
34
- _CryptService_instances.add(this);
35
- this.options = options;
36
- _CryptService_algorithm.set(this, "aes-256-gcm");
37
- _CryptService_encoding.set(this, "base64");
38
- _CryptService_keyByteLength.set(this, 32);
39
- _CryptService_saltByteLength.set(this, 16);
40
- _CryptService_viByteLength.set(this, 16);
41
- _CryptService_secret.set(this, void 0);
42
- const secret = options.secret ?? process.env.CRYPT_SECRET ?? process.env.APP_SECRET;
43
- if (!secret) {
44
- throw new Error("Crypt secret is missing. Set CRYPT_SECRET or APP_SECRET or pass a secret option.");
4
+ const jose_1 = require("jose");
5
+ const derive_key_1 = require("./utils/derive-key");
6
+ /**
7
+ * Service that provides encryption and decryption functionality using JWE (JSON Web Encryption).
8
+ *
9
+ * Uses HKDF to derive a 32-byte key from the secret, then A256GCMKW for key management
10
+ * and A256GCM for content encryption. Accepts secrets of any length.
11
+ *
12
+ * @example
13
+ * ```typescript
14
+ * import { CryptService } from '@nest-boot/crypt';
15
+ *
16
+ * // Initialize at application startup for static usage
17
+ * CryptService.init(process.env.CRYPT_SECRET);
18
+ *
19
+ * // Use static methods
20
+ * const encrypted = await CryptService.encrypt(data);
21
+ * const decrypted = await CryptService.decrypt(encrypted);
22
+ * ```
23
+ */
24
+ class CryptService {
25
+ /**
26
+ * Gets the static CryptService instance.
27
+ * @throws Error if CryptService has not been initialized via `init()`
28
+ * @returns The CryptService instance
29
+ */
30
+ static get instance() {
31
+ if (!this._instance) {
32
+ throw new Error("CryptService not initialized");
45
33
  }
46
- __classPrivateFieldSet(this, _CryptService_secret, secret, "f");
34
+ return this._instance;
47
35
  }
48
- async encrypt(value, secret) {
49
- const { key, salt } = await __classPrivateFieldGet(this, _CryptService_instances, "m", _CryptService_getKeyAndSalt).call(this, secret ?? __classPrivateFieldGet(this, _CryptService_secret, "f"));
50
- const iv = (0, crypto_1.randomBytes)(__classPrivateFieldGet(this, _CryptService_viByteLength, "f"));
51
- const cipher = (0, crypto_1.createCipheriv)(__classPrivateFieldGet(this, _CryptService_algorithm, "f"), key, iv);
52
- const data = Buffer.concat([cipher.update(value), cipher.final()]);
53
- const tag = cipher.getAuthTag();
54
- return Buffer.from(JSON.stringify({
55
- iv: iv.toString(__classPrivateFieldGet(this, _CryptService_encoding, "f")),
56
- tag: tag.toString(__classPrivateFieldGet(this, _CryptService_encoding, "f")),
57
- data: data.toString(__classPrivateFieldGet(this, _CryptService_encoding, "f")),
58
- salt: salt.toString(__classPrivateFieldGet(this, _CryptService_encoding, "f")),
59
- })).toString(__classPrivateFieldGet(this, _CryptService_encoding, "f"));
36
+ /**
37
+ * Initializes the static CryptService instance with the given secret.
38
+ * Call this method at application startup to configure the default secret.
39
+ *
40
+ * @param secret - The secret key to use for encryption/decryption
41
+ *
42
+ * @example
43
+ * ```typescript
44
+ * // In your application bootstrap
45
+ * CryptService.init(process.env.CRYPT_SECRET);
46
+ * ```
47
+ */
48
+ static init(secret) {
49
+ this._instance = new CryptService(secret);
60
50
  }
61
- async decrypt(value, secret) {
62
- const payload = JSON.parse(Buffer.from(value, __classPrivateFieldGet(this, _CryptService_encoding, "f")).toString("utf8"));
63
- const key = (await (0, util_1.promisify)(crypto_1.scrypt)(secret ?? __classPrivateFieldGet(this, _CryptService_secret, "f"), Buffer.from(payload.salt, __classPrivateFieldGet(this, _CryptService_encoding, "f")), __classPrivateFieldGet(this, _CryptService_keyByteLength, "f")));
64
- const iv = Buffer.from(payload.iv, __classPrivateFieldGet(this, _CryptService_encoding, "f"));
65
- const tag = Buffer.from(payload.tag, __classPrivateFieldGet(this, _CryptService_encoding, "f"));
66
- const data = Buffer.from(payload.data, __classPrivateFieldGet(this, _CryptService_encoding, "f"));
67
- const decipher = (0, crypto_1.createDecipheriv)(__classPrivateFieldGet(this, _CryptService_algorithm, "f"), key, iv);
68
- decipher.setAuthTag(tag);
69
- return Buffer.concat([decipher.update(data), decipher.final()]).toString("utf8");
51
+ /**
52
+ * Encrypts a string value using the static instance.
53
+ * @param value - The plaintext string to encrypt
54
+ * @returns A JWE compact serialization string
55
+ * @throws Error if CryptService has not been initialized via `init()`
56
+ */
57
+ static encrypt(value) {
58
+ return this.instance.encrypt(value);
70
59
  }
71
- };
60
+ /**
61
+ * Decrypts a JWE string using the static instance.
62
+ * @param value - The JWE compact serialization string to decrypt
63
+ * @returns The decrypted plaintext string
64
+ * @throws Error if CryptService has not been initialized via `init()`
65
+ */
66
+ static decrypt(value) {
67
+ return this.instance.decrypt(value);
68
+ }
69
+ /**
70
+ * Creates an instance of CryptService.
71
+ * @param secret - The secret key to use for encryption/decryption
72
+ */
73
+ constructor(secret) {
74
+ this.secret = secret;
75
+ }
76
+ /**
77
+ * Gets or creates the derived key asynchronously.
78
+ */
79
+ getDerivedKey() {
80
+ return (this.derivedKeyPromise ??= (0, derive_key_1.deriveKey)(this.secret));
81
+ }
82
+ /**
83
+ * Encrypts a string value using JWE with A256GCMKW and A256GCM.
84
+ * The secret is first derived using HKDF-SHA256.
85
+ * @param value - The plaintext string to encrypt
86
+ * @returns A JWE compact serialization string
87
+ */
88
+ async encrypt(value) {
89
+ const key = await this.getDerivedKey();
90
+ return await new jose_1.CompactEncrypt(new TextEncoder().encode(value))
91
+ .setProtectedHeader({ alg: "A256GCMKW", enc: "A256GCM" })
92
+ .encrypt(key);
93
+ }
94
+ /**
95
+ * Decrypts a JWE compact serialization string.
96
+ * The secret is first derived using HKDF-SHA256.
97
+ * @param value - The JWE string to decrypt
98
+ * @returns The decrypted plaintext string
99
+ */
100
+ async decrypt(value) {
101
+ const key = await this.getDerivedKey();
102
+ const { plaintext } = await (0, jose_1.compactDecrypt)(value, key, {
103
+ keyManagementAlgorithms: ["A256GCMKW"],
104
+ contentEncryptionAlgorithms: ["A256GCM"],
105
+ });
106
+ return new TextDecoder().decode(plaintext);
107
+ }
108
+ }
72
109
  exports.CryptService = CryptService;
73
- _CryptService_algorithm = new WeakMap();
74
- _CryptService_encoding = new WeakMap();
75
- _CryptService_keyByteLength = new WeakMap();
76
- _CryptService_saltByteLength = new WeakMap();
77
- _CryptService_viByteLength = new WeakMap();
78
- _CryptService_secret = new WeakMap();
79
- _CryptService_instances = new WeakSet();
80
- _CryptService_getKeyAndSalt = async function _CryptService_getKeyAndSalt(secret) {
81
- const salt = (0, crypto_1.randomBytes)(__classPrivateFieldGet(this, _CryptService_saltByteLength, "f"));
82
- return {
83
- key: (await (0, util_1.promisify)(crypto_1.scrypt)(secret, salt, __classPrivateFieldGet(this, _CryptService_keyByteLength, "f"))),
84
- salt,
85
- };
86
- };
87
- exports.CryptService = CryptService = __decorate([
88
- (0, common_1.Injectable)(),
89
- __param(0, (0, common_1.Optional)()),
90
- __param(0, (0, common_1.Inject)(crypt_module_definition_1.MODULE_OPTIONS_TOKEN)),
91
- __metadata("design:paramtypes", [Object])
92
- ], CryptService);
93
110
  //# sourceMappingURL=crypt.service.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"crypt.service.js","sourceRoot":"","sources":["../src/crypt.service.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"crypt.service.js","sourceRoot":"","sources":["../src/crypt.service.ts"],"names":[],"mappings":";;;AAAA,+BAAsD;AAEtD,mDAA+C;AAE/C;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAa,YAAY;IAGvB;;;;OAIG;IACH,MAAM,KAAK,QAAQ;QACjB,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,CAAC;YACpB,MAAM,IAAI,KAAK,CAAC,8BAA8B,CAAC,CAAC;QAClD,CAAC;QAED,OAAO,IAAI,CAAC,SAAS,CAAC;IACxB,CAAC;IAED;;;;;;;;;;;OAWG;IACH,MAAM,CAAC,IAAI,CAAC,MAAc;QACxB,IAAI,CAAC,SAAS,GAAG,IAAI,YAAY,CAAC,MAAM,CAAC,CAAC;IAC5C,CAAC;IAED;;;;;OAKG;IACH,MAAM,CAAC,OAAO,CAAC,KAAa;QAC1B,OAAO,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;IACtC,CAAC;IAED;;;;;OAKG;IACH,MAAM,CAAC,OAAO,CAAC,KAAa;QAC1B,OAAO,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;IACtC,CAAC;IAKD;;;OAGG;IACH,YAAY,MAAc;QACxB,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;IACvB,CAAC;IAED;;OAEG;IACK,aAAa;QACnB,OAAO,CAAC,IAAI,CAAC,iBAAiB,KAAK,IAAA,sBAAS,EAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC;IAC7D,CAAC;IAED;;;;;OAKG;IACH,KAAK,CAAC,OAAO,CAAC,KAAa;QACzB,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,aAAa,EAAE,CAAC;QAEvC,OAAO,MAAM,IAAI,qBAAc,CAAC,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;aAC7D,kBAAkB,CAAC,EAAE,GAAG,EAAE,WAAW,EAAE,GAAG,EAAE,SAAS,EAAE,CAAC;aACxD,OAAO,CAAC,GAAG,CAAC,CAAC;IAClB,CAAC;IAED;;;;;OAKG;IACH,KAAK,CAAC,OAAO,CAAC,KAAa;QACzB,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,aAAa,EAAE,CAAC;QAEvC,MAAM,EAAE,SAAS,EAAE,GAAG,MAAM,IAAA,qBAAc,EAAC,KAAK,EAAE,GAAG,EAAE;YACrD,uBAAuB,EAAE,CAAC,WAAW,CAAC;YACtC,2BAA2B,EAAE,CAAC,SAAS,CAAC;SACzC,CAAC,CAAC;QAEH,OAAO,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;IAC7C,CAAC;CACF;AApGD,oCAoGC"}