@excofy/utils 2.0.0 → 2.1.1

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.
@@ -20,9 +20,6 @@ jobs:
20
20
  - name: Install Dependencies
21
21
  run: npm ci
22
22
 
23
- - name: Lint Code
24
- run: npm run lint
25
-
26
23
  - name: Build Package
27
24
  run: npm run build
28
25
 
package/dist/index.cjs CHANGED
@@ -30,6 +30,8 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
30
30
  // src/index.ts
31
31
  var index_exports = {};
32
32
  __export(index_exports, {
33
+ ExpiredTokenError: () => ExpiredTokenError,
34
+ InvalidTokenError: () => InvalidTokenError,
33
35
  createValidator: () => createValidator,
34
36
  cryptoUtils: () => cryptoUtils,
35
37
  generateCode: () => generateCode,
@@ -684,6 +686,26 @@ var stringUtils = {
684
686
  removeFileExtension: (fileName) => fileName.replace(/\.[^/.]+$/, "")
685
687
  };
686
688
 
689
+ // src/errors/crypto/CryptoError.ts
690
+ var CryptoError = class extends Error {
691
+ constructor(message) {
692
+ super(message);
693
+ this.name = "CryptoError";
694
+ }
695
+ };
696
+ var InvalidTokenError = class extends CryptoError {
697
+ constructor(message = "Invalid or malformed token") {
698
+ super(message);
699
+ this.name = "InvalidTokenError";
700
+ }
701
+ };
702
+ var ExpiredTokenError = class extends CryptoError {
703
+ constructor(message = "Token has expired") {
704
+ super(message);
705
+ this.name = "ExpiredTokenError";
706
+ }
707
+ };
708
+
687
709
  // src/helpers/crypto.ts
688
710
  var encoder = new TextEncoder();
689
711
  var decoder = new TextDecoder();
@@ -729,9 +751,24 @@ var decryptPayload = async ({
729
751
  );
730
752
  return decoder.decode(buffer);
731
753
  };
754
+ async function generateDeterministicHash(code, secret) {
755
+ const key = await crypto.subtle.importKey(
756
+ "raw",
757
+ encoder.encode(secret),
758
+ { name: "HMAC", hash: "SHA-256" },
759
+ false,
760
+ ["sign"]
761
+ );
762
+ const signature = await crypto.subtle.sign("HMAC", key, encoder.encode(code));
763
+ return Array.from(new Uint8Array(signature)).map((b) => b.toString(16).padStart(2, "0")).join("");
764
+ }
765
+ async function verifyDeterministicHash(inputCode, storedHash, secret) {
766
+ const hash = await generateDeterministicHash(inputCode, secret);
767
+ return hash === storedHash;
768
+ }
732
769
  var cryptoUtils = {
733
770
  uuidV4: () => crypto.randomUUID(),
734
- hash: async (password, salt) => {
771
+ hash: async (password, salt = 10) => {
735
772
  const importedKey = await crypto.subtle.importKey(
736
773
  "raw",
737
774
  encoder.encode(password),
@@ -794,11 +831,11 @@ var cryptoUtils = {
794
831
  );
795
832
  if (!valid) throw new Error("Invalid access token");
796
833
  } catch (err) {
797
- throw new Error("Invalid access token");
834
+ throw new InvalidTokenError("Invalid or malformed access token");
798
835
  }
799
836
  const { expiresAt } = JSON.parse(payloadDecrypted);
800
837
  if (Date.now() > new Date(expiresAt).getTime()) {
801
- throw new Error("Expired access token");
838
+ throw new ExpiredTokenError("Access token has expired");
802
839
  }
803
840
  return payloadDecrypted;
804
841
  },
@@ -807,7 +844,9 @@ var cryptoUtils = {
807
844
  return Array.from(new Uint8Array(buffer)).map((b) => b.toString(16).padStart(2, "0")).join("");
808
845
  },
809
846
  encryptPayload,
810
- decryptPayload
847
+ decryptPayload,
848
+ generateDeterministicHash,
849
+ verifyDeterministicHash
811
850
  };
812
851
 
813
852
  // src/helpers/slug.ts
@@ -849,6 +888,8 @@ var toDecimal = (value) => {
849
888
  };
850
889
  // Annotate the CommonJS export names for ESM import in node:
851
890
  0 && (module.exports = {
891
+ ExpiredTokenError,
892
+ InvalidTokenError,
852
893
  createValidator,
853
894
  cryptoUtils,
854
895
  generateCode,
package/dist/index.d.cts CHANGED
@@ -133,6 +133,8 @@ interface ICrypto {
133
133
  AUTH_PAYLOAD_SECRET: string;
134
134
  token: string;
135
135
  }) => Promise<string>;
136
+ generateDeterministicHash: (code: string, secret: string) => Promise<string>;
137
+ verifyDeterministicHash: (inputCode: string, storedHash: string, secret: string) => Promise<boolean>;
136
138
  }
137
139
  declare const cryptoUtils: ICrypto;
138
140
 
@@ -198,4 +200,23 @@ declare namespace number {
198
200
  export { number_toCents as toCents, number_toDecimal as toDecimal };
199
201
  }
200
202
 
201
- export { createValidator, cryptoUtils, generateCode, htmlEntityDecode, number as numberUtils, slug as slugUtils, stringUtils };
203
+ /**
204
+ * Classe base para erros de criptografia
205
+ */
206
+ declare class CryptoError extends Error {
207
+ constructor(message: string);
208
+ }
209
+ /**
210
+ * Token inválido, malformado ou corrompido
211
+ */
212
+ declare class InvalidTokenError extends CryptoError {
213
+ constructor(message?: string);
214
+ }
215
+ /**
216
+ * Token válido mas expirado
217
+ */
218
+ declare class ExpiredTokenError extends CryptoError {
219
+ constructor(message?: string);
220
+ }
221
+
222
+ export { ExpiredTokenError, InvalidTokenError, createValidator, cryptoUtils, generateCode, htmlEntityDecode, number as numberUtils, slug as slugUtils, stringUtils };
package/dist/index.d.ts CHANGED
@@ -133,6 +133,8 @@ interface ICrypto {
133
133
  AUTH_PAYLOAD_SECRET: string;
134
134
  token: string;
135
135
  }) => Promise<string>;
136
+ generateDeterministicHash: (code: string, secret: string) => Promise<string>;
137
+ verifyDeterministicHash: (inputCode: string, storedHash: string, secret: string) => Promise<boolean>;
136
138
  }
137
139
  declare const cryptoUtils: ICrypto;
138
140
 
@@ -198,4 +200,23 @@ declare namespace number {
198
200
  export { number_toCents as toCents, number_toDecimal as toDecimal };
199
201
  }
200
202
 
201
- export { createValidator, cryptoUtils, generateCode, htmlEntityDecode, number as numberUtils, slug as slugUtils, stringUtils };
203
+ /**
204
+ * Classe base para erros de criptografia
205
+ */
206
+ declare class CryptoError extends Error {
207
+ constructor(message: string);
208
+ }
209
+ /**
210
+ * Token inválido, malformado ou corrompido
211
+ */
212
+ declare class InvalidTokenError extends CryptoError {
213
+ constructor(message?: string);
214
+ }
215
+ /**
216
+ * Token válido mas expirado
217
+ */
218
+ declare class ExpiredTokenError extends CryptoError {
219
+ constructor(message?: string);
220
+ }
221
+
222
+ export { ExpiredTokenError, InvalidTokenError, createValidator, cryptoUtils, generateCode, htmlEntityDecode, number as numberUtils, slug as slugUtils, stringUtils };
package/dist/index.js CHANGED
@@ -648,6 +648,26 @@ var stringUtils = {
648
648
  removeFileExtension: (fileName) => fileName.replace(/\.[^/.]+$/, "")
649
649
  };
650
650
 
651
+ // src/errors/crypto/CryptoError.ts
652
+ var CryptoError = class extends Error {
653
+ constructor(message) {
654
+ super(message);
655
+ this.name = "CryptoError";
656
+ }
657
+ };
658
+ var InvalidTokenError = class extends CryptoError {
659
+ constructor(message = "Invalid or malformed token") {
660
+ super(message);
661
+ this.name = "InvalidTokenError";
662
+ }
663
+ };
664
+ var ExpiredTokenError = class extends CryptoError {
665
+ constructor(message = "Token has expired") {
666
+ super(message);
667
+ this.name = "ExpiredTokenError";
668
+ }
669
+ };
670
+
651
671
  // src/helpers/crypto.ts
652
672
  var encoder = new TextEncoder();
653
673
  var decoder = new TextDecoder();
@@ -693,9 +713,24 @@ var decryptPayload = async ({
693
713
  );
694
714
  return decoder.decode(buffer);
695
715
  };
716
+ async function generateDeterministicHash(code, secret) {
717
+ const key = await crypto.subtle.importKey(
718
+ "raw",
719
+ encoder.encode(secret),
720
+ { name: "HMAC", hash: "SHA-256" },
721
+ false,
722
+ ["sign"]
723
+ );
724
+ const signature = await crypto.subtle.sign("HMAC", key, encoder.encode(code));
725
+ return Array.from(new Uint8Array(signature)).map((b) => b.toString(16).padStart(2, "0")).join("");
726
+ }
727
+ async function verifyDeterministicHash(inputCode, storedHash, secret) {
728
+ const hash = await generateDeterministicHash(inputCode, secret);
729
+ return hash === storedHash;
730
+ }
696
731
  var cryptoUtils = {
697
732
  uuidV4: () => crypto.randomUUID(),
698
- hash: async (password, salt) => {
733
+ hash: async (password, salt = 10) => {
699
734
  const importedKey = await crypto.subtle.importKey(
700
735
  "raw",
701
736
  encoder.encode(password),
@@ -758,11 +793,11 @@ var cryptoUtils = {
758
793
  );
759
794
  if (!valid) throw new Error("Invalid access token");
760
795
  } catch (err) {
761
- throw new Error("Invalid access token");
796
+ throw new InvalidTokenError("Invalid or malformed access token");
762
797
  }
763
798
  const { expiresAt } = JSON.parse(payloadDecrypted);
764
799
  if (Date.now() > new Date(expiresAt).getTime()) {
765
- throw new Error("Expired access token");
800
+ throw new ExpiredTokenError("Access token has expired");
766
801
  }
767
802
  return payloadDecrypted;
768
803
  },
@@ -771,7 +806,9 @@ var cryptoUtils = {
771
806
  return Array.from(new Uint8Array(buffer)).map((b) => b.toString(16).padStart(2, "0")).join("");
772
807
  },
773
808
  encryptPayload,
774
- decryptPayload
809
+ decryptPayload,
810
+ generateDeterministicHash,
811
+ verifyDeterministicHash
775
812
  };
776
813
 
777
814
  // src/helpers/slug.ts
@@ -812,6 +849,8 @@ var toDecimal = (value) => {
812
849
  return new Big(value).div(100).round(2).toNumber();
813
850
  };
814
851
  export {
852
+ ExpiredTokenError,
853
+ InvalidTokenError,
815
854
  createValidator,
816
855
  cryptoUtils,
817
856
  generateCode,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@excofy/utils",
3
- "version": "2.0.0",
3
+ "version": "2.1.1",
4
4
  "description": "Biblioteca de utilitários para o Excofy",
5
5
  "main": "dist/index.js",
6
6
  "type": "module",
@@ -0,0 +1,29 @@
1
+ /**
2
+ * Classe base para erros de criptografia
3
+ */
4
+ export class CryptoError extends Error {
5
+ constructor(message: string) {
6
+ super(message);
7
+ this.name = 'CryptoError';
8
+ }
9
+ }
10
+
11
+ /**
12
+ * Token inválido, malformado ou corrompido
13
+ */
14
+ export class InvalidTokenError extends CryptoError {
15
+ constructor(message: string = 'Invalid or malformed token') {
16
+ super(message);
17
+ this.name = 'InvalidTokenError';
18
+ }
19
+ }
20
+
21
+ /**
22
+ * Token válido mas expirado
23
+ */
24
+ export class ExpiredTokenError extends CryptoError {
25
+ constructor(message: string = 'Token has expired') {
26
+ super(message);
27
+ this.name = 'ExpiredTokenError';
28
+ }
29
+ }
@@ -0,0 +1 @@
1
+ export { InvalidTokenError, ExpiredTokenError } from './crypto/CryptoError';
@@ -1,3 +1,8 @@
1
+ import {
2
+ ExpiredTokenError,
3
+ InvalidTokenError,
4
+ } from '../errors/crypto/CryptoError';
5
+
1
6
  interface IGenerateAccessToken {
2
7
  AUTH_SIGN_SECRET: string;
3
8
  AUTH_PAYLOAD_SECRET: string;
@@ -25,6 +30,12 @@ interface ICrypto {
25
30
  AUTH_PAYLOAD_SECRET: string;
26
31
  token: string;
27
32
  }) => Promise<string>;
33
+ generateDeterministicHash: (code: string, secret: string) => Promise<string>;
34
+ verifyDeterministicHash: (
35
+ inputCode: string,
36
+ storedHash: string,
37
+ secret: string
38
+ ) => Promise<boolean>;
28
39
  }
29
40
 
30
41
  /* --------------------- Helpers básicos --------------------- */
@@ -94,11 +105,55 @@ const decryptPayload = async ({
94
105
  return decoder.decode(buffer);
95
106
  };
96
107
 
108
+ /* --------------------- Hash (generate/verify) --------------------- */
109
+ /**
110
+ * Gera um hash determinístico (HMAC) a partir de um código e um segredo.
111
+ *
112
+ * @param code
113
+ * @param secret
114
+ * @returns
115
+ */
116
+ export async function generateDeterministicHash(
117
+ code: string,
118
+ secret: string
119
+ ): Promise<string> {
120
+ const key = await crypto.subtle.importKey(
121
+ 'raw',
122
+ encoder.encode(secret),
123
+ { name: 'HMAC', hash: 'SHA-256' },
124
+ false,
125
+ ['sign']
126
+ );
127
+
128
+ const signature = await crypto.subtle.sign('HMAC', key, encoder.encode(code));
129
+
130
+ return Array.from(new Uint8Array(signature))
131
+ .map((b) => b.toString(16).padStart(2, '0'))
132
+ .join('');
133
+ }
134
+
135
+ /**
136
+ * Verifica se o hash gerado a partir do código e segredo bate com o hash armazenado.
137
+ *
138
+ * @param inputCode
139
+ * @param storedHash
140
+ * @param secret
141
+ * @returns
142
+ */
143
+ export async function verifyDeterministicHash(
144
+ inputCode: string,
145
+ storedHash: string,
146
+ secret: string
147
+ ): Promise<boolean> {
148
+ const hash = await generateDeterministicHash(inputCode, secret);
149
+ return hash === storedHash;
150
+ }
151
+
97
152
  /* --------------------- Main API --------------------- */
98
153
  export const cryptoUtils: ICrypto = {
99
154
  uuidV4: (): string => crypto.randomUUID(),
100
155
 
101
- hash: async (password: string, salt: number): Promise<string> => {
156
+ hash: async (password: string, salt: number = 10): Promise<string> => {
102
157
  const importedKey = await crypto.subtle.importKey(
103
158
  'raw',
104
159
  encoder.encode(password),
@@ -178,13 +233,13 @@ export const cryptoUtils: ICrypto = {
178
233
  if (!valid) throw new Error('Invalid access token');
179
234
  } catch (err) {
180
235
  // qualquer falha na decriptação ou verificação -> token inválido
181
- throw new Error('Invalid access token');
236
+ throw new InvalidTokenError('Invalid or malformed access token');
182
237
  }
183
238
 
184
239
  // verifica expiração **fora do try/catch**, para não ser capturada como token inválido
185
240
  const { expiresAt } = JSON.parse(payloadDecrypted);
186
241
  if (Date.now() > new Date(expiresAt).getTime()) {
187
- throw new Error('Expired access token');
242
+ throw new ExpiredTokenError('Access token has expired');
188
243
  }
189
244
 
190
245
  return payloadDecrypted;
@@ -199,4 +254,7 @@ export const cryptoUtils: ICrypto = {
199
254
 
200
255
  encryptPayload,
201
256
  decryptPayload,
257
+
258
+ generateDeterministicHash,
259
+ verifyDeterministicHash,
202
260
  };
package/src/index.ts CHANGED
@@ -15,3 +15,6 @@ export {
15
15
  cryptoUtils,
16
16
  generateCode,
17
17
  };
18
+
19
+ // 🚀 Classes de erro para autenticação
20
+ export { InvalidTokenError, ExpiredTokenError } from './errors';