@excofy/utils 2.1.2 → 2.3.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 +38 -0
- package/dist/index.d.cts +3 -1
- package/dist/index.d.ts +3 -1
- package/dist/index.js +38 -0
- package/package.json +2 -2
- package/src/helpers/crypto.ts +1 -1
- package/src/helpers/file.ts +28 -0
- package/src/helpers/validator.ts +57 -0
- package/tests/helpers/crypto.spec.ts +22 -0
package/dist/index.cjs
CHANGED
|
@@ -234,6 +234,8 @@ function createValidator() {
|
|
|
234
234
|
isValidType = typeof value === "object" && value !== null && !Array.isArray(value);
|
|
235
235
|
} else if (type === "file") {
|
|
236
236
|
isValidType = value instanceof File;
|
|
237
|
+
} else if (type === "base64") {
|
|
238
|
+
isValidType = typeof value === "string" && !!value.match(/^data:([A-Za-z-+\/]+);base64,([A-Za-z0-9+/=]+)$/);
|
|
237
239
|
} else if (type === "date") {
|
|
238
240
|
isValidType = typeof value === "string" && !Number.isNaN(new Date(value).getTime());
|
|
239
241
|
} else {
|
|
@@ -250,6 +252,42 @@ function createValidator() {
|
|
|
250
252
|
return !current.required && (current.value === void 0 || current.value === null || current.value === "");
|
|
251
253
|
};
|
|
252
254
|
const validator = {
|
|
255
|
+
base64Type(validTypes, message) {
|
|
256
|
+
if (shouldSkipValidation()) return validator;
|
|
257
|
+
const value = current.value;
|
|
258
|
+
if (typeof value !== "string") {
|
|
259
|
+
current.pushError(message);
|
|
260
|
+
return validator;
|
|
261
|
+
}
|
|
262
|
+
const match = value.match(/^data:([A-Za-z-+\/]+);base64,/);
|
|
263
|
+
if (!match) {
|
|
264
|
+
current.pushError(message);
|
|
265
|
+
return validator;
|
|
266
|
+
}
|
|
267
|
+
const mimeType = match[1];
|
|
268
|
+
if (!validTypes.includes(mimeType)) {
|
|
269
|
+
current.pushError(message);
|
|
270
|
+
}
|
|
271
|
+
return validator;
|
|
272
|
+
},
|
|
273
|
+
base64MaxSize(maxSize, message) {
|
|
274
|
+
if (shouldSkipValidation()) return validator;
|
|
275
|
+
const value = current.value;
|
|
276
|
+
if (typeof value !== "string") {
|
|
277
|
+
current.pushError(message);
|
|
278
|
+
return validator;
|
|
279
|
+
}
|
|
280
|
+
const base64Content = value.split(",")[1];
|
|
281
|
+
if (!base64Content) {
|
|
282
|
+
current.pushError(message);
|
|
283
|
+
return validator;
|
|
284
|
+
}
|
|
285
|
+
const sizeInBytes = Math.ceil(base64Content.length * 3 / 4);
|
|
286
|
+
if (sizeInBytes > maxSize) {
|
|
287
|
+
current.pushError(message);
|
|
288
|
+
}
|
|
289
|
+
return validator;
|
|
290
|
+
},
|
|
253
291
|
cnpj: (message) => {
|
|
254
292
|
if (shouldSkipValidation()) {
|
|
255
293
|
return validator;
|
package/dist/index.d.cts
CHANGED
|
@@ -13,11 +13,13 @@ 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
|
}
|
|
20
20
|
interface ValidatorField {
|
|
21
|
+
base64Type(validTypes: string[], message: string): ValidatorField;
|
|
22
|
+
base64MaxSize(maxSize: number, message: string): ValidatorField;
|
|
21
23
|
cnpj(message: string): ValidatorField;
|
|
22
24
|
cpf(message: string): ValidatorField;
|
|
23
25
|
each(callback: <U extends Record<string, TInputValue>>(item: U, index: number, subValidator: ReturnType<typeof createValidator<U>>) => void): ValidatorField;
|
package/dist/index.d.ts
CHANGED
|
@@ -13,11 +13,13 @@ 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
|
}
|
|
20
20
|
interface ValidatorField {
|
|
21
|
+
base64Type(validTypes: string[], message: string): ValidatorField;
|
|
22
|
+
base64MaxSize(maxSize: number, message: string): ValidatorField;
|
|
21
23
|
cnpj(message: string): ValidatorField;
|
|
22
24
|
cpf(message: string): ValidatorField;
|
|
23
25
|
each(callback: <U extends Record<string, TInputValue>>(item: U, index: number, subValidator: ReturnType<typeof createValidator<U>>) => void): ValidatorField;
|
package/dist/index.js
CHANGED
|
@@ -196,6 +196,8 @@ function createValidator() {
|
|
|
196
196
|
isValidType = typeof value === "object" && value !== null && !Array.isArray(value);
|
|
197
197
|
} else if (type === "file") {
|
|
198
198
|
isValidType = value instanceof File;
|
|
199
|
+
} else if (type === "base64") {
|
|
200
|
+
isValidType = typeof value === "string" && !!value.match(/^data:([A-Za-z-+\/]+);base64,([A-Za-z0-9+/=]+)$/);
|
|
199
201
|
} else if (type === "date") {
|
|
200
202
|
isValidType = typeof value === "string" && !Number.isNaN(new Date(value).getTime());
|
|
201
203
|
} else {
|
|
@@ -212,6 +214,42 @@ function createValidator() {
|
|
|
212
214
|
return !current.required && (current.value === void 0 || current.value === null || current.value === "");
|
|
213
215
|
};
|
|
214
216
|
const validator = {
|
|
217
|
+
base64Type(validTypes, message) {
|
|
218
|
+
if (shouldSkipValidation()) return validator;
|
|
219
|
+
const value = current.value;
|
|
220
|
+
if (typeof value !== "string") {
|
|
221
|
+
current.pushError(message);
|
|
222
|
+
return validator;
|
|
223
|
+
}
|
|
224
|
+
const match = value.match(/^data:([A-Za-z-+\/]+);base64,/);
|
|
225
|
+
if (!match) {
|
|
226
|
+
current.pushError(message);
|
|
227
|
+
return validator;
|
|
228
|
+
}
|
|
229
|
+
const mimeType = match[1];
|
|
230
|
+
if (!validTypes.includes(mimeType)) {
|
|
231
|
+
current.pushError(message);
|
|
232
|
+
}
|
|
233
|
+
return validator;
|
|
234
|
+
},
|
|
235
|
+
base64MaxSize(maxSize, message) {
|
|
236
|
+
if (shouldSkipValidation()) return validator;
|
|
237
|
+
const value = current.value;
|
|
238
|
+
if (typeof value !== "string") {
|
|
239
|
+
current.pushError(message);
|
|
240
|
+
return validator;
|
|
241
|
+
}
|
|
242
|
+
const base64Content = value.split(",")[1];
|
|
243
|
+
if (!base64Content) {
|
|
244
|
+
current.pushError(message);
|
|
245
|
+
return validator;
|
|
246
|
+
}
|
|
247
|
+
const sizeInBytes = Math.ceil(base64Content.length * 3 / 4);
|
|
248
|
+
if (sizeInBytes > maxSize) {
|
|
249
|
+
current.pushError(message);
|
|
250
|
+
}
|
|
251
|
+
return validator;
|
|
252
|
+
},
|
|
215
253
|
cnpj: (message) => {
|
|
216
254
|
if (shouldSkipValidation()) {
|
|
217
255
|
return validator;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@excofy/utils",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.3.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
|
+
};
|
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 {
|
|
@@ -19,6 +21,8 @@ interface IInputErrors {
|
|
|
19
21
|
}
|
|
20
22
|
|
|
21
23
|
interface ValidatorField {
|
|
24
|
+
base64Type(validTypes: string[], message: string): ValidatorField;
|
|
25
|
+
base64MaxSize(maxSize: number, message: string): ValidatorField;
|
|
22
26
|
cnpj(message: string): ValidatorField;
|
|
23
27
|
cpf(message: string): ValidatorField;
|
|
24
28
|
each(
|
|
@@ -139,6 +143,10 @@ export function createValidator<
|
|
|
139
143
|
typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
140
144
|
} else if (type === 'file') {
|
|
141
145
|
isValidType = value instanceof File;
|
|
146
|
+
} else if (type === 'base64') {
|
|
147
|
+
isValidType =
|
|
148
|
+
typeof value === 'string' &&
|
|
149
|
+
!!value.match(/^data:([A-Za-z-+\/]+);base64,([A-Za-z0-9+/=]+)$/);
|
|
142
150
|
} else if (type === 'date') {
|
|
143
151
|
isValidType =
|
|
144
152
|
typeof value === 'string' && !Number.isNaN(new Date(value).getTime());
|
|
@@ -169,6 +177,55 @@ export function createValidator<
|
|
|
169
177
|
};
|
|
170
178
|
|
|
171
179
|
const validator: ValidatorField = {
|
|
180
|
+
base64Type(validTypes: string[], message: string) {
|
|
181
|
+
if (shouldSkipValidation()) return validator;
|
|
182
|
+
|
|
183
|
+
const value = current.value;
|
|
184
|
+
|
|
185
|
+
if (typeof value !== 'string') {
|
|
186
|
+
current.pushError(message);
|
|
187
|
+
return validator;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
const match = value.match(/^data:([A-Za-z-+\/]+);base64,/);
|
|
191
|
+
if (!match) {
|
|
192
|
+
current.pushError(message);
|
|
193
|
+
return validator;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
const mimeType = match[1];
|
|
197
|
+
if (!validTypes.includes(mimeType)) {
|
|
198
|
+
current.pushError(message);
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
return validator;
|
|
202
|
+
},
|
|
203
|
+
|
|
204
|
+
base64MaxSize(maxSize: number, message: string) {
|
|
205
|
+
if (shouldSkipValidation()) return validator;
|
|
206
|
+
|
|
207
|
+
const value = current.value;
|
|
208
|
+
|
|
209
|
+
if (typeof value !== 'string') {
|
|
210
|
+
current.pushError(message);
|
|
211
|
+
return validator;
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
const base64Content = value.split(',')[1];
|
|
215
|
+
if (!base64Content) {
|
|
216
|
+
current.pushError(message);
|
|
217
|
+
return validator;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
// Calcula o tamanho do arquivo em bytes
|
|
221
|
+
const sizeInBytes = Math.ceil((base64Content.length * 3) / 4);
|
|
222
|
+
if (sizeInBytes > maxSize) {
|
|
223
|
+
current.pushError(message);
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
return validator;
|
|
227
|
+
},
|
|
228
|
+
|
|
172
229
|
cnpj: (message: string) => {
|
|
173
230
|
if (shouldSkipValidation()) {
|
|
174
231
|
return validator;
|
|
@@ -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
|
+
});
|