hazo_secure 1.3.0 → 1.5.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/CHANGE_LOG.md +52 -0
- package/README.md +27 -0
- package/dist/crypto/index.d.ts +70 -1
- package/dist/crypto/index.js +90 -3
- package/dist/mask/index.d.ts +27 -1
- package/dist/mask/index.js +14 -0
- package/package.json +14 -14
package/CHANGE_LOG.md
CHANGED
|
@@ -1,5 +1,57 @@
|
|
|
1
1
|
# Change Log
|
|
2
2
|
|
|
3
|
+
## 1.5.0 — 2026-07-21
|
|
4
|
+
|
|
5
|
+
### New: `hazo_secure/mask` — `maskTFN` / `maskABN` display masks
|
|
6
|
+
|
|
7
|
+
- **`maskTFN(tfn)`** — masks an Australian Tax File Number for display,
|
|
8
|
+
revealing only the last 3 digits (`"***-***-789"`). Strips whitespace
|
|
9
|
+
before masking so both `"123456789"` and `"123 456 789"` normalise the
|
|
10
|
+
same way. Returns `"***"` for inputs too short to safely reveal 3 digits,
|
|
11
|
+
`""` for null/undefined/empty.
|
|
12
|
+
- **`maskABN(abn)`** — same shape for Australian Business Numbers
|
|
13
|
+
(`"**-***-***-901"`).
|
|
14
|
+
- Deliberately not added to `BUILTIN_TRANSFORMS` — these take no `maskKey`
|
|
15
|
+
and aren't deterministic-by-key like the existing DB-anonymisation
|
|
16
|
+
transforms; they're pure display formatting. Ported from Hazodocs
|
|
17
|
+
`lib/formatting.ts` (`maskTFN`/`maskABN`, previously app-local per D-011).
|
|
18
|
+
|
|
19
|
+
### New: `hazo_secure/crypto` — `randomCode` / `randomToken` / `hashToken` / `verifyToken`
|
|
20
|
+
|
|
21
|
+
- **`randomCode(length = 16)`** — cryptographically secure code from a
|
|
22
|
+
human-readable alphabet (`[A-Z2-9]`, excludes ambiguous `0`/`O`/`1`/`I`/`L`).
|
|
23
|
+
Throws for `length < 8` (inadequate entropy).
|
|
24
|
+
- **`randomToken(bytes = 32)`** — cryptographically secure base64url token
|
|
25
|
+
(43 chars at the default byte length).
|
|
26
|
+
- **`hashToken(raw)`** — scrypt-hashes a raw token under a random 16-byte
|
|
27
|
+
salt for at-rest storage; returns `"<saltHex>:<hashHex>"`.
|
|
28
|
+
- **`verifyToken(raw, stored)`** — recomputes the scrypt hash under the
|
|
29
|
+
embedded salt and compares in constant time via `timingSafeEqual`. Fails
|
|
30
|
+
closed (`false`, never throws) for a malformed `stored` value.
|
|
31
|
+
- Added as a sibling module (`src/crypto/tokens.ts`) alongside the existing
|
|
32
|
+
`signHmac`/`verifyHmac` primitives in the same `./crypto` subpath — no new
|
|
33
|
+
subpath export. Ported from Hazodocs `lib/security/random.ts` and
|
|
34
|
+
`lib/invitations/tokens.ts`.
|
|
35
|
+
|
|
36
|
+
## 1.4.0 — 2026-07-12
|
|
37
|
+
|
|
38
|
+
### New: `hazo_secure/crypto` — generic HMAC sign/verify primitive
|
|
39
|
+
|
|
40
|
+
- **`signHmac(payload, secret)`** — signs an arbitrary UTF-8 payload string
|
|
41
|
+
with HMAC-SHA256, returning a `<payloadB64url>.<sigB64url>` token. No
|
|
42
|
+
expiry/claims logic — callers put their own JSON in the payload and handle
|
|
43
|
+
their own expiry/revocation.
|
|
44
|
+
- **`verifyHmac(token, secret)`** — constant-time verification via
|
|
45
|
+
`timingSafeEqual`, with a length pre-check on the signature against a
|
|
46
|
+
fixed constant before comparing, and a caught missing/empty-secret path
|
|
47
|
+
that fails closed with `{ valid: false, reason: "malformed" }` instead of
|
|
48
|
+
throwing. Returns `{ valid: true, payload }` with the decoded original
|
|
49
|
+
payload string on success.
|
|
50
|
+
- **`HmacVerifyResult`** type: `{ valid: true; payload: string } | { valid: false; reason: "malformed" | "signature_mismatch" }`.
|
|
51
|
+
- Dependency-free (only `node:crypto`); added to the existing `./crypto`
|
|
52
|
+
subpath export, no new subpath. Motivated by `hazo_embed`'s need for
|
|
53
|
+
domain-locked embed-key token signing, but kept fully generic.
|
|
54
|
+
|
|
3
55
|
## 1.3.0 — 2026-06-12
|
|
4
56
|
|
|
5
57
|
### New: `hazo_secure/secrets` — SecretsProvider
|
package/README.md
CHANGED
|
@@ -93,6 +93,33 @@ gdpr.registerExporter({
|
|
|
93
93
|
});
|
|
94
94
|
```
|
|
95
95
|
|
|
96
|
+
## New in 1.5.0
|
|
97
|
+
|
|
98
|
+
### `hazo_secure/mask` — `maskTFN` / `maskABN` display masks
|
|
99
|
+
|
|
100
|
+
```ts
|
|
101
|
+
import { maskTFN, maskABN } from "hazo_secure/mask";
|
|
102
|
+
|
|
103
|
+
maskTFN("123 456 789"); // "***-***-789"
|
|
104
|
+
maskABN("12 345 678 901"); // "**-***-***-901"
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
Pure display formatting for Australian Tax File Numbers / ABNs — reveals only the last 3 digits, tolerant of space-formatted input, `""` for null/undefined/empty. Not part of `BUILTIN_TRANSFORMS` (no `maskKey`, not a DB-anonymisation transform).
|
|
108
|
+
|
|
109
|
+
### `hazo_secure/crypto` — `randomCode` / `randomToken` / `hashToken` / `verifyToken`
|
|
110
|
+
|
|
111
|
+
```ts
|
|
112
|
+
import { randomCode, randomToken, hashToken, verifyToken } from "hazo_secure/crypto";
|
|
113
|
+
|
|
114
|
+
const code = randomCode(); // "K7XQ9M2Z4RHY8VNC" — human-readable, no 0/O/1/I/L
|
|
115
|
+
const token = randomToken(); // base64url, 32 random bytes by default
|
|
116
|
+
|
|
117
|
+
const stored = await hashToken(token); // "<saltHex>:<hashHex>" — store this
|
|
118
|
+
const ok = await verifyToken(token, stored); // true
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
`hashToken`/`verifyToken` use scrypt with a random per-token salt; `verifyToken` fails closed (`false`, never throws) for a malformed stored value.
|
|
122
|
+
|
|
96
123
|
## New in 1.0.0
|
|
97
124
|
|
|
98
125
|
### `hazo_secure/ratelimit` — ConnectRateLimitStore (token bucket)
|
package/dist/crypto/index.d.ts
CHANGED
|
@@ -31,6 +31,75 @@ declare class HttpKeyProvider implements KeyProvider {
|
|
|
31
31
|
clearCache(): void;
|
|
32
32
|
}
|
|
33
33
|
|
|
34
|
+
/**
|
|
35
|
+
* Sign an arbitrary UTF-8 payload string with HMAC-SHA256, returning a
|
|
36
|
+
* `<payloadB64url>.<sigB64url>` token. The payload is opaque to this
|
|
37
|
+
* module — callers put their own JSON (or any string) in it and are
|
|
38
|
+
* responsible for their own expiry/revocation semantics; this primitive
|
|
39
|
+
* only proves the payload wasn't tampered with and was signed under `secret`.
|
|
40
|
+
*/
|
|
41
|
+
declare function signHmac(payload: string, secret: string): string;
|
|
42
|
+
type HmacVerifyResult = {
|
|
43
|
+
valid: true;
|
|
44
|
+
payload: string;
|
|
45
|
+
} | {
|
|
46
|
+
valid: false;
|
|
47
|
+
reason: "malformed" | "signature_mismatch";
|
|
48
|
+
};
|
|
49
|
+
/**
|
|
50
|
+
* Verify a token produced by `signHmac`. Constant-time signature comparison
|
|
51
|
+
* via `timingSafeEqual`, with a length pre-check against a fixed constant
|
|
52
|
+
* (not secret-dependent) so short/garbage signatures never reach the
|
|
53
|
+
* timing-safe path. Fails closed — never throws, even for a missing/empty
|
|
54
|
+
* `secret` or a malformed token.
|
|
55
|
+
*/
|
|
56
|
+
declare function verifyHmac(token: string, secret: string): HmacVerifyResult;
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Generate a cryptographically secure random code using a human-readable
|
|
60
|
+
* base32-ish alphabet. Excludes visually ambiguous characters (`0`/`O`,
|
|
61
|
+
* `1`/`I`/`L`) to minimize transcription errors — suitable for codes a
|
|
62
|
+
* person reads aloud or copies from a screen/print-out (invitation codes,
|
|
63
|
+
* short-lived verification codes, etc.).
|
|
64
|
+
*
|
|
65
|
+
* @param length - desired code length (default: 16 chars)
|
|
66
|
+
* @throws {Error} if `length < 8` (inadequate entropy)
|
|
67
|
+
* @returns a string of `length` characters drawn from `[A-Z2-9]` excluding `0`/`O`/`1`/`I`/`L`
|
|
68
|
+
*/
|
|
69
|
+
declare function randomCode(length?: number): string;
|
|
70
|
+
/**
|
|
71
|
+
* Generate a cryptographically secure random token in base64url encoding.
|
|
72
|
+
* Suitable for session tokens, API keys, password-reset tokens, and
|
|
73
|
+
* invitation tokens.
|
|
74
|
+
*
|
|
75
|
+
* @param bytes - number of random bytes (default: 32, resulting in 43 base64url chars)
|
|
76
|
+
* @returns a base64url string (no `+`, `/`, or `=` padding)
|
|
77
|
+
*/
|
|
78
|
+
declare function randomToken(bytes?: number): string;
|
|
79
|
+
/**
|
|
80
|
+
* Hash a raw token for at-rest storage using scrypt with a random 16-byte
|
|
81
|
+
* salt. The returned string embeds the salt so `verifyToken` doesn't need it
|
|
82
|
+
* supplied separately — store the returned string verbatim (e.g. in a
|
|
83
|
+
* `token_hash` column) and discard the raw token.
|
|
84
|
+
*
|
|
85
|
+
* Format: `<saltHex>:<hashHex>` (scrypt output is 64 bytes / 128 hex chars).
|
|
86
|
+
*
|
|
87
|
+
* @param raw - the plaintext token to hash (e.g. output of `randomToken`)
|
|
88
|
+
* @returns `"<saltHex>:<hashHex>"`
|
|
89
|
+
*/
|
|
90
|
+
declare function hashToken(raw: string): Promise<string>;
|
|
91
|
+
/**
|
|
92
|
+
* Verify a raw token against a hash produced by `hashToken`. Recomputes the
|
|
93
|
+
* scrypt hash under the embedded salt and compares in constant time via
|
|
94
|
+
* `timingSafeEqual`. Fails closed — returns `false` (never throws) for a
|
|
95
|
+
* malformed `stored` value (wrong shape, non-hex segments, etc.).
|
|
96
|
+
*
|
|
97
|
+
* @param raw - the plaintext token supplied by the caller
|
|
98
|
+
* @param stored - the `"<saltHex>:<hashHex>"` string previously returned by `hashToken`
|
|
99
|
+
* @returns `true` if `raw` hashes to `stored` under its embedded salt, else `false`
|
|
100
|
+
*/
|
|
101
|
+
declare function verifyToken(raw: string, stored: string): Promise<boolean>;
|
|
102
|
+
|
|
34
103
|
/**
|
|
35
104
|
* Source of symmetric keys for `encryptField` / `decryptField`. The current
|
|
36
105
|
* key is used for encryption; `byId` resolves any key (current or rotated-out)
|
|
@@ -177,4 +246,4 @@ declare class LookupKeyProvider implements KeyProvider {
|
|
|
177
246
|
* Convention: `<table>:<entityId>:<field>` — collision-free across tables. */
|
|
178
247
|
declare function aadFor(table: string, entityId: string, field: string): string;
|
|
179
248
|
|
|
180
|
-
export { CryptoError, type CryptoErrorCode, type EncryptedField, EnvKeyProvider, HttpKeyProvider, type HttpKeyProviderOptions, type KeyProvider, LookupKeyProvider, StaticKeyProvider, aadFor, decryptField, encryptField };
|
|
249
|
+
export { CryptoError, type CryptoErrorCode, type EncryptedField, EnvKeyProvider, type HmacVerifyResult, HttpKeyProvider, type HttpKeyProviderOptions, type KeyProvider, LookupKeyProvider, StaticKeyProvider, aadFor, decryptField, encryptField, hashToken, randomCode, randomToken, signHmac, verifyHmac, verifyToken };
|
package/dist/crypto/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// src/crypto/index.ts
|
|
2
|
-
import { createCipheriv, createDecipheriv, randomBytes } from "crypto";
|
|
2
|
+
import { createCipheriv, createDecipheriv, randomBytes as randomBytes2 } from "crypto";
|
|
3
3
|
import { HazoError } from "hazo_core";
|
|
4
4
|
|
|
5
5
|
// src/crypto/provider-http.ts
|
|
@@ -79,6 +79,87 @@ var HttpKeyProvider = class {
|
|
|
79
79
|
}
|
|
80
80
|
};
|
|
81
81
|
|
|
82
|
+
// src/crypto/hmac.ts
|
|
83
|
+
import { createHmac, timingSafeEqual } from "crypto";
|
|
84
|
+
var HMAC_B64URL_LEN = 43;
|
|
85
|
+
function b64url(input) {
|
|
86
|
+
const buf = typeof input === "string" ? Buffer.from(input, "utf8") : input;
|
|
87
|
+
return buf.toString("base64").replace(/=+$/g, "").replace(/\+/g, "-").replace(/\//g, "_");
|
|
88
|
+
}
|
|
89
|
+
function b64urlDecode(input) {
|
|
90
|
+
const pad = input.length % 4 === 0 ? "" : "=".repeat(4 - input.length % 4);
|
|
91
|
+
return Buffer.from(input.replace(/-/g, "+").replace(/_/g, "/") + pad, "base64");
|
|
92
|
+
}
|
|
93
|
+
function sign(payloadB64, secret) {
|
|
94
|
+
if (!secret) throw new Error("hazo_secure/crypto: HMAC secret is not set");
|
|
95
|
+
return b64url(createHmac("sha256", secret).update(payloadB64).digest());
|
|
96
|
+
}
|
|
97
|
+
function signHmac(payload, secret) {
|
|
98
|
+
const payloadB64 = b64url(payload);
|
|
99
|
+
const sig = sign(payloadB64, secret);
|
|
100
|
+
return `${payloadB64}.${sig}`;
|
|
101
|
+
}
|
|
102
|
+
function verifyHmac(token, secret) {
|
|
103
|
+
if (!secret) return { valid: false, reason: "malformed" };
|
|
104
|
+
if (!token || typeof token !== "string") return { valid: false, reason: "malformed" };
|
|
105
|
+
const parts = token.split(".");
|
|
106
|
+
if (parts.length !== 2) return { valid: false, reason: "malformed" };
|
|
107
|
+
const [payloadB64, sig] = parts;
|
|
108
|
+
if (sig.length !== HMAC_B64URL_LEN) {
|
|
109
|
+
return { valid: false, reason: "signature_mismatch" };
|
|
110
|
+
}
|
|
111
|
+
let expectedSig;
|
|
112
|
+
try {
|
|
113
|
+
expectedSig = sign(payloadB64, secret);
|
|
114
|
+
} catch {
|
|
115
|
+
return { valid: false, reason: "malformed" };
|
|
116
|
+
}
|
|
117
|
+
const a = Buffer.from(sig);
|
|
118
|
+
const b = Buffer.from(expectedSig);
|
|
119
|
+
if (a.length !== b.length || !timingSafeEqual(a, b)) {
|
|
120
|
+
return { valid: false, reason: "signature_mismatch" };
|
|
121
|
+
}
|
|
122
|
+
let payload;
|
|
123
|
+
try {
|
|
124
|
+
payload = b64urlDecode(payloadB64).toString("utf8");
|
|
125
|
+
} catch {
|
|
126
|
+
return { valid: false, reason: "malformed" };
|
|
127
|
+
}
|
|
128
|
+
return { valid: true, payload };
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
// src/crypto/tokens.ts
|
|
132
|
+
import { randomBytes, randomInt, scryptSync, timingSafeEqual as timingSafeEqual2 } from "crypto";
|
|
133
|
+
var CODE_ALPHABET = "ABCDEFGHJKMNPQRSTUVWXYZ23456789";
|
|
134
|
+
var SCRYPT_KEY_LEN = 64;
|
|
135
|
+
function randomCode(length = 16) {
|
|
136
|
+
if (length < 8) {
|
|
137
|
+
throw new Error(`randomCode length must be >= 8 for adequate entropy (got ${length})`);
|
|
138
|
+
}
|
|
139
|
+
let out = "";
|
|
140
|
+
for (let i = 0; i < length; i++) {
|
|
141
|
+
out += CODE_ALPHABET[randomInt(0, CODE_ALPHABET.length)];
|
|
142
|
+
}
|
|
143
|
+
return out;
|
|
144
|
+
}
|
|
145
|
+
function randomToken(bytes = 32) {
|
|
146
|
+
return randomBytes(bytes).toString("base64url");
|
|
147
|
+
}
|
|
148
|
+
async function hashToken(raw) {
|
|
149
|
+
const salt = randomBytes(16);
|
|
150
|
+
const hash = scryptSync(raw, salt, SCRYPT_KEY_LEN);
|
|
151
|
+
return `${salt.toString("hex")}:${hash.toString("hex")}`;
|
|
152
|
+
}
|
|
153
|
+
async function verifyToken(raw, stored) {
|
|
154
|
+
const [saltHex, hashHex] = stored.split(":");
|
|
155
|
+
if (!saltHex || !hashHex) return false;
|
|
156
|
+
const salt = Buffer.from(saltHex, "hex");
|
|
157
|
+
const expected = Buffer.from(hashHex, "hex");
|
|
158
|
+
if (salt.length === 0 || expected.length === 0) return false;
|
|
159
|
+
const candidate = scryptSync(raw, salt, SCRYPT_KEY_LEN);
|
|
160
|
+
return candidate.length === expected.length && timingSafeEqual2(candidate, expected);
|
|
161
|
+
}
|
|
162
|
+
|
|
82
163
|
// src/crypto/index.ts
|
|
83
164
|
var CryptoError = class extends HazoError {
|
|
84
165
|
constructor(message, code) {
|
|
@@ -110,7 +191,7 @@ async function encryptField(plaintext, opts) {
|
|
|
110
191
|
"invalid_key"
|
|
111
192
|
);
|
|
112
193
|
}
|
|
113
|
-
const iv =
|
|
194
|
+
const iv = randomBytes2(IV_LEN);
|
|
114
195
|
const cipher = createCipheriv(ALG, key, iv, { authTagLength: TAG_LEN });
|
|
115
196
|
if (opts.aad) cipher.setAAD(Buffer.from(opts.aad, "utf8"));
|
|
116
197
|
const ct = Buffer.concat([cipher.update(plaintext, "utf8"), cipher.final()]);
|
|
@@ -267,5 +348,11 @@ export {
|
|
|
267
348
|
StaticKeyProvider,
|
|
268
349
|
aadFor,
|
|
269
350
|
decryptField,
|
|
270
|
-
encryptField
|
|
351
|
+
encryptField,
|
|
352
|
+
hashToken,
|
|
353
|
+
randomCode,
|
|
354
|
+
randomToken,
|
|
355
|
+
signHmac,
|
|
356
|
+
verifyHmac,
|
|
357
|
+
verifyToken
|
|
271
358
|
};
|
package/dist/mask/index.d.ts
CHANGED
|
@@ -34,6 +34,32 @@ declare function drop(_value: unknown, _col: string, _maskKey: string): unknown;
|
|
|
34
34
|
* nullify — replace with null (less aggressive than drop; preserves column semantics).
|
|
35
35
|
*/
|
|
36
36
|
declare function nullify(_value: unknown, _col: string, _maskKey: string): unknown;
|
|
37
|
+
/**
|
|
38
|
+
* maskTFN — mask an Australian Tax File Number for display, revealing only
|
|
39
|
+
* the last 3 digits.
|
|
40
|
+
*
|
|
41
|
+
* TFNs are commonly rendered/entered as `123 456 789` or `123456789`;
|
|
42
|
+
* whitespace is stripped before masking so both forms produce the same
|
|
43
|
+
* output. Returns `"***"` for inputs too short to safely reveal 3 digits,
|
|
44
|
+
* and `""` for null/undefined/empty input.
|
|
45
|
+
*
|
|
46
|
+
* @param tfn - raw or space-formatted TFN, or null/undefined
|
|
47
|
+
* @returns a `"***-***-789"`-shaped string, `"***"`, or `""`
|
|
48
|
+
*/
|
|
49
|
+
declare function maskTFN(tfn: string | null | undefined): string;
|
|
50
|
+
/**
|
|
51
|
+
* maskABN — mask an Australian Business Number for display, revealing only
|
|
52
|
+
* the last 3 digits.
|
|
53
|
+
*
|
|
54
|
+
* ABNs are commonly rendered/entered as `12 345 678 901` or `12345678901`;
|
|
55
|
+
* whitespace is stripped before masking so both forms produce the same
|
|
56
|
+
* output. Returns `"***"` for inputs too short to safely reveal 3 digits,
|
|
57
|
+
* and `""` for null/undefined/empty input.
|
|
58
|
+
*
|
|
59
|
+
* @param abn - raw or space-formatted ABN, or null/undefined
|
|
60
|
+
* @returns a `"**-***-***-901"`-shaped string, `"***"`, or `""`
|
|
61
|
+
*/
|
|
62
|
+
declare function maskABN(abn: string | null | undefined): string;
|
|
37
63
|
/**
|
|
38
64
|
* redact_pii — NER-based PII redaction (wink-nlp lite model).
|
|
39
65
|
* Detects named entities (dates, cardinals, etc.) and replaces them with [REDACTED_TYPE].
|
|
@@ -45,4 +71,4 @@ declare function redact_pii(value: unknown, _col: string, _maskKey: string): unk
|
|
|
45
71
|
declare const BUILTIN_TRANSFORMS: Record<string, (value: unknown, col: string, maskKey: string) => unknown>;
|
|
46
72
|
type MaskTransformFn = (value: unknown, col: string, maskKey: string) => unknown;
|
|
47
73
|
|
|
48
|
-
export { BUILTIN_TRANSFORMS, type MaskTransformFn, drop, fake_name, hash, jitter_date, mask_email, mask_phone, nullify, redact_pii, tokenize };
|
|
74
|
+
export { BUILTIN_TRANSFORMS, type MaskTransformFn, drop, fake_name, hash, jitter_date, maskABN, maskTFN, mask_email, mask_phone, nullify, redact_pii, tokenize };
|
package/dist/mask/index.js
CHANGED
|
@@ -58,6 +58,18 @@ function drop(_value, _col, _maskKey) {
|
|
|
58
58
|
function nullify(_value, _col, _maskKey) {
|
|
59
59
|
return null;
|
|
60
60
|
}
|
|
61
|
+
function maskTFN(tfn) {
|
|
62
|
+
if (!tfn) return "";
|
|
63
|
+
const cleaned = tfn.replace(/\s/g, "");
|
|
64
|
+
if (cleaned.length < 3) return "***";
|
|
65
|
+
return `***-***-${cleaned.slice(-3)}`;
|
|
66
|
+
}
|
|
67
|
+
function maskABN(abn) {
|
|
68
|
+
if (!abn) return "";
|
|
69
|
+
const cleaned = abn.replace(/\s/g, "");
|
|
70
|
+
if (cleaned.length < 3) return "***";
|
|
71
|
+
return `**-***-***-${cleaned.slice(-3)}`;
|
|
72
|
+
}
|
|
61
73
|
var _esmReq = createRequire(import.meta.url);
|
|
62
74
|
var _nlpInstance = null;
|
|
63
75
|
var _nlpIts = null;
|
|
@@ -107,6 +119,8 @@ export {
|
|
|
107
119
|
fake_name,
|
|
108
120
|
hash,
|
|
109
121
|
jitter_date,
|
|
122
|
+
maskABN,
|
|
123
|
+
maskTFN,
|
|
110
124
|
mask_email,
|
|
111
125
|
mask_phone,
|
|
112
126
|
nullify,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "hazo_secure",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.5.0",
|
|
4
4
|
"description": "Security & compliance primitives — SSRF-safe fetch, rate limiting, field-level encryption, GDPR orchestration, CSRF. Five subpath modules, pick the ones you need.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -76,12 +76,12 @@
|
|
|
76
76
|
"wink-eng-lite-web-model": "^1.7.0"
|
|
77
77
|
},
|
|
78
78
|
"peerDependencies": {
|
|
79
|
-
"hazo_core": "^1.1
|
|
80
|
-
"hazo_logs": "^2.
|
|
81
|
-
"hazo_connect": "^3.
|
|
82
|
-
"hazo_jobs": "^0.
|
|
83
|
-
"hazo_files": "^3.1.
|
|
84
|
-
"hazo_ui": "^
|
|
79
|
+
"hazo_core": "^1.2.1",
|
|
80
|
+
"hazo_logs": "^2.1.1",
|
|
81
|
+
"hazo_connect": "^3.9.2",
|
|
82
|
+
"hazo_jobs": "^0.15.0",
|
|
83
|
+
"hazo_files": "^3.1.1",
|
|
84
|
+
"hazo_ui": "^6.1.0"
|
|
85
85
|
},
|
|
86
86
|
"peerDependenciesMeta": {
|
|
87
87
|
"hazo_logs": {
|
|
@@ -103,19 +103,19 @@
|
|
|
103
103
|
"devDependencies": {
|
|
104
104
|
"@types/jest": "^30.0.0",
|
|
105
105
|
"@types/node": "^22.10.0",
|
|
106
|
-
"hazo_core": "^1.1
|
|
107
|
-
"hazo_logs": "^2.
|
|
108
|
-
"hazo_connect": "^3.
|
|
109
|
-
"hazo_jobs": "^0.
|
|
110
|
-
"hazo_files": "^3.1.
|
|
111
|
-
"hazo_ui": "^
|
|
106
|
+
"hazo_core": "^1.2.1",
|
|
107
|
+
"hazo_logs": "^2.1.1",
|
|
108
|
+
"hazo_connect": "^3.9.2",
|
|
109
|
+
"hazo_jobs": "^0.15.0",
|
|
110
|
+
"hazo_files": "^3.1.1",
|
|
111
|
+
"hazo_ui": "^6.1.0",
|
|
112
112
|
"jest": "^30.2.0",
|
|
113
113
|
"ts-jest": "^29.4.5",
|
|
114
114
|
"tsup": "^8.5.1",
|
|
115
115
|
"typescript": "^5.7.2",
|
|
116
116
|
"wink-nlp": "^2.3.1",
|
|
117
117
|
"wink-eng-lite-web-model": "^1.7.0",
|
|
118
|
-
"zod": "^
|
|
118
|
+
"zod": "^4.1.12"
|
|
119
119
|
},
|
|
120
120
|
"author": "Pubs Abayasiri",
|
|
121
121
|
"license": "MIT"
|