@gyramais/log-redaction 0.2.0 → 0.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/README.md +3 -1
- package/dist/index.d.ts +7 -7
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +37 -23
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/index.ts +61 -27
package/README.md
CHANGED
|
@@ -21,7 +21,9 @@ precise compor caso específico ou testar direto.
|
|
|
21
21
|
|
|
22
22
|
**Documento sai parcial:** `cpf`, `cnpj`, `document`, `documents`, `newDocument` e
|
|
23
23
|
`signerDocument` preservam os 3 primeiros e os 2 últimos dígitos
|
|
24
|
-
(`11122233344` -> `111******44`
|
|
24
|
+
(`11122233344` -> `111******44`; `12ABC34501DE35` -> `12A*********35`, preservando as
|
|
25
|
+
letras do CNPJ alfanumérico), em vez de virarem `****`. Só valor com forma de
|
|
26
|
+
documento — 11 ou 14 caracteres — sai parcial; o resto vai para mascaramento total. É a convenção que já
|
|
25
27
|
existia em `gyra-integration/src/common/utils/mask-document.ts`, e os casos da spec
|
|
26
28
|
daquele arquivo são testados aqui para as implementações não divergirem. As outras
|
|
27
29
|
chaves de PII seguem em mascaramento total.
|
package/dist/index.d.ts
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import type { IncomingHttpHeaders } from 'http';
|
|
2
|
-
export declare const SAFE_HEADERS: string[];
|
|
3
|
-
export declare const SENSITIVE_FIELDS: string[];
|
|
4
|
-
export declare const OAUTH_CALLBACK_ONLY_FIELDS: string[];
|
|
5
|
-
export declare const OIDC_CALLBACK_MARKERS: string[];
|
|
6
|
-
export declare const PII_FIELDS: string[];
|
|
7
|
-
export declare const DOCUMENT_FIELDS: string[];
|
|
8
|
-
export declare const AMBIGUOUS_PII_FIELDS: string[];
|
|
2
|
+
export declare const SAFE_HEADERS: readonly string[];
|
|
3
|
+
export declare const SENSITIVE_FIELDS: readonly string[];
|
|
4
|
+
export declare const OAUTH_CALLBACK_ONLY_FIELDS: readonly string[];
|
|
5
|
+
export declare const OIDC_CALLBACK_MARKERS: readonly string[];
|
|
6
|
+
export declare const PII_FIELDS: readonly string[];
|
|
7
|
+
export declare const DOCUMENT_FIELDS: readonly string[];
|
|
8
|
+
export declare const AMBIGUOUS_PII_FIELDS: readonly string[];
|
|
9
9
|
export declare const LOOKS_PERSONAL: RegExp;
|
|
10
10
|
export declare const FORMATTING_NOISE: RegExp;
|
|
11
11
|
export declare const looksPersonal: (value: unknown) => boolean;
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AA4CA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,MAAM,CAAC;AAQhD,eAAO,MAAM,YAAY,mBAMvB,CAAC;AAGH,eAAO,MAAM,gBAAgB,mBAuB3B,CAAC;AAWH,eAAO,MAAM,0BAA0B,mBAA2B,CAAC;AAGnE,eAAO,MAAM,qBAAqB,mBAAqC,CAAC;AAgBxE,eAAO,MAAM,UAAU,mBAcrB,CAAC;AAUH,eAAO,MAAM,eAAe,mBAO1B,CAAC;AAQH,eAAO,MAAM,oBAAoB,mBAAwB,CAAC;AAM1D,eAAO,MAAM,cAAc,QAAqB,CAAC;AAKjD,eAAO,MAAM,gBAAgB,QAAa,CAAC;AAE3C,eAAO,MAAM,aAAa,GAAI,OAAO,OAAO,KAAG,OAEW,CAAC;AAE3D,eAAO,MAAM,QAAQ,SAAS,CAAC;AAC/B,eAAO,MAAM,SAAS,+BAA0B,CAAC;AACjD,eAAO,MAAM,QAAQ,eAAe,CAAC;AAIrC,eAAO,MAAM,cAAc,IAAI,CAAC;AAOhC,eAAO,MAAM,YAAY,GAAI,KAAK,MAAM,KAAG,MACH,CAAC;AAWzC,eAAO,MAAM,WAAW,GAAI,KAAK,MAAM,KAAG,OACH,CAAC;AACxC,eAAO,MAAM,KAAK,GAAI,KAAK,MAAM,KAAG,OAA0C,CAAC;AAC/E,eAAO,MAAM,UAAU,GAAI,KAAK,MAAM,KAAG,OACH,CAAC;AAYvC,eAAO,MAAM,cAAc,GAAI,KAAK,MAAM,EAAE,OAAO,OAAO,KAAG,OAEkB,CAAC;AAEhF,eAAO,MAAM,mBAAmB,GAAI,KAAK,MAAM,KAAG,OACD,CAAC;AAElD,eAAO,MAAM,mBAAmB,GAAI,KAAK,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAG,OACM,CAAC;AAK1E,eAAO,MAAM,OAAO,GAAI,OAAO,OAAO,KAAG,OAgBxC,CAAC;AAuBF,eAAO,MAAM,YAAY,GAAI,OAAO,OAAO,KAAG,OAoC7C,CAAC;AAIF,eAAO,MAAM,eAAe,GAC1B,SAAS,mBAAmB,GAAG,SAAS,KACvC,MAAM,CAAC,MAAM,EAAE,OAAO,CAcxB,CAAC;AAcF,eAAO,MAAM,aAAa,GAAI,CAAC,EAC7B,OAAO,CAAC,EACR,cAAS,EACT,sBAA4B,KAC3B,CA8CF,CAAC;AAMF,eAAO,MAAM,OAAO,GAAI,KAAK,MAAM,KAAG,MAgCrC,CAAC;AAOF,eAAO,MAAM,aAAa,GACxB,KAAK,OAAO,KACX;IAAE,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAUlD,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -8,15 +8,15 @@ exports.describeError = exports.maskUrl = exports.maskSensitive = exports.pickSa
|
|
|
8
8
|
// Ficam de fora, por serem credencial viva: `authorization`, `cookie`,
|
|
9
9
|
// `gyra-client-secret`. O `gyra-client-id` também fica de fora: sozinho é só
|
|
10
10
|
// um identificador, mas emparelhado com o secret num mesmo log facilita ataque.
|
|
11
|
-
exports.SAFE_HEADERS = [
|
|
11
|
+
exports.SAFE_HEADERS = Object.freeze([
|
|
12
12
|
'x-amzn-trace-id',
|
|
13
13
|
'x-forwarded-for',
|
|
14
14
|
'user-agent',
|
|
15
15
|
'content-type',
|
|
16
16
|
'content-length',
|
|
17
|
-
];
|
|
17
|
+
]);
|
|
18
18
|
// Credencial: o valor não tem utilidade nenhuma no log, vai inteiro para `****`.
|
|
19
|
-
exports.SENSITIVE_FIELDS = [
|
|
19
|
+
exports.SENSITIVE_FIELDS = Object.freeze([
|
|
20
20
|
'password',
|
|
21
21
|
'token',
|
|
22
22
|
'accessToken',
|
|
@@ -39,7 +39,7 @@ exports.SENSITIVE_FIELDS = [
|
|
|
39
39
|
// usa `code` como campo não sensível.
|
|
40
40
|
'code',
|
|
41
41
|
'idToken',
|
|
42
|
-
];
|
|
42
|
+
]);
|
|
43
43
|
// `state` é o nonce anti-CSRF do OAuth. Na query ele é sempre OAuth. No body só
|
|
44
44
|
// é OAuth no callback OIDC com `responseMode: 'form_post'` — o do Microsoft
|
|
45
45
|
// (`microsoft-oauth.strategy.ts:19`, `responseType: 'code id_token'`), numa rota
|
|
@@ -49,9 +49,9 @@ exports.SENSITIVE_FIELDS = [
|
|
|
49
49
|
// No body, portanto, só mascara quando a assinatura do callback OIDC está
|
|
50
50
|
// presente: `code` ou `idToken` no mesmo objeto. Um payload de endereço não tem
|
|
51
51
|
// nenhum dos dois.
|
|
52
|
-
exports.OAUTH_CALLBACK_ONLY_FIELDS = ['state'];
|
|
52
|
+
exports.OAUTH_CALLBACK_ONLY_FIELDS = Object.freeze(['state']);
|
|
53
53
|
// Presença destas chaves marca o objeto como callback OIDC.
|
|
54
|
-
exports.OIDC_CALLBACK_MARKERS = ['code', 'idToken'];
|
|
54
|
+
exports.OIDC_CALLBACK_MARKERS = Object.freeze(['code', 'idToken']);
|
|
55
55
|
// Dado pessoal: categoria distinta de credencial. Não pode ir em plain text —
|
|
56
56
|
// requisito LGPD já vigente na plataforma, registrado em
|
|
57
57
|
// `gyra-integration/specs/001-scr-raw-data-api/spec.md:179` — mas, diferente de
|
|
@@ -66,7 +66,7 @@ exports.OIDC_CALLBACK_MARKERS = ['code', 'idToken'];
|
|
|
66
66
|
// `documentType` e `documentTypes` NÃO entram: são enums (CPF/CNPJ), não
|
|
67
67
|
// valores. A comparação é por chave exata, então ficam de fora naturalmente —
|
|
68
68
|
// um match por substring em "document" os pegaria e perderia informação útil.
|
|
69
|
-
exports.PII_FIELDS = [
|
|
69
|
+
exports.PII_FIELDS = Object.freeze([
|
|
70
70
|
'email',
|
|
71
71
|
'signerEmail',
|
|
72
72
|
'username',
|
|
@@ -80,7 +80,7 @@ exports.PII_FIELDS = [
|
|
|
80
80
|
'phoneNumber',
|
|
81
81
|
'signerPhoneNumber',
|
|
82
82
|
'signerName',
|
|
83
|
-
];
|
|
83
|
+
]);
|
|
84
84
|
// Documento é PII, mas de um tipo em que dígito parcial ainda é útil para
|
|
85
85
|
// investigar sem identificar a pessoa. Estas chaves recebem mascaramento PARCIAL
|
|
86
86
|
// (`maskDocument`) em vez de `****`; as outras chaves de PII_FIELDS seguem no
|
|
@@ -89,21 +89,21 @@ exports.PII_FIELDS = [
|
|
|
89
89
|
// A lista é subconjunto de PII_FIELDS de propósito: a ordem de checagem em
|
|
90
90
|
// `maskSensitive` testa documento ANTES de PII, então o que estiver aqui ganha o
|
|
91
91
|
// tratamento parcial e o resto cai no total.
|
|
92
|
-
exports.DOCUMENT_FIELDS = [
|
|
92
|
+
exports.DOCUMENT_FIELDS = Object.freeze([
|
|
93
93
|
'cpf',
|
|
94
94
|
'cnpj',
|
|
95
95
|
'document',
|
|
96
96
|
'documents',
|
|
97
97
|
'newDocument',
|
|
98
98
|
'signerDocument',
|
|
99
|
-
];
|
|
99
|
+
]);
|
|
100
100
|
// Chaves cujo significado varia entre os 15 serviços. Aqui a decisão é pelo
|
|
101
101
|
// VALOR, não pelo nome: `to` é destinatário de e-mail no gyra-communication, mas
|
|
102
102
|
// é data ISO em `UsageQueryDto.to` (gyra-billing) e limite de faixa numérica em
|
|
103
103
|
// `CreateDto.to: number` (gyra-core e gyra-credit-policy, 6 DTOs). Mascarar por
|
|
104
104
|
// nome apagaria o campo que se quer ver ao depurar faixa de risco ou intervalo
|
|
105
105
|
// de cobrança — a mesma disciplina já aplicada ao `documentType`.
|
|
106
|
-
exports.AMBIGUOUS_PII_FIELDS = ['to'];
|
|
106
|
+
exports.AMBIGUOUS_PII_FIELDS = Object.freeze(['to']);
|
|
107
107
|
// Casa e-mail e telefone; não casa data ISO nem número pequeno. Erra para o
|
|
108
108
|
// lado de mascarar: um epoch em milissegundos tem 13 dígitos e seria mascarado —
|
|
109
109
|
// aceitável, porque nenhum `to` da plataforma carrega epoch hoje e o custo de
|
|
@@ -185,9 +185,16 @@ exports.maskPii = maskPii;
|
|
|
185
185
|
// entrega é minimização com utilidade: dá para correlacionar duas linhas do mesmo
|
|
186
186
|
// documento e conferir prefixo de CNPJ sem reconstruir o número.
|
|
187
187
|
//
|
|
188
|
-
//
|
|
189
|
-
//
|
|
190
|
-
|
|
188
|
+
// Só valor com FORMA de documento sai parcial: CPF tem 11 caracteres, CNPJ tem 14.
|
|
189
|
+
// Qualquer outra coisa que chegue numa chave de documento é dado desconhecido — pode
|
|
190
|
+
// ser um nome, um e-mail, um id — e expor pedaço de dado desconhecido num campo de
|
|
191
|
+
// PII é o default errado. Esses vão para mascaramento total.
|
|
192
|
+
//
|
|
193
|
+
// Isto é mais restritivo que o `mask-document.ts` do gyra-integration, que aplica o
|
|
194
|
+
// parcial a qualquer valor com mais de 5 caracteres. A divergência é deliberada e só
|
|
195
|
+
// para o lado seguro: para CPF e CNPJ de verdade — os casos que importam — as duas
|
|
196
|
+
// implementações produzem exatamente a mesma saída.
|
|
197
|
+
const DOCUMENT_LENGTHS = [11, 14];
|
|
191
198
|
const maskDocument = (value) => {
|
|
192
199
|
if (Array.isArray(value)) {
|
|
193
200
|
return value.map(exports.maskDocument);
|
|
@@ -198,18 +205,25 @@ const maskDocument = (value) => {
|
|
|
198
205
|
if (typeof value !== 'string' && typeof value !== 'number') {
|
|
199
206
|
return exports.REDACTED;
|
|
200
207
|
}
|
|
201
|
-
//
|
|
202
|
-
//
|
|
203
|
-
|
|
204
|
-
|
|
208
|
+
// Sai só a FORMATAÇÃO (ponto, barra, hífen, espaço), não todo caractere
|
|
209
|
+
// não-numérico: `12.345.678/0001-99` e `12345678000199` são o mesmo documento e
|
|
210
|
+
// têm que sair iguais, mas o CNPJ alfanumérico (`12.ABC.345/01DE-35`, suportado
|
|
211
|
+
// desde a GYR-1444) tem LETRAS que fazem parte do documento.
|
|
212
|
+
//
|
|
213
|
+
// Descartar as letras faria a máscara mentir: `12ABC34501DE35` sairia como
|
|
214
|
+
// `123****35` — 9 caracteres onde o documento tem 14, e prefixo `123` quando o
|
|
215
|
+
// real é `12A`. Isso destrói as duas coisas que o parcial existe para dar:
|
|
216
|
+
// correlacionar duas linhas do mesmo documento, e conferir o prefixo.
|
|
217
|
+
const chars = String(value).replace(/[\s.\-/]/g, '');
|
|
218
|
+
if (!chars) {
|
|
205
219
|
return exports.REDACTED;
|
|
206
220
|
}
|
|
207
|
-
if (
|
|
208
|
-
return
|
|
221
|
+
if (!DOCUMENT_LENGTHS.includes(chars.length)) {
|
|
222
|
+
return exports.REDACTED;
|
|
209
223
|
}
|
|
210
|
-
const head =
|
|
211
|
-
const tail =
|
|
212
|
-
return `${head}${'*'.repeat(
|
|
224
|
+
const head = chars.slice(0, 3);
|
|
225
|
+
const tail = chars.slice(-2);
|
|
226
|
+
return `${head}${'*'.repeat(chars.length - 5)}${tail}`;
|
|
213
227
|
};
|
|
214
228
|
exports.maskDocument = maskDocument;
|
|
215
229
|
// Node normaliza os nomes dos headers de entrada para minúsculas em
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAAA,uDAAuD;;;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
package/src/index.ts
CHANGED
|
@@ -8,10 +8,30 @@
|
|
|
8
8
|
mesmo bloco existia duplicado e identico nos 15 servicos
|
|
9
9
|
(md5 cc04916718f5db4c776d256fc05068b3, 313 linhas, conferido nos 15 em main).
|
|
10
10
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
11
|
+
Nenhum comentario da fonte foi alterado — eles registram seis rodadas de revisao
|
|
12
|
+
e tres revisoes humanas, e explicam decisoes que ja foram questionadas e
|
|
13
|
+
defendidas. Nao reformate e nao os remova.
|
|
14
|
+
|
|
15
|
+
Divergencias em relacao a fonte, todas deliberadas e datadas:
|
|
16
|
+
|
|
17
|
+
- VISIBILIDADE (0.1.0): as declaracoes ganharam `export`. Sem mudanca de
|
|
18
|
+
assinatura nem de comportamento.
|
|
19
|
+
|
|
20
|
+
- DOCUMENTO PARCIAL (0.2.0): campos de DOCUMENT_FIELDS passam por
|
|
21
|
+
`maskDocument` e saem com 3 primeiros + 2 ultimos digitos, em vez de `****`.
|
|
22
|
+
Aqui a identidade byte-a-byte com a fonte acabou, de proposito. O formato e o
|
|
23
|
+
mesmo de gyra-integration/src/common/utils/mask-document.ts, que ja estava em
|
|
24
|
+
producao. A LGPD e principiologica e NAO prescreve contagem de digitos: mudar
|
|
25
|
+
essa contagem e decisao de compliance, com dono, e muda o log de 15 servicos.
|
|
26
|
+
|
|
27
|
+
- LISTAS CONGELADAS (0.3.0): as listas exportadas passam por `Object.freeze`.
|
|
28
|
+
Elas iam por referencia, entao um consumidor podia alterar SENSITIVE_FIELDS e
|
|
29
|
+
desligar o mascaramento do processo inteiro em silencio — o oposto do que este
|
|
30
|
+
modulo existe para garantir. Congelar faz a tentativa falhar alto, e o tipo
|
|
31
|
+
vira `readonly string[]`, o que tambem acusa em tempo de compilacao.
|
|
32
|
+
|
|
33
|
+
O md5 acima segue valendo para conferir que o bloco que cada servico REMOVE na
|
|
34
|
+
migracao nao sofreu deriva. Isso e independente do estado deste arquivo.
|
|
15
35
|
|
|
16
36
|
API que os servicos consomem: maskSensitive, maskUrl, pickSafeHeaders,
|
|
17
37
|
describeError — os quatro usados por todas as 9 variantes da classe
|
|
@@ -30,16 +50,16 @@ import type { IncomingHttpHeaders } from 'http';
|
|
|
30
50
|
// Ficam de fora, por serem credencial viva: `authorization`, `cookie`,
|
|
31
51
|
// `gyra-client-secret`. O `gyra-client-id` também fica de fora: sozinho é só
|
|
32
52
|
// um identificador, mas emparelhado com o secret num mesmo log facilita ataque.
|
|
33
|
-
export const SAFE_HEADERS = [
|
|
53
|
+
export const SAFE_HEADERS = Object.freeze([
|
|
34
54
|
'x-amzn-trace-id',
|
|
35
55
|
'x-forwarded-for',
|
|
36
56
|
'user-agent',
|
|
37
57
|
'content-type',
|
|
38
58
|
'content-length',
|
|
39
|
-
];
|
|
59
|
+
]);
|
|
40
60
|
|
|
41
61
|
// Credencial: o valor não tem utilidade nenhuma no log, vai inteiro para `****`.
|
|
42
|
-
export const SENSITIVE_FIELDS = [
|
|
62
|
+
export const SENSITIVE_FIELDS = Object.freeze([
|
|
43
63
|
'password',
|
|
44
64
|
'token',
|
|
45
65
|
'accessToken',
|
|
@@ -62,7 +82,7 @@ export const SENSITIVE_FIELDS = [
|
|
|
62
82
|
// usa `code` como campo não sensível.
|
|
63
83
|
'code',
|
|
64
84
|
'idToken',
|
|
65
|
-
];
|
|
85
|
+
]);
|
|
66
86
|
|
|
67
87
|
// `state` é o nonce anti-CSRF do OAuth. Na query ele é sempre OAuth. No body só
|
|
68
88
|
// é OAuth no callback OIDC com `responseMode: 'form_post'` — o do Microsoft
|
|
@@ -73,10 +93,10 @@ export const SENSITIVE_FIELDS = [
|
|
|
73
93
|
// No body, portanto, só mascara quando a assinatura do callback OIDC está
|
|
74
94
|
// presente: `code` ou `idToken` no mesmo objeto. Um payload de endereço não tem
|
|
75
95
|
// nenhum dos dois.
|
|
76
|
-
export const OAUTH_CALLBACK_ONLY_FIELDS = ['state'];
|
|
96
|
+
export const OAUTH_CALLBACK_ONLY_FIELDS = Object.freeze(['state']);
|
|
77
97
|
|
|
78
98
|
// Presença destas chaves marca o objeto como callback OIDC.
|
|
79
|
-
export const OIDC_CALLBACK_MARKERS = ['code', 'idToken'];
|
|
99
|
+
export const OIDC_CALLBACK_MARKERS = Object.freeze(['code', 'idToken']);
|
|
80
100
|
|
|
81
101
|
// Dado pessoal: categoria distinta de credencial. Não pode ir em plain text —
|
|
82
102
|
// requisito LGPD já vigente na plataforma, registrado em
|
|
@@ -92,7 +112,7 @@ export const OIDC_CALLBACK_MARKERS = ['code', 'idToken'];
|
|
|
92
112
|
// `documentType` e `documentTypes` NÃO entram: são enums (CPF/CNPJ), não
|
|
93
113
|
// valores. A comparação é por chave exata, então ficam de fora naturalmente —
|
|
94
114
|
// um match por substring em "document" os pegaria e perderia informação útil.
|
|
95
|
-
export const PII_FIELDS = [
|
|
115
|
+
export const PII_FIELDS = Object.freeze([
|
|
96
116
|
'email',
|
|
97
117
|
'signerEmail',
|
|
98
118
|
'username',
|
|
@@ -106,7 +126,7 @@ export const PII_FIELDS = [
|
|
|
106
126
|
'phoneNumber',
|
|
107
127
|
'signerPhoneNumber',
|
|
108
128
|
'signerName',
|
|
109
|
-
];
|
|
129
|
+
]);
|
|
110
130
|
|
|
111
131
|
// Documento é PII, mas de um tipo em que dígito parcial ainda é útil para
|
|
112
132
|
// investigar sem identificar a pessoa. Estas chaves recebem mascaramento PARCIAL
|
|
@@ -116,14 +136,14 @@ export const PII_FIELDS = [
|
|
|
116
136
|
// A lista é subconjunto de PII_FIELDS de propósito: a ordem de checagem em
|
|
117
137
|
// `maskSensitive` testa documento ANTES de PII, então o que estiver aqui ganha o
|
|
118
138
|
// tratamento parcial e o resto cai no total.
|
|
119
|
-
export const DOCUMENT_FIELDS = [
|
|
139
|
+
export const DOCUMENT_FIELDS = Object.freeze([
|
|
120
140
|
'cpf',
|
|
121
141
|
'cnpj',
|
|
122
142
|
'document',
|
|
123
143
|
'documents',
|
|
124
144
|
'newDocument',
|
|
125
145
|
'signerDocument',
|
|
126
|
-
];
|
|
146
|
+
]);
|
|
127
147
|
|
|
128
148
|
// Chaves cujo significado varia entre os 15 serviços. Aqui a decisão é pelo
|
|
129
149
|
// VALOR, não pelo nome: `to` é destinatário de e-mail no gyra-communication, mas
|
|
@@ -131,7 +151,7 @@ export const DOCUMENT_FIELDS = [
|
|
|
131
151
|
// `CreateDto.to: number` (gyra-core e gyra-credit-policy, 6 DTOs). Mascarar por
|
|
132
152
|
// nome apagaria o campo que se quer ver ao depurar faixa de risco ou intervalo
|
|
133
153
|
// de cobrança — a mesma disciplina já aplicada ao `documentType`.
|
|
134
|
-
export const AMBIGUOUS_PII_FIELDS = ['to'];
|
|
154
|
+
export const AMBIGUOUS_PII_FIELDS = Object.freeze(['to']);
|
|
135
155
|
|
|
136
156
|
// Casa e-mail e telefone; não casa data ISO nem número pequeno. Erra para o
|
|
137
157
|
// lado de mascarar: um epoch em milissegundos tem 13 dígitos e seria mascarado —
|
|
@@ -230,9 +250,16 @@ export const maskPii = (value: unknown): unknown => {
|
|
|
230
250
|
// entrega é minimização com utilidade: dá para correlacionar duas linhas do mesmo
|
|
231
251
|
// documento e conferir prefixo de CNPJ sem reconstruir o número.
|
|
232
252
|
//
|
|
233
|
-
//
|
|
234
|
-
//
|
|
235
|
-
|
|
253
|
+
// Só valor com FORMA de documento sai parcial: CPF tem 11 caracteres, CNPJ tem 14.
|
|
254
|
+
// Qualquer outra coisa que chegue numa chave de documento é dado desconhecido — pode
|
|
255
|
+
// ser um nome, um e-mail, um id — e expor pedaço de dado desconhecido num campo de
|
|
256
|
+
// PII é o default errado. Esses vão para mascaramento total.
|
|
257
|
+
//
|
|
258
|
+
// Isto é mais restritivo que o `mask-document.ts` do gyra-integration, que aplica o
|
|
259
|
+
// parcial a qualquer valor com mais de 5 caracteres. A divergência é deliberada e só
|
|
260
|
+
// para o lado seguro: para CPF e CNPJ de verdade — os casos que importam — as duas
|
|
261
|
+
// implementações produzem exatamente a mesma saída.
|
|
262
|
+
const DOCUMENT_LENGTHS = [11, 14];
|
|
236
263
|
|
|
237
264
|
export const maskDocument = (value: unknown): unknown => {
|
|
238
265
|
if (Array.isArray(value)) {
|
|
@@ -247,22 +274,29 @@ export const maskDocument = (value: unknown): unknown => {
|
|
|
247
274
|
return REDACTED;
|
|
248
275
|
}
|
|
249
276
|
|
|
250
|
-
//
|
|
251
|
-
//
|
|
252
|
-
|
|
277
|
+
// Sai só a FORMATAÇÃO (ponto, barra, hífen, espaço), não todo caractere
|
|
278
|
+
// não-numérico: `12.345.678/0001-99` e `12345678000199` são o mesmo documento e
|
|
279
|
+
// têm que sair iguais, mas o CNPJ alfanumérico (`12.ABC.345/01DE-35`, suportado
|
|
280
|
+
// desde a GYR-1444) tem LETRAS que fazem parte do documento.
|
|
281
|
+
//
|
|
282
|
+
// Descartar as letras faria a máscara mentir: `12ABC34501DE35` sairia como
|
|
283
|
+
// `123****35` — 9 caracteres onde o documento tem 14, e prefixo `123` quando o
|
|
284
|
+
// real é `12A`. Isso destrói as duas coisas que o parcial existe para dar:
|
|
285
|
+
// correlacionar duas linhas do mesmo documento, e conferir o prefixo.
|
|
286
|
+
const chars = String(value).replace(/[\s.\-/]/g, '');
|
|
253
287
|
|
|
254
|
-
if (!
|
|
288
|
+
if (!chars) {
|
|
255
289
|
return REDACTED;
|
|
256
290
|
}
|
|
257
291
|
|
|
258
|
-
if (
|
|
259
|
-
return
|
|
292
|
+
if (!DOCUMENT_LENGTHS.includes(chars.length)) {
|
|
293
|
+
return REDACTED;
|
|
260
294
|
}
|
|
261
295
|
|
|
262
|
-
const head =
|
|
263
|
-
const tail =
|
|
296
|
+
const head = chars.slice(0, 3);
|
|
297
|
+
const tail = chars.slice(-2);
|
|
264
298
|
|
|
265
|
-
return `${head}${'*'.repeat(
|
|
299
|
+
return `${head}${'*'.repeat(chars.length - 5)}${tail}`;
|
|
266
300
|
};
|
|
267
301
|
|
|
268
302
|
// Node normaliza os nomes dos headers de entrada para minúsculas em
|