@yuneta/gobj-js 7.26.20 → 7.26.21
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 +19 -4
- package/dist/gobj-js.cjs.js +309 -69
- package/dist/gobj-js.cjs.js.map +1 -1
- package/dist/gobj-js.cjs.min.js +944 -756
- package/dist/gobj-js.cjs.min.js.map +1 -1
- package/dist/gobj-js.es.js +309 -69
- package/dist/gobj-js.es.js.map +1 -1
- package/dist/gobj-js.es.min.js +950 -762
- package/dist/gobj-js.es.min.js.map +1 -1
- package/dist/gobj-js.iife.js +309 -69
- package/dist/gobj-js.iife.js.map +1 -1
- package/dist/gobj-js.iife.min.js +1116 -928
- package/dist/gobj-js.iife.min.js.map +1 -1
- package/dist/gobj-js.umd.js +309 -69
- package/dist/gobj-js.umd.js.map +1 -1
- package/dist/gobj-js.umd.min.js +1116 -928
- package/dist/gobj-js.umd.min.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -674,16 +674,31 @@ is_secret_name("mapping") // → false (pin inside a word)
|
|
|
674
674
|
is_secret_name("token_endpoint") // → false (names something ABOUT one)
|
|
675
675
|
mask_secrets_inline("login user=a passw=x") // → "login user=a passw=********"
|
|
676
676
|
mask_secrets_inline("curl -H 'Authorization: Bearer abc' u")
|
|
677
|
-
// → "curl -H 'Authorization:
|
|
677
|
+
// → "curl -H 'Authorization: ********' u"
|
|
678
|
+
mask_secrets_inline("sent Bearer mF_9.B5f-4.1JqM") // → "sent Bearer ********"
|
|
679
|
+
mask_secrets_inline("the bearer of this letter") // → null: prose
|
|
680
|
+
mask_secrets_inline("\"password\": hunter2") // → "\"password\": ********"
|
|
678
681
|
json_mask_secrets({user: "a", password: "x"}) // → {user: "a", password: "********"}
|
|
679
682
|
json_mask_secrets({note: "eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJ4In0.c2ln"})
|
|
680
683
|
// → {note: "********"}: a JWT under any key
|
|
681
684
|
trace_json_masked(kw, "sent") // trace_json() of the masked copy
|
|
682
685
|
```
|
|
683
686
|
|
|
684
|
-
As the C kernel's: the same names, the same
|
|
685
|
-
|
|
686
|
-
|
|
687
|
+
As the C kernel's: the same names, the same rules. By name: the value of a
|
|
688
|
+
`name=value` and of a `name: value` (`"password": x`, `Authorization: Basic x`,
|
|
689
|
+
`bearer: tok`, `{\"password\":\"x\"}` of a json inside a json) whose name is
|
|
690
|
+
a secret's, whole. By value: a JWT or a JWE (`eyJ`, base64url and a `.`: also
|
|
691
|
+
one a cap cut), and after `Bearer` or `Basic` the word that can be a credential
|
|
692
|
+
-- quoted, after the scheme doubled, or not a word of prose (a digit, a symbol,
|
|
693
|
+
a character that is no ASCII, its case mixed, 24 characters or more; for
|
|
694
|
+
`Bearer` 8 at least, for `Basic` a run of base64 that decodes to a
|
|
695
|
+
`user:password`). Each rule judges the text as it came, and a run of
|
|
696
|
+
characters to mask is one `********`: nothing that the masking of 7.26.9 hid is
|
|
697
|
+
shown, but the word after a bare `Bearer` that cannot be a credential. A key
|
|
698
|
+
is judged as a name, never as a value: a key that is itself a credential (a
|
|
699
|
+
dict keyed by tokens, `{"eyJ...": 1}`) is shown as it is. A NUL in a string is
|
|
700
|
+
read as a blank; linear and bounded (a text over 4 MB is not shown at all).
|
|
701
|
+
`key` and `cert` are not secrets' names.
|
|
687
702
|
|
|
688
703
|
### Logging
|
|
689
704
|
|
package/dist/gobj-js.cjs.js
CHANGED
|
@@ -3521,77 +3521,249 @@ function inline_secret_value_end(str, p, outer) {
|
|
|
3521
3521
|
}
|
|
3522
3522
|
/************************************************************
|
|
3523
3523
|
* A credential by its SHAPE, whatever names it -- the C kernel's
|
|
3524
|
-
* jwt_len() /
|
|
3525
|
-
* record redacts:
|
|
3526
|
-
* - a JWT: "eyJ" (the base64url of '{"') at the start
|
|
3527
|
-
* word,
|
|
3528
|
-
*
|
|
3529
|
-
*
|
|
3530
|
-
*
|
|
3531
|
-
|
|
3524
|
+
* jwt_len() / scheme_credential(), the shapes the agent's audit
|
|
3525
|
+
* record redacts, and the schemes of an HTTP Authorization:
|
|
3526
|
+
* - a JWT or a JWE: "eyJ" (the base64url of '{"') at the start
|
|
3527
|
+
* of a word, base64url, and a '.' after it -- three parts
|
|
3528
|
+
* joined by '.' (a JWS), five (a JWE), or fewer when a cap cut
|
|
3529
|
+
* it; the dots at the end of the run are not its own (a JWT
|
|
3530
|
+
* ends a sentence: "... eyJ.eyJ.sig.");
|
|
3531
|
+
* - the credential after the scheme word "Bearer" or "Basic"
|
|
3532
|
+
* (any case, a word of its own): scheme_credential().
|
|
3533
|
+
************************************************************/
|
|
3534
|
+
var MASK_TOKEN_MIN = 8;
|
|
3535
|
+
var MASK_PROSE_MAX = 24;
|
|
3532
3536
|
function is_ascii_alnum_code(code) {
|
|
3533
3537
|
return code >= 48 && code <= 57 || code >= 65 && code <= 90 || code >= 97 && code <= 122;
|
|
3534
3538
|
}
|
|
3539
|
+
function is_ascii_letter_code(code) {
|
|
3540
|
+
return code >= 65 && code <= 90 || code >= 97 && code <= 122;
|
|
3541
|
+
}
|
|
3542
|
+
function is_ascii_upper_code(code) {
|
|
3543
|
+
return code >= 65 && code <= 90;
|
|
3544
|
+
}
|
|
3535
3545
|
function is_base64url_code(code) {
|
|
3536
3546
|
return is_ascii_alnum_code(code) || code === 45 || code === 95;
|
|
3537
3547
|
}
|
|
3548
|
+
function ascii_case_equal(str, p, word) {
|
|
3549
|
+
if (str.length - p < word.length) return false;
|
|
3550
|
+
for (let i = 0; i < word.length; i++) {
|
|
3551
|
+
let code = str.charCodeAt(p + i);
|
|
3552
|
+
if (code >= 65 && code <= 90) code += 32;
|
|
3553
|
+
if (code !== word.charCodeAt(i)) return false;
|
|
3554
|
+
}
|
|
3555
|
+
return true;
|
|
3556
|
+
}
|
|
3538
3557
|
function jwt_len(str, p) {
|
|
3539
3558
|
if (str.length - p < 3 || str[p] !== "e" || str[p + 1] !== "y" || str[p + 2] !== "J") return 0;
|
|
3540
3559
|
if (p > 0 && (is_base64url_code(str.charCodeAt(p - 1)) || str[p - 1] === ".")) return 0;
|
|
3541
3560
|
let e = p;
|
|
3542
|
-
let
|
|
3561
|
+
let dotted = false;
|
|
3543
3562
|
while (e < str.length && (is_base64url_code(str.charCodeAt(e)) || str[e] === ".")) {
|
|
3544
|
-
if (str[e] === ".")
|
|
3563
|
+
if (str[e] === ".") dotted = true;
|
|
3545
3564
|
e++;
|
|
3546
3565
|
}
|
|
3547
|
-
|
|
3548
|
-
|
|
3549
|
-
|
|
3566
|
+
if (!dotted) return 0;
|
|
3567
|
+
while (str[e - 1] === ".") e--;
|
|
3568
|
+
return e - p;
|
|
3569
|
+
}
|
|
3570
|
+
function scheme_word_len(str, p) {
|
|
3571
|
+
if (p > 0 && is_ascii_alnum_code(str.charCodeAt(p - 1))) return 0;
|
|
3572
|
+
for (const scheme of ["bearer", "basic"]) {
|
|
3573
|
+
const n = scheme.length;
|
|
3574
|
+
if (str.length - p > n && ascii_case_equal(str, p, scheme) && (str[p + n] === " " || str[p + n] === " ")) return n;
|
|
3575
|
+
}
|
|
3576
|
+
return 0;
|
|
3577
|
+
}
|
|
3578
|
+
function code_points(str, w, n) {
|
|
3579
|
+
let count = 0;
|
|
3580
|
+
for (let i = w; i < w + n; i++) {
|
|
3581
|
+
const code = str.charCodeAt(i);
|
|
3582
|
+
if (code < 56320 || code > 57343) count++;
|
|
3583
|
+
}
|
|
3584
|
+
return count;
|
|
3585
|
+
}
|
|
3586
|
+
function is_prose_word(str, w, n) {
|
|
3587
|
+
if (n === 0 || n >= MASK_PROSE_MAX) return false;
|
|
3588
|
+
let i = w;
|
|
3589
|
+
const end = w + n;
|
|
3590
|
+
while (true) {
|
|
3591
|
+
let r = i;
|
|
3592
|
+
let upper_rest = true;
|
|
3593
|
+
let lower_rest = true;
|
|
3594
|
+
while (r < end && is_ascii_letter_code(str.charCodeAt(r))) {
|
|
3595
|
+
if (r > i) {
|
|
3596
|
+
if (is_ascii_upper_code(str.charCodeAt(r))) lower_rest = false;
|
|
3597
|
+
else upper_rest = false;
|
|
3598
|
+
}
|
|
3599
|
+
r++;
|
|
3600
|
+
}
|
|
3601
|
+
if (r === i) return false;
|
|
3602
|
+
if (!lower_rest && !(upper_rest && is_ascii_upper_code(str.charCodeAt(i)))) return false;
|
|
3603
|
+
if (r === end) return true;
|
|
3604
|
+
if (str[r] !== "-" && str[r] !== "." && str[r] !== "/" || r + 1 === end) return false;
|
|
3605
|
+
i = r + 1;
|
|
3606
|
+
}
|
|
3607
|
+
}
|
|
3608
|
+
function base64_digit(code) {
|
|
3609
|
+
if (code >= 65 && code <= 90) return code - 65;
|
|
3610
|
+
if (code >= 97 && code <= 122) return code - 97 + 26;
|
|
3611
|
+
if (code >= 48 && code <= 57) return code - 48 + 52;
|
|
3612
|
+
if (code === 43) return 62;
|
|
3613
|
+
if (code === 47) return 63;
|
|
3614
|
+
return -1;
|
|
3615
|
+
}
|
|
3616
|
+
function is_basic_credential(str, w, n) {
|
|
3617
|
+
let bits = 0;
|
|
3618
|
+
let n_bits = 0;
|
|
3619
|
+
for (let i = 0; i < n; i++) {
|
|
3620
|
+
const v = base64_digit(str.charCodeAt(w + i));
|
|
3621
|
+
if (v < 0) return false;
|
|
3622
|
+
bits = (bits << 6 | v) & 16383;
|
|
3623
|
+
n_bits += 6;
|
|
3624
|
+
if (n_bits >= 8) {
|
|
3625
|
+
n_bits -= 8;
|
|
3626
|
+
if ((bits >> n_bits & 255) === 58) return true;
|
|
3627
|
+
}
|
|
3550
3628
|
}
|
|
3551
|
-
return
|
|
3629
|
+
return false;
|
|
3552
3630
|
}
|
|
3553
|
-
var
|
|
3554
|
-
function
|
|
3555
|
-
const
|
|
3556
|
-
if (
|
|
3557
|
-
|
|
3558
|
-
let
|
|
3559
|
-
|
|
3631
|
+
var SCHEME_WORD_STOPS = " \r\n\"',;}]\0";
|
|
3632
|
+
function scheme_credential(str, p) {
|
|
3633
|
+
const n = scheme_word_len(str, p);
|
|
3634
|
+
if (!n) return [0, 0];
|
|
3635
|
+
const scheme = n === 5 ? "basic" : "bearer";
|
|
3636
|
+
let context = false;
|
|
3637
|
+
let t = p + n;
|
|
3560
3638
|
while (t < str.length && (str[t] === " " || str[t] === " ")) t++;
|
|
3639
|
+
if (t < str.length && scheme_word_len(str, t) === n && ascii_case_equal(str, t, scheme)) {
|
|
3640
|
+
t += n;
|
|
3641
|
+
context = true;
|
|
3642
|
+
while (t < str.length && (str[t] === " " || str[t] === " ")) t++;
|
|
3643
|
+
}
|
|
3644
|
+
if (t >= str.length) return [0, 0];
|
|
3645
|
+
if (str[t] === "\"" || str[t] === "'") {
|
|
3646
|
+
let q = t + 1;
|
|
3647
|
+
while (q < str.length && str[q] !== str[t] && str[q] !== " " && str[q] !== " " && str[q] !== "\r" && str[q] !== "\n" && str[q] !== "\0") q++;
|
|
3648
|
+
if (q < str.length && str[q] === str[t] && q > t + 1) return [t - p, q + 1 - t];
|
|
3649
|
+
return [0, 0];
|
|
3650
|
+
}
|
|
3561
3651
|
let e = t;
|
|
3562
|
-
while (e < str.length &&
|
|
3652
|
+
while (e < str.length && SCHEME_WORD_STOPS.indexOf(str[e]) < 0) e++;
|
|
3653
|
+
if (e === t) return [0, 0];
|
|
3654
|
+
if (!context) {
|
|
3655
|
+
let w_end = e;
|
|
3656
|
+
while (w_end > t && str[w_end - 1] === ".") w_end--;
|
|
3657
|
+
const len = w_end - t;
|
|
3658
|
+
if (len === 0 || is_prose_word(str, t, len)) return [0, 0];
|
|
3659
|
+
if (n === 5) {
|
|
3660
|
+
if (!is_basic_credential(str, t, len)) return [0, 0];
|
|
3661
|
+
} else if (code_points(str, t, len) < MASK_TOKEN_MIN) return [0, 0];
|
|
3662
|
+
}
|
|
3563
3663
|
return [t - p, e - t];
|
|
3564
3664
|
}
|
|
3565
|
-
|
|
3566
|
-
|
|
3567
|
-
|
|
3568
|
-
|
|
3569
|
-
|
|
3570
|
-
|
|
3571
|
-
|
|
3572
|
-
|
|
3573
|
-
|
|
3665
|
+
function shape_len(str, p) {
|
|
3666
|
+
const c = str[p];
|
|
3667
|
+
if (c === "e") return [0, jwt_len(str, p)];
|
|
3668
|
+
if (c === "b" || c === "B") return scheme_credential(str, p);
|
|
3669
|
+
return [0, 0];
|
|
3670
|
+
}
|
|
3671
|
+
function shape_len_7_26_9(str, p) {
|
|
3672
|
+
const c = str[p];
|
|
3673
|
+
if (c === "e") {
|
|
3674
|
+
if (str.length - p < 3 || str[p + 1] !== "y" || str[p + 2] !== "J") return [0, 0];
|
|
3675
|
+
if (p > 0 && (is_base64url_code(str.charCodeAt(p - 1)) || str[p - 1] === ".")) return [0, 0];
|
|
3676
|
+
let e = p;
|
|
3677
|
+
let dots = 0;
|
|
3678
|
+
while (e < str.length && (is_base64url_code(str.charCodeAt(e)) || str[e] === ".")) {
|
|
3679
|
+
if (str[e] === ".") dots++;
|
|
3680
|
+
e++;
|
|
3681
|
+
}
|
|
3682
|
+
while (str[e - 1] === ".") {
|
|
3683
|
+
e--;
|
|
3684
|
+
dots--;
|
|
3685
|
+
}
|
|
3686
|
+
return dots === 2 ? [0, e - p] : [0, 0];
|
|
3687
|
+
}
|
|
3688
|
+
if (c === "b" || c === "B") {
|
|
3689
|
+
if (str.length - p <= 6 || !ascii_case_equal(str, p, "bearer")) return [0, 0];
|
|
3690
|
+
if (p > 0 && is_ascii_alnum_code(str.charCodeAt(p - 1))) return [0, 0];
|
|
3691
|
+
let t = p + 6;
|
|
3692
|
+
if (str[t] !== " " && str[t] !== " ") return [0, 0];
|
|
3693
|
+
while (t < str.length && (str[t] === " " || str[t] === " ")) t++;
|
|
3694
|
+
let e = t;
|
|
3695
|
+
while (e < str.length && " \r\n'\",;}]\0".indexOf(str[e]) < 0) e++;
|
|
3696
|
+
return [t - p, e - t];
|
|
3697
|
+
}
|
|
3698
|
+
return [0, 0];
|
|
3699
|
+
}
|
|
3700
|
+
var COLON_VALUE_STOPS = " \r\n,;&)]}<>\"'\0";
|
|
3701
|
+
function colon_value_end(str, v) {
|
|
3702
|
+
if (v >= str.length) return v;
|
|
3703
|
+
const c = str[v];
|
|
3704
|
+
if (c === "\"" || c === "'") {
|
|
3705
|
+
let e = v + 1;
|
|
3706
|
+
while (e < str.length && str[e] !== c) {
|
|
3707
|
+
if (str[e] === "\\" && e + 1 < str.length) e++;
|
|
3708
|
+
e++;
|
|
3709
|
+
}
|
|
3710
|
+
return e < str.length ? e + 1 : str.length;
|
|
3711
|
+
}
|
|
3712
|
+
if (c === "{" || c === "[") {
|
|
3713
|
+
let depth = 0;
|
|
3714
|
+
let in_string = false;
|
|
3715
|
+
for (let e = v; e < str.length; e++) if (in_string) {
|
|
3716
|
+
if (str[e] === "\\" && e + 1 < str.length) e++;
|
|
3717
|
+
else if (str[e] === "\"") in_string = false;
|
|
3718
|
+
} else if (str[e] === "\"") in_string = true;
|
|
3719
|
+
else if (str[e] === "{" || str[e] === "[") depth++;
|
|
3720
|
+
else if (str[e] === "}" || str[e] === "]") {
|
|
3721
|
+
depth--;
|
|
3722
|
+
if (depth === 0) return e + 1;
|
|
3723
|
+
}
|
|
3724
|
+
return str.length;
|
|
3725
|
+
}
|
|
3726
|
+
if (c === "\\") {
|
|
3727
|
+
let q = v;
|
|
3728
|
+
while (q < str.length && str[q] === "\\") q++;
|
|
3729
|
+
if (q < str.length && (str[q] === "\"" || str[q] === "'")) {
|
|
3730
|
+
const level = q - v;
|
|
3731
|
+
let run = 0;
|
|
3732
|
+
for (let e = q + 1; e < str.length; e++) {
|
|
3733
|
+
if (str[e] === "\\") {
|
|
3734
|
+
run++;
|
|
3735
|
+
continue;
|
|
3736
|
+
}
|
|
3737
|
+
if (str[e] === str[q] && run === level) return e + 1;
|
|
3738
|
+
run = 0;
|
|
3739
|
+
}
|
|
3740
|
+
return str.length;
|
|
3741
|
+
}
|
|
3742
|
+
}
|
|
3743
|
+
let e = v;
|
|
3744
|
+
const n = scheme_word_len(str, v);
|
|
3745
|
+
if (n) {
|
|
3746
|
+
e = v + n;
|
|
3747
|
+
while (e < str.length && (str[e] === " " || str[e] === " ")) e++;
|
|
3748
|
+
if (e < str.length && (str[e] === "\"" || str[e] === "'")) return colon_value_end(str, e);
|
|
3749
|
+
}
|
|
3750
|
+
while (e < str.length && COLON_VALUE_STOPS.indexOf(str[e]) < 0) e++;
|
|
3751
|
+
return e;
|
|
3752
|
+
}
|
|
3574
3753
|
var MASK_MAX_NAME = 128;
|
|
3575
3754
|
var MASK_MAX_BYTES = 4194304;
|
|
3576
3755
|
var MASK_TOO_LARGE = "<not shown: too large to mask>";
|
|
3577
|
-
function
|
|
3578
|
-
|
|
3579
|
-
|
|
3580
|
-
|
|
3581
|
-
|
|
3582
|
-
let re_attr = /(^|[ \t])attribute=["']?([^ \t"']*)/g;
|
|
3583
|
-
let m;
|
|
3584
|
-
while ((m = re_attr.exec(str)) !== null) if (is_secret_name(m[2].slice(-128))) value_is_secret = true;
|
|
3585
|
-
let parts = [];
|
|
3586
|
-
let copied = 0;
|
|
3587
|
-
let changed = false;
|
|
3756
|
+
function mark_range(marks, from, to) {
|
|
3757
|
+
for (let i = from; i < to; i++) marks[i] = 1;
|
|
3758
|
+
}
|
|
3759
|
+
function mark_params(str, value_is_secret, as_7_26_9, marks) {
|
|
3760
|
+
const is_blank_or_end = (i) => i >= str.length || str[i] === " " || str[i] === " " || str[i] === "\0";
|
|
3588
3761
|
let outer = "";
|
|
3589
3762
|
let word = 0;
|
|
3590
3763
|
let p = 0;
|
|
3591
|
-
const is_blank_or_end = (i) => i >= str.length || str[i] === " " || str[i] === " ";
|
|
3592
3764
|
while (p < str.length) {
|
|
3593
|
-
|
|
3594
|
-
if (c === " " || c === " ") {
|
|
3765
|
+
const c = str[p];
|
|
3766
|
+
if (c === " " || c === " " || c === "\0") {
|
|
3595
3767
|
p++;
|
|
3596
3768
|
word = p;
|
|
3597
3769
|
continue;
|
|
@@ -3600,48 +3772,116 @@ function mask_secrets_inline(str) {
|
|
|
3600
3772
|
if (!outer && (p === 0 || str[p - 1] === " " || str[p - 1] === " " || str[p - 1] === "=")) outer = c;
|
|
3601
3773
|
else if (c === outer && is_blank_or_end(p + 1)) outer = "";
|
|
3602
3774
|
}
|
|
3603
|
-
|
|
3604
|
-
|
|
3605
|
-
|
|
3606
|
-
|
|
3607
|
-
|
|
3608
|
-
|
|
3609
|
-
|
|
3610
|
-
copied = p;
|
|
3611
|
-
changed = true;
|
|
3612
|
-
word = p;
|
|
3613
|
-
continue;
|
|
3775
|
+
if (as_7_26_9) {
|
|
3776
|
+
const [offset, n] = shape_len_7_26_9(str, p);
|
|
3777
|
+
if (n) {
|
|
3778
|
+
p += offset + n;
|
|
3779
|
+
word = p;
|
|
3780
|
+
continue;
|
|
3781
|
+
}
|
|
3614
3782
|
}
|
|
3615
3783
|
if (c !== "=") {
|
|
3616
3784
|
p++;
|
|
3617
3785
|
continue;
|
|
3618
3786
|
}
|
|
3619
|
-
|
|
3787
|
+
const name_from = Math.max(word, p - MASK_MAX_NAME);
|
|
3788
|
+
const name = str.substring(name_from, p);
|
|
3620
3789
|
word = p + 1;
|
|
3621
|
-
if (!(is_secret_name(name) || value_is_secret && name.
|
|
3790
|
+
if (!(is_secret_name(name) || value_is_secret && name.length === 5 && ascii_case_equal(str, name_from, "value"))) {
|
|
3622
3791
|
p++;
|
|
3623
3792
|
continue;
|
|
3624
3793
|
}
|
|
3625
3794
|
p++;
|
|
3626
|
-
let quote = str[p] === "\"" || str[p] === "'" ? str[p] : "";
|
|
3627
3795
|
let end;
|
|
3796
|
+
const quote = p < str.length && (str[p] === "\"" || str[p] === "'") ? str[p] : "";
|
|
3628
3797
|
if (quote) {
|
|
3629
3798
|
end = p + 1;
|
|
3630
|
-
while (end < str.length && str[end] !== quote) end++;
|
|
3631
|
-
if (str[end] === quote) end++;
|
|
3799
|
+
while (end < str.length && str[end] !== quote && str[end] !== "\0") end++;
|
|
3800
|
+
if (end < str.length && str[end] === quote) end++;
|
|
3632
3801
|
} else end = inline_secret_value_end(str, p, outer);
|
|
3633
|
-
|
|
3634
|
-
|
|
3802
|
+
mark_range(marks, p, end);
|
|
3803
|
+
p = end;
|
|
3804
|
+
word = p;
|
|
3805
|
+
}
|
|
3806
|
+
}
|
|
3807
|
+
function mark_shapes(str, marks) {
|
|
3808
|
+
for (let p = 0; p < str.length; p++) {
|
|
3809
|
+
const c = str[p];
|
|
3810
|
+
if (c !== "e" && c !== "b" && c !== "B") continue;
|
|
3811
|
+
const [offset, n] = shape_len(str, p);
|
|
3812
|
+
if (n) mark_range(marks, p + offset, p + offset + n);
|
|
3813
|
+
}
|
|
3814
|
+
}
|
|
3815
|
+
function mark_labels(str, marks) {
|
|
3816
|
+
let word = 0;
|
|
3817
|
+
let p = 0;
|
|
3818
|
+
while (p < str.length) {
|
|
3819
|
+
const c = str[p];
|
|
3820
|
+
if (c === " " || c === " " || c === "\0" || c === "=") {
|
|
3821
|
+
p++;
|
|
3822
|
+
word = p;
|
|
3823
|
+
continue;
|
|
3824
|
+
}
|
|
3825
|
+
if (c !== ":") {
|
|
3826
|
+
p++;
|
|
3827
|
+
continue;
|
|
3828
|
+
}
|
|
3829
|
+
if (!is_secret_name(str.substring(Math.max(word, p - MASK_MAX_NAME), p))) {
|
|
3830
|
+
p++;
|
|
3831
|
+
word = p;
|
|
3832
|
+
continue;
|
|
3833
|
+
}
|
|
3834
|
+
let v = p + 1;
|
|
3835
|
+
while (v < str.length && (str[v] === " " || str[v] === " ")) v++;
|
|
3836
|
+
const e = colon_value_end(str, v);
|
|
3837
|
+
mark_range(marks, v, e);
|
|
3838
|
+
const n_scheme = scheme_word_len(str, v);
|
|
3839
|
+
if (n_scheme) p = v + n_scheme;
|
|
3840
|
+
else p = e > v ? e : p + 1;
|
|
3841
|
+
word = p;
|
|
3842
|
+
}
|
|
3843
|
+
}
|
|
3844
|
+
/************************************************************
|
|
3845
|
+
* A text (a command line) with the secrets that can be told
|
|
3846
|
+
* written as "********" (each run of them as one), the rest as it
|
|
3847
|
+
* is: the value of every "name=value" whose name is a secret's,
|
|
3848
|
+
* quoted or not (and the "value" of a write-attr whose attribute
|
|
3849
|
+
* names a secret); the same for a "name: value", its name in quotes
|
|
3850
|
+
* or not (a json, a header, a label: "password": x, Authorization:
|
|
3851
|
+
* Basic x, bearer: tok); and a JWT or the credential after "Bearer "
|
|
3852
|
+
* or "Basic ", wherever they are, whatever names them. Each rule
|
|
3853
|
+
* judges the text as it came. Return null when there was nothing to
|
|
3854
|
+
* mask. As the C kernel's mask_secrets_inline().
|
|
3855
|
+
************************************************************/
|
|
3856
|
+
function mask_secrets_inline(str) {
|
|
3857
|
+
if (typeof str !== "string") return null;
|
|
3858
|
+
if (str.indexOf("=") < 0 && str.indexOf(":") < 0 && str.indexOf("eyJ") < 0 && !/bearer|basic/i.test(str)) return null;
|
|
3859
|
+
if (str.length > MASK_MAX_BYTES) return MASK_TOO_LARGE;
|
|
3860
|
+
let value_is_secret = false;
|
|
3861
|
+
let re_attr = /(^|[ \t])attribute=["']?([^ \t"'\u0000]*)/g;
|
|
3862
|
+
let m;
|
|
3863
|
+
while ((m = re_attr.exec(str)) !== null) if (is_secret_name(m[2].slice(-128))) value_is_secret = true;
|
|
3864
|
+
const marks = new Uint8Array(str.length);
|
|
3865
|
+
mark_params(str, value_is_secret, true, marks);
|
|
3866
|
+
mark_params(str, value_is_secret, false, marks);
|
|
3867
|
+
mark_shapes(str, marks);
|
|
3868
|
+
mark_labels(str, marks);
|
|
3869
|
+
let parts = [];
|
|
3870
|
+
let changed = false;
|
|
3871
|
+
let i = 0;
|
|
3872
|
+
while (i < str.length) {
|
|
3873
|
+
let j = i;
|
|
3874
|
+
if (marks[i]) {
|
|
3875
|
+
while (j < str.length && marks[j]) j++;
|
|
3635
3876
|
parts.push("********");
|
|
3636
|
-
copied = end;
|
|
3637
3877
|
changed = true;
|
|
3878
|
+
} else {
|
|
3879
|
+
while (j < str.length && !marks[j]) j++;
|
|
3880
|
+
parts.push(str.substring(i, j));
|
|
3638
3881
|
}
|
|
3639
|
-
|
|
3640
|
-
word = p;
|
|
3882
|
+
i = j;
|
|
3641
3883
|
}
|
|
3642
|
-
|
|
3643
|
-
parts.push(str.substring(copied));
|
|
3644
|
-
return parts.join("");
|
|
3884
|
+
return changed ? parts.join("") : null;
|
|
3645
3885
|
}
|
|
3646
3886
|
/************************************************************
|
|
3647
3887
|
* A json as a log or a trace may show it: at any depth, the
|