@excofy/utils 2.1.2 → 2.2.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/index.cjs CHANGED
@@ -96,6 +96,30 @@ function isValidCNPJ(cnpj) {
96
96
  return digit1 === digits[1];
97
97
  }
98
98
 
99
+ // src/helpers/file.ts
100
+ var fileUtils = {
101
+ base64ToFile: (base64, filename) => {
102
+ if (!base64 || base64 === "") {
103
+ return null;
104
+ }
105
+ const arr = base64.split(",");
106
+ if (arr.length !== 2) {
107
+ return null;
108
+ }
109
+ const mime = arr[0].match(/:(.*?);/)?.[1];
110
+ if (!mime) {
111
+ return null;
112
+ }
113
+ const bstr = atob(arr[1]);
114
+ let n = bstr.length;
115
+ const u8arr = new Uint8Array(n);
116
+ while (n--) {
117
+ u8arr[n] = bstr.charCodeAt(n);
118
+ }
119
+ return new File([u8arr], filename, { type: mime });
120
+ }
121
+ };
122
+
99
123
  // src/helpers/sanitize.ts
100
124
  var import_xss = require("xss");
101
125
  var allTags = [
@@ -234,6 +258,8 @@ function createValidator() {
234
258
  isValidType = typeof value === "object" && value !== null && !Array.isArray(value);
235
259
  } else if (type === "file") {
236
260
  isValidType = value instanceof File;
261
+ } else if (type === "base64") {
262
+ isValidType = typeof value === "string" && !!value.match(/^data:([A-Za-z-+\/]+);base64,([A-Za-z0-9+/=]+)$/);
237
263
  } else if (type === "date") {
238
264
  isValidType = typeof value === "string" && !Number.isNaN(new Date(value).getTime());
239
265
  } else {
@@ -592,6 +618,22 @@ function createValidator() {
592
618
  current.inputs[current.field] = arr;
593
619
  }
594
620
  return validator;
621
+ },
622
+ asFileFromBase64(message, filename) {
623
+ if (shouldSkipValidation()) return validator;
624
+ const value = current.value;
625
+ if (typeof value !== "string") {
626
+ current.pushError(message);
627
+ return validator;
628
+ }
629
+ if (!value.match(/^data:([A-Za-z-+\/]+);base64,([A-Za-z0-9+/=]+)$/)) {
630
+ current.pushError(message);
631
+ return validator;
632
+ }
633
+ const file = fileUtils.base64ToFile(value, filename);
634
+ current.value = file;
635
+ current.inputs[current.field] = file;
636
+ return validator;
595
637
  }
596
638
  };
597
639
  return {
package/dist/index.d.cts CHANGED
@@ -13,7 +13,7 @@ type TMessage = {
13
13
  };
14
14
  type TValue = string | number | boolean | File | object | null | undefined;
15
15
  type TInputValue = TValue;
16
- type TTypes = 'string' | 'number' | 'boolean' | 'object' | 'array' | 'file' | 'date';
16
+ type TTypes = 'string' | 'number' | 'boolean' | 'object' | 'array' | 'file' | 'base64' | 'date';
17
17
  interface IInputErrors {
18
18
  [key: string]: TMessage[] | IInputErrors[];
19
19
  }
@@ -48,6 +48,7 @@ interface ValidatorField {
48
48
  asNumber(message: string): ValidatorField;
49
49
  asBoolean(message: string): ValidatorField;
50
50
  asStringArray(message: string): ValidatorField;
51
+ asFileFromBase64(message: string, filename: string): ValidatorField;
51
52
  }
52
53
  /**
53
54
  * Cria um validador de inputs com suporte a validações encadeadas, transformação e sanitização.
package/dist/index.d.ts CHANGED
@@ -13,7 +13,7 @@ type TMessage = {
13
13
  };
14
14
  type TValue = string | number | boolean | File | object | null | undefined;
15
15
  type TInputValue = TValue;
16
- type TTypes = 'string' | 'number' | 'boolean' | 'object' | 'array' | 'file' | 'date';
16
+ type TTypes = 'string' | 'number' | 'boolean' | 'object' | 'array' | 'file' | 'base64' | 'date';
17
17
  interface IInputErrors {
18
18
  [key: string]: TMessage[] | IInputErrors[];
19
19
  }
@@ -48,6 +48,7 @@ interface ValidatorField {
48
48
  asNumber(message: string): ValidatorField;
49
49
  asBoolean(message: string): ValidatorField;
50
50
  asStringArray(message: string): ValidatorField;
51
+ asFileFromBase64(message: string, filename: string): ValidatorField;
51
52
  }
52
53
  /**
53
54
  * Cria um validador de inputs com suporte a validações encadeadas, transformação e sanitização.
package/dist/index.js CHANGED
@@ -58,6 +58,30 @@ function isValidCNPJ(cnpj) {
58
58
  return digit1 === digits[1];
59
59
  }
60
60
 
61
+ // src/helpers/file.ts
62
+ var fileUtils = {
63
+ base64ToFile: (base64, filename) => {
64
+ if (!base64 || base64 === "") {
65
+ return null;
66
+ }
67
+ const arr = base64.split(",");
68
+ if (arr.length !== 2) {
69
+ return null;
70
+ }
71
+ const mime = arr[0].match(/:(.*?);/)?.[1];
72
+ if (!mime) {
73
+ return null;
74
+ }
75
+ const bstr = atob(arr[1]);
76
+ let n = bstr.length;
77
+ const u8arr = new Uint8Array(n);
78
+ while (n--) {
79
+ u8arr[n] = bstr.charCodeAt(n);
80
+ }
81
+ return new File([u8arr], filename, { type: mime });
82
+ }
83
+ };
84
+
61
85
  // src/helpers/sanitize.ts
62
86
  import { FilterXSS } from "xss";
63
87
  var allTags = [
@@ -196,6 +220,8 @@ function createValidator() {
196
220
  isValidType = typeof value === "object" && value !== null && !Array.isArray(value);
197
221
  } else if (type === "file") {
198
222
  isValidType = value instanceof File;
223
+ } else if (type === "base64") {
224
+ isValidType = typeof value === "string" && !!value.match(/^data:([A-Za-z-+\/]+);base64,([A-Za-z0-9+/=]+)$/);
199
225
  } else if (type === "date") {
200
226
  isValidType = typeof value === "string" && !Number.isNaN(new Date(value).getTime());
201
227
  } else {
@@ -554,6 +580,22 @@ function createValidator() {
554
580
  current.inputs[current.field] = arr;
555
581
  }
556
582
  return validator;
583
+ },
584
+ asFileFromBase64(message, filename) {
585
+ if (shouldSkipValidation()) return validator;
586
+ const value = current.value;
587
+ if (typeof value !== "string") {
588
+ current.pushError(message);
589
+ return validator;
590
+ }
591
+ if (!value.match(/^data:([A-Za-z-+\/]+);base64,([A-Za-z0-9+/=]+)$/)) {
592
+ current.pushError(message);
593
+ return validator;
594
+ }
595
+ const file = fileUtils.base64ToFile(value, filename);
596
+ current.value = file;
597
+ current.inputs[current.field] = file;
598
+ return validator;
557
599
  }
558
600
  };
559
601
  return {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@excofy/utils",
3
- "version": "2.1.2",
3
+ "version": "2.2.0",
4
4
  "description": "Biblioteca de utilitários para o Excofy",
5
5
  "main": "dist/index.js",
6
6
  "type": "module",
@@ -16,7 +16,7 @@
16
16
  "typecheck": "tsc --noEmit",
17
17
  "prepublishOnly": "npm run build",
18
18
  "deploy": "act",
19
- "test": "tsx --test 'tests/**/*.spec.ts' --testTimeout=10000"
19
+ "test": "tsx --test 'tests/helpers/crypto.spec.ts' --testTimeout=10000"
20
20
  },
21
21
  "repository": {
22
22
  "type": "git",
@@ -153,7 +153,7 @@ export async function verifyDeterministicHash(
153
153
  export const cryptoUtils: ICrypto = {
154
154
  uuidV4: (): string => crypto.randomUUID(),
155
155
 
156
- hash: async (password: string, salt: number = 10): Promise<string> => {
156
+ hash: async (password: string, salt = 10): Promise<string> => {
157
157
  const importedKey = await crypto.subtle.importKey(
158
158
  'raw',
159
159
  encoder.encode(password),
@@ -0,0 +1,28 @@
1
+ export const fileUtils = {
2
+ base64ToFile: (base64: string | null, filename: string): File | null => {
3
+ if (!base64 || base64 === '') {
4
+ return null;
5
+ }
6
+
7
+ const arr = base64.split(',');
8
+ if (arr.length !== 2) {
9
+ return null;
10
+ }
11
+
12
+ const mime = arr[0].match(/:(.*?);/)?.[1];
13
+
14
+ if (!mime) {
15
+ return null;
16
+ }
17
+
18
+ const bstr = atob(arr[1]);
19
+ let n = bstr.length;
20
+ const u8arr = new Uint8Array(n);
21
+
22
+ while (n--) {
23
+ u8arr[n] = bstr.charCodeAt(n);
24
+ }
25
+
26
+ return new File([u8arr], filename, { type: mime });
27
+ },
28
+ };
@@ -1,4 +1,5 @@
1
1
  import { isValidCNPJ, isValidCPF } from './document';
2
+ import { fileUtils } from './file';
2
3
  import { sanitizeValue, type AllowedTag } from './sanitize';
3
4
  import { video } from './video';
4
5
 
@@ -12,6 +13,7 @@ type TTypes =
12
13
  | 'object'
13
14
  | 'array'
14
15
  | 'file'
16
+ | 'base64'
15
17
  | 'date';
16
18
 
17
19
  interface IInputErrors {
@@ -56,6 +58,7 @@ interface ValidatorField {
56
58
  asNumber(message: string): ValidatorField;
57
59
  asBoolean(message: string): ValidatorField;
58
60
  asStringArray(message: string): ValidatorField;
61
+ asFileFromBase64(message: string, filename: string): ValidatorField;
59
62
  }
60
63
 
61
64
  /**
@@ -139,6 +142,10 @@ export function createValidator<
139
142
  typeof value === 'object' && value !== null && !Array.isArray(value);
140
143
  } else if (type === 'file') {
141
144
  isValidType = value instanceof File;
145
+ } else if (type === 'base64') {
146
+ isValidType =
147
+ typeof value === 'string' &&
148
+ !!value.match(/^data:([A-Za-z-+\/]+);base64,([A-Za-z0-9+/=]+)$/);
142
149
  } else if (type === 'date') {
143
150
  isValidType =
144
151
  typeof value === 'string' && !Number.isNaN(new Date(value).getTime());
@@ -629,6 +636,28 @@ export function createValidator<
629
636
 
630
637
  return validator;
631
638
  },
639
+
640
+ asFileFromBase64(message: string, filename: string) {
641
+ if (shouldSkipValidation()) return validator;
642
+
643
+ const value = current.value;
644
+
645
+ if (typeof value !== 'string') {
646
+ current.pushError(message);
647
+ return validator;
648
+ }
649
+
650
+ if (!value.match(/^data:([A-Za-z-+\/]+);base64,([A-Za-z0-9+/=]+)$/)) {
651
+ current.pushError(message);
652
+ return validator;
653
+ }
654
+
655
+ const file = fileUtils.base64ToFile(value, filename);
656
+ current.value = file;
657
+ current.inputs[current.field] = file as TRaw[keyof TRaw];
658
+
659
+ return validator;
660
+ },
632
661
  };
633
662
 
634
663
  return {
@@ -0,0 +1,22 @@
1
+ import { describe, it } from 'node:test';
2
+ import assert from 'node:assert/strict';
3
+ import { cryptoUtils } from '../../src/helpers/crypto';
4
+
5
+ const AUTH_PAYLOAD_SECRET = '98c026b8-80d7-43ac-80d0-5118cb9c0102';
6
+ const code = 'N3HDL5';
7
+
8
+ describe('cryptoUtils', () => {
9
+ it('uuidV4 deve gerar um UUID válido', async () => {
10
+ const encrypted = await cryptoUtils.encryptPayload({
11
+ AUTH_PAYLOAD_SECRET,
12
+ payload: code,
13
+ });
14
+
15
+ const hash = await cryptoUtils.generateDeterministicHash(
16
+ code,
17
+ AUTH_PAYLOAD_SECRET
18
+ );
19
+
20
+ console.log({ encrypted, hash });
21
+ });
22
+ });