@excofy/utils 2.1.1 → 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 +44 -2
- package/dist/index.d.cts +2 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.js +44 -2
- package/package.json +2 -2
- package/src/helpers/crypto.ts +1 -1
- package/src/helpers/file.ts +28 -0
- package/src/helpers/generateCode.ts +2 -2
- package/src/helpers/validator.ts +29 -0
- package/tests/helpers/crypto.spec.ts +22 -0
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 {
|
|
@@ -659,8 +701,8 @@ function createValidator() {
|
|
|
659
701
|
|
|
660
702
|
// src/helpers/generateCode.ts
|
|
661
703
|
var generateCode = (length = 6, type = "alphanumeric") => {
|
|
662
|
-
const digits = "
|
|
663
|
-
const letters = "
|
|
704
|
+
const digits = "123456789";
|
|
705
|
+
const letters = "ABCDEFGHIJKLMNPQRSTUVWXYZ";
|
|
664
706
|
let charset;
|
|
665
707
|
switch (type) {
|
|
666
708
|
case "numeric":
|
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 {
|
|
@@ -621,8 +663,8 @@ function createValidator() {
|
|
|
621
663
|
|
|
622
664
|
// src/helpers/generateCode.ts
|
|
623
665
|
var generateCode = (length = 6, type = "alphanumeric") => {
|
|
624
|
-
const digits = "
|
|
625
|
-
const letters = "
|
|
666
|
+
const digits = "123456789";
|
|
667
|
+
const letters = "ABCDEFGHIJKLMNPQRSTUVWXYZ";
|
|
626
668
|
let charset;
|
|
627
669
|
switch (type) {
|
|
628
670
|
case "numeric":
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@excofy/utils",
|
|
3
|
-
"version": "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
|
|
19
|
+
"test": "tsx --test 'tests/helpers/crypto.spec.ts' --testTimeout=10000"
|
|
20
20
|
},
|
|
21
21
|
"repository": {
|
|
22
22
|
"type": "git",
|
package/src/helpers/crypto.ts
CHANGED
|
@@ -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
|
|
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
|
+
};
|
|
@@ -18,8 +18,8 @@ export const generateCode = (
|
|
|
18
18
|
length = 6,
|
|
19
19
|
type: 'alphanumeric' | 'numeric' | 'letters' = 'alphanumeric'
|
|
20
20
|
): string => {
|
|
21
|
-
const digits = '
|
|
22
|
-
const letters = '
|
|
21
|
+
const digits = '123456789';
|
|
22
|
+
const letters = 'ABCDEFGHIJKLMNPQRSTUVWXYZ';
|
|
23
23
|
let charset: string;
|
|
24
24
|
|
|
25
25
|
switch (type) {
|
package/src/helpers/validator.ts
CHANGED
|
@@ -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
|
+
});
|