@yuneta/gobj-js 7.26.19 → 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.
@@ -3437,6 +3437,11 @@ var gobjJs = (function(exports) {
3437
3437
  "sessionkey",
3438
3438
  "authdata"
3439
3439
  ];
3440
+ var SECRET_NAME_SEGMENTS = /* @__PURE__ */ new Set([
3441
+ "pass",
3442
+ "pin",
3443
+ "otp"
3444
+ ]);
3440
3445
  var NOT_SECRET_SEGMENTS = /* @__PURE__ */ new Set([
3441
3446
  "endpoint",
3442
3447
  "url",
@@ -3469,10 +3474,16 @@ var gobjJs = (function(exports) {
3469
3474
  if (typeof name !== "string" || name.length < 3) return false;
3470
3475
  let lower = name.toLowerCase();
3471
3476
  let hit = false;
3472
- for (const part of SECRET_NAME_PARTS) if (lower.indexOf(part) >= 0) {
3477
+ for (const segment of lower.split(/[^a-z0-9]+/)) if (SECRET_NAME_SEGMENTS.has(segment)) {
3473
3478
  hit = true;
3474
3479
  break;
3475
3480
  }
3481
+ if (!hit) {
3482
+ for (const part of SECRET_NAME_PARTS) if (lower.indexOf(part) >= 0) {
3483
+ hit = true;
3484
+ break;
3485
+ }
3486
+ }
3476
3487
  if (!hit) {
3477
3488
  let joined = lower.replace(/[_\-. \t]/g, "");
3478
3489
  for (const part of SECRET_NAME_JOINED) if (joined.indexOf(part) >= 0) {
@@ -3510,32 +3521,250 @@ var gobjJs = (function(exports) {
3510
3521
  }
3511
3522
  }
3512
3523
  /************************************************************
3513
- * A text (a command line) with the value of every "name=value"
3514
- * whose name is a secret's written as "********", quoted or not
3515
- * (and the "value" of a write-attr whose attribute names a
3516
- * secret). The rest as it is. Return null when there was nothing
3517
- * to mask. As the C kernel's mask_secrets_inline().
3524
+ * A credential by its SHAPE, whatever names it -- the C kernel's
3525
+ * jwt_len() / scheme_credential(), the shapes the agent's audit
3526
+ * record redacts, and the schemes of an HTTP Authorization:
3527
+ * - a JWT or a JWE: "eyJ" (the base64url of '{"') at the start
3528
+ * of a word, base64url, and a '.' after it -- three parts
3529
+ * joined by '.' (a JWS), five (a JWE), or fewer when a cap cut
3530
+ * it; the dots at the end of the run are not its own (a JWT
3531
+ * ends a sentence: "... eyJ.eyJ.sig.");
3532
+ * - the credential after the scheme word "Bearer" or "Basic"
3533
+ * (any case, a word of its own): scheme_credential().
3518
3534
  ************************************************************/
3535
+ var MASK_TOKEN_MIN = 8;
3536
+ var MASK_PROSE_MAX = 24;
3537
+ function is_ascii_alnum_code(code) {
3538
+ return code >= 48 && code <= 57 || code >= 65 && code <= 90 || code >= 97 && code <= 122;
3539
+ }
3540
+ function is_ascii_letter_code(code) {
3541
+ return code >= 65 && code <= 90 || code >= 97 && code <= 122;
3542
+ }
3543
+ function is_ascii_upper_code(code) {
3544
+ return code >= 65 && code <= 90;
3545
+ }
3546
+ function is_base64url_code(code) {
3547
+ return is_ascii_alnum_code(code) || code === 45 || code === 95;
3548
+ }
3549
+ function ascii_case_equal(str, p, word) {
3550
+ if (str.length - p < word.length) return false;
3551
+ for (let i = 0; i < word.length; i++) {
3552
+ let code = str.charCodeAt(p + i);
3553
+ if (code >= 65 && code <= 90) code += 32;
3554
+ if (code !== word.charCodeAt(i)) return false;
3555
+ }
3556
+ return true;
3557
+ }
3558
+ function jwt_len(str, p) {
3559
+ if (str.length - p < 3 || str[p] !== "e" || str[p + 1] !== "y" || str[p + 2] !== "J") return 0;
3560
+ if (p > 0 && (is_base64url_code(str.charCodeAt(p - 1)) || str[p - 1] === ".")) return 0;
3561
+ let e = p;
3562
+ let dotted = false;
3563
+ while (e < str.length && (is_base64url_code(str.charCodeAt(e)) || str[e] === ".")) {
3564
+ if (str[e] === ".") dotted = true;
3565
+ e++;
3566
+ }
3567
+ if (!dotted) return 0;
3568
+ while (str[e - 1] === ".") e--;
3569
+ return e - p;
3570
+ }
3571
+ function scheme_word_len(str, p) {
3572
+ if (p > 0 && is_ascii_alnum_code(str.charCodeAt(p - 1))) return 0;
3573
+ for (const scheme of ["bearer", "basic"]) {
3574
+ const n = scheme.length;
3575
+ if (str.length - p > n && ascii_case_equal(str, p, scheme) && (str[p + n] === " " || str[p + n] === " ")) return n;
3576
+ }
3577
+ return 0;
3578
+ }
3579
+ function code_points(str, w, n) {
3580
+ let count = 0;
3581
+ for (let i = w; i < w + n; i++) {
3582
+ const code = str.charCodeAt(i);
3583
+ if (code < 56320 || code > 57343) count++;
3584
+ }
3585
+ return count;
3586
+ }
3587
+ function is_prose_word(str, w, n) {
3588
+ if (n === 0 || n >= MASK_PROSE_MAX) return false;
3589
+ let i = w;
3590
+ const end = w + n;
3591
+ while (true) {
3592
+ let r = i;
3593
+ let upper_rest = true;
3594
+ let lower_rest = true;
3595
+ while (r < end && is_ascii_letter_code(str.charCodeAt(r))) {
3596
+ if (r > i) {
3597
+ if (is_ascii_upper_code(str.charCodeAt(r))) lower_rest = false;
3598
+ else upper_rest = false;
3599
+ }
3600
+ r++;
3601
+ }
3602
+ if (r === i) return false;
3603
+ if (!lower_rest && !(upper_rest && is_ascii_upper_code(str.charCodeAt(i)))) return false;
3604
+ if (r === end) return true;
3605
+ if (str[r] !== "-" && str[r] !== "." && str[r] !== "/" || r + 1 === end) return false;
3606
+ i = r + 1;
3607
+ }
3608
+ }
3609
+ function base64_digit(code) {
3610
+ if (code >= 65 && code <= 90) return code - 65;
3611
+ if (code >= 97 && code <= 122) return code - 97 + 26;
3612
+ if (code >= 48 && code <= 57) return code - 48 + 52;
3613
+ if (code === 43) return 62;
3614
+ if (code === 47) return 63;
3615
+ return -1;
3616
+ }
3617
+ function is_basic_credential(str, w, n) {
3618
+ let bits = 0;
3619
+ let n_bits = 0;
3620
+ for (let i = 0; i < n; i++) {
3621
+ const v = base64_digit(str.charCodeAt(w + i));
3622
+ if (v < 0) return false;
3623
+ bits = (bits << 6 | v) & 16383;
3624
+ n_bits += 6;
3625
+ if (n_bits >= 8) {
3626
+ n_bits -= 8;
3627
+ if ((bits >> n_bits & 255) === 58) return true;
3628
+ }
3629
+ }
3630
+ return false;
3631
+ }
3632
+ var SCHEME_WORD_STOPS = " \r\n\"',;}]\0";
3633
+ function scheme_credential(str, p) {
3634
+ const n = scheme_word_len(str, p);
3635
+ if (!n) return [0, 0];
3636
+ const scheme = n === 5 ? "basic" : "bearer";
3637
+ let context = false;
3638
+ let t = p + n;
3639
+ while (t < str.length && (str[t] === " " || str[t] === " ")) t++;
3640
+ if (t < str.length && scheme_word_len(str, t) === n && ascii_case_equal(str, t, scheme)) {
3641
+ t += n;
3642
+ context = true;
3643
+ while (t < str.length && (str[t] === " " || str[t] === " ")) t++;
3644
+ }
3645
+ if (t >= str.length) return [0, 0];
3646
+ if (str[t] === "\"" || str[t] === "'") {
3647
+ let q = t + 1;
3648
+ while (q < str.length && str[q] !== str[t] && str[q] !== " " && str[q] !== " " && str[q] !== "\r" && str[q] !== "\n" && str[q] !== "\0") q++;
3649
+ if (q < str.length && str[q] === str[t] && q > t + 1) return [t - p, q + 1 - t];
3650
+ return [0, 0];
3651
+ }
3652
+ let e = t;
3653
+ while (e < str.length && SCHEME_WORD_STOPS.indexOf(str[e]) < 0) e++;
3654
+ if (e === t) return [0, 0];
3655
+ if (!context) {
3656
+ let w_end = e;
3657
+ while (w_end > t && str[w_end - 1] === ".") w_end--;
3658
+ const len = w_end - t;
3659
+ if (len === 0 || is_prose_word(str, t, len)) return [0, 0];
3660
+ if (n === 5) {
3661
+ if (!is_basic_credential(str, t, len)) return [0, 0];
3662
+ } else if (code_points(str, t, len) < MASK_TOKEN_MIN) return [0, 0];
3663
+ }
3664
+ return [t - p, e - t];
3665
+ }
3666
+ function shape_len(str, p) {
3667
+ const c = str[p];
3668
+ if (c === "e") return [0, jwt_len(str, p)];
3669
+ if (c === "b" || c === "B") return scheme_credential(str, p);
3670
+ return [0, 0];
3671
+ }
3672
+ function shape_len_7_26_9(str, p) {
3673
+ const c = str[p];
3674
+ if (c === "e") {
3675
+ if (str.length - p < 3 || str[p + 1] !== "y" || str[p + 2] !== "J") return [0, 0];
3676
+ if (p > 0 && (is_base64url_code(str.charCodeAt(p - 1)) || str[p - 1] === ".")) return [0, 0];
3677
+ let e = p;
3678
+ let dots = 0;
3679
+ while (e < str.length && (is_base64url_code(str.charCodeAt(e)) || str[e] === ".")) {
3680
+ if (str[e] === ".") dots++;
3681
+ e++;
3682
+ }
3683
+ while (str[e - 1] === ".") {
3684
+ e--;
3685
+ dots--;
3686
+ }
3687
+ return dots === 2 ? [0, e - p] : [0, 0];
3688
+ }
3689
+ if (c === "b" || c === "B") {
3690
+ if (str.length - p <= 6 || !ascii_case_equal(str, p, "bearer")) return [0, 0];
3691
+ if (p > 0 && is_ascii_alnum_code(str.charCodeAt(p - 1))) return [0, 0];
3692
+ let t = p + 6;
3693
+ if (str[t] !== " " && str[t] !== " ") return [0, 0];
3694
+ while (t < str.length && (str[t] === " " || str[t] === " ")) t++;
3695
+ let e = t;
3696
+ while (e < str.length && " \r\n'\",;}]\0".indexOf(str[e]) < 0) e++;
3697
+ return [t - p, e - t];
3698
+ }
3699
+ return [0, 0];
3700
+ }
3701
+ var COLON_VALUE_STOPS = " \r\n,;&)]}<>\"'\0";
3702
+ function colon_value_end(str, v) {
3703
+ if (v >= str.length) return v;
3704
+ const c = str[v];
3705
+ if (c === "\"" || c === "'") {
3706
+ let e = v + 1;
3707
+ while (e < str.length && str[e] !== c) {
3708
+ if (str[e] === "\\" && e + 1 < str.length) e++;
3709
+ e++;
3710
+ }
3711
+ return e < str.length ? e + 1 : str.length;
3712
+ }
3713
+ if (c === "{" || c === "[") {
3714
+ let depth = 0;
3715
+ let in_string = false;
3716
+ for (let e = v; e < str.length; e++) if (in_string) {
3717
+ if (str[e] === "\\" && e + 1 < str.length) e++;
3718
+ else if (str[e] === "\"") in_string = false;
3719
+ } else if (str[e] === "\"") in_string = true;
3720
+ else if (str[e] === "{" || str[e] === "[") depth++;
3721
+ else if (str[e] === "}" || str[e] === "]") {
3722
+ depth--;
3723
+ if (depth === 0) return e + 1;
3724
+ }
3725
+ return str.length;
3726
+ }
3727
+ if (c === "\\") {
3728
+ let q = v;
3729
+ while (q < str.length && str[q] === "\\") q++;
3730
+ if (q < str.length && (str[q] === "\"" || str[q] === "'")) {
3731
+ const level = q - v;
3732
+ let run = 0;
3733
+ for (let e = q + 1; e < str.length; e++) {
3734
+ if (str[e] === "\\") {
3735
+ run++;
3736
+ continue;
3737
+ }
3738
+ if (str[e] === str[q] && run === level) return e + 1;
3739
+ run = 0;
3740
+ }
3741
+ return str.length;
3742
+ }
3743
+ }
3744
+ let e = v;
3745
+ const n = scheme_word_len(str, v);
3746
+ if (n) {
3747
+ e = v + n;
3748
+ while (e < str.length && (str[e] === " " || str[e] === " ")) e++;
3749
+ if (e < str.length && (str[e] === "\"" || str[e] === "'")) return colon_value_end(str, e);
3750
+ }
3751
+ while (e < str.length && COLON_VALUE_STOPS.indexOf(str[e]) < 0) e++;
3752
+ return e;
3753
+ }
3519
3754
  var MASK_MAX_NAME = 128;
3520
3755
  var MASK_MAX_BYTES = 4194304;
3521
3756
  var MASK_TOO_LARGE = "<not shown: too large to mask>";
3522
- function mask_secrets_inline(str) {
3523
- if (typeof str !== "string" || str.indexOf("=") < 0) return null;
3524
- if (str.length > MASK_MAX_BYTES) return MASK_TOO_LARGE;
3525
- let value_is_secret = false;
3526
- let re_attr = /(^|[ \t])attribute=["']?([^ \t"']*)/g;
3527
- let m;
3528
- while ((m = re_attr.exec(str)) !== null) if (is_secret_name(m[2].slice(-128))) value_is_secret = true;
3529
- let parts = [];
3530
- let copied = 0;
3531
- let changed = false;
3757
+ function mark_range(marks, from, to) {
3758
+ for (let i = from; i < to; i++) marks[i] = 1;
3759
+ }
3760
+ function mark_params(str, value_is_secret, as_7_26_9, marks) {
3761
+ const is_blank_or_end = (i) => i >= str.length || str[i] === " " || str[i] === " " || str[i] === "\0";
3532
3762
  let outer = "";
3533
3763
  let word = 0;
3534
3764
  let p = 0;
3535
- const is_blank_or_end = (i) => i >= str.length || str[i] === " " || str[i] === " ";
3536
3765
  while (p < str.length) {
3537
- let c = str[p];
3538
- if (c === " " || c === " ") {
3766
+ const c = str[p];
3767
+ if (c === " " || c === " " || c === "\0") {
3539
3768
  p++;
3540
3769
  word = p;
3541
3770
  continue;
@@ -3544,43 +3773,124 @@ var gobjJs = (function(exports) {
3544
3773
  if (!outer && (p === 0 || str[p - 1] === " " || str[p - 1] === " " || str[p - 1] === "=")) outer = c;
3545
3774
  else if (c === outer && is_blank_or_end(p + 1)) outer = "";
3546
3775
  }
3776
+ if (as_7_26_9) {
3777
+ const [offset, n] = shape_len_7_26_9(str, p);
3778
+ if (n) {
3779
+ p += offset + n;
3780
+ word = p;
3781
+ continue;
3782
+ }
3783
+ }
3547
3784
  if (c !== "=") {
3548
3785
  p++;
3549
3786
  continue;
3550
3787
  }
3551
- let name = str.substring(Math.max(word, p - MASK_MAX_NAME), p);
3788
+ const name_from = Math.max(word, p - MASK_MAX_NAME);
3789
+ const name = str.substring(name_from, p);
3552
3790
  word = p + 1;
3553
- if (!(is_secret_name(name) || value_is_secret && name.toLowerCase() === "value")) {
3791
+ if (!(is_secret_name(name) || value_is_secret && name.length === 5 && ascii_case_equal(str, name_from, "value"))) {
3554
3792
  p++;
3555
3793
  continue;
3556
3794
  }
3557
3795
  p++;
3558
- let quote = str[p] === "\"" || str[p] === "'" ? str[p] : "";
3559
3796
  let end;
3797
+ const quote = p < str.length && (str[p] === "\"" || str[p] === "'") ? str[p] : "";
3560
3798
  if (quote) {
3561
3799
  end = p + 1;
3562
- while (end < str.length && str[end] !== quote) end++;
3563
- if (str[end] === quote) end++;
3800
+ while (end < str.length && str[end] !== quote && str[end] !== "\0") end++;
3801
+ if (end < str.length && str[end] === quote) end++;
3564
3802
  } else end = inline_secret_value_end(str, p, outer);
3565
- if (end > p) {
3566
- parts.push(str.substring(copied, p));
3803
+ mark_range(marks, p, end);
3804
+ p = end;
3805
+ word = p;
3806
+ }
3807
+ }
3808
+ function mark_shapes(str, marks) {
3809
+ for (let p = 0; p < str.length; p++) {
3810
+ const c = str[p];
3811
+ if (c !== "e" && c !== "b" && c !== "B") continue;
3812
+ const [offset, n] = shape_len(str, p);
3813
+ if (n) mark_range(marks, p + offset, p + offset + n);
3814
+ }
3815
+ }
3816
+ function mark_labels(str, marks) {
3817
+ let word = 0;
3818
+ let p = 0;
3819
+ while (p < str.length) {
3820
+ const c = str[p];
3821
+ if (c === " " || c === " " || c === "\0" || c === "=") {
3822
+ p++;
3823
+ word = p;
3824
+ continue;
3825
+ }
3826
+ if (c !== ":") {
3827
+ p++;
3828
+ continue;
3829
+ }
3830
+ if (!is_secret_name(str.substring(Math.max(word, p - MASK_MAX_NAME), p))) {
3831
+ p++;
3832
+ word = p;
3833
+ continue;
3834
+ }
3835
+ let v = p + 1;
3836
+ while (v < str.length && (str[v] === " " || str[v] === " ")) v++;
3837
+ const e = colon_value_end(str, v);
3838
+ mark_range(marks, v, e);
3839
+ const n_scheme = scheme_word_len(str, v);
3840
+ if (n_scheme) p = v + n_scheme;
3841
+ else p = e > v ? e : p + 1;
3842
+ word = p;
3843
+ }
3844
+ }
3845
+ /************************************************************
3846
+ * A text (a command line) with the secrets that can be told
3847
+ * written as "********" (each run of them as one), the rest as it
3848
+ * is: the value of every "name=value" whose name is a secret's,
3849
+ * quoted or not (and the "value" of a write-attr whose attribute
3850
+ * names a secret); the same for a "name: value", its name in quotes
3851
+ * or not (a json, a header, a label: "password": x, Authorization:
3852
+ * Basic x, bearer: tok); and a JWT or the credential after "Bearer "
3853
+ * or "Basic ", wherever they are, whatever names them. Each rule
3854
+ * judges the text as it came. Return null when there was nothing to
3855
+ * mask. As the C kernel's mask_secrets_inline().
3856
+ ************************************************************/
3857
+ function mask_secrets_inline(str) {
3858
+ if (typeof str !== "string") return null;
3859
+ if (str.indexOf("=") < 0 && str.indexOf(":") < 0 && str.indexOf("eyJ") < 0 && !/bearer|basic/i.test(str)) return null;
3860
+ if (str.length > MASK_MAX_BYTES) return MASK_TOO_LARGE;
3861
+ let value_is_secret = false;
3862
+ let re_attr = /(^|[ \t])attribute=["']?([^ \t"'\u0000]*)/g;
3863
+ let m;
3864
+ while ((m = re_attr.exec(str)) !== null) if (is_secret_name(m[2].slice(-128))) value_is_secret = true;
3865
+ const marks = new Uint8Array(str.length);
3866
+ mark_params(str, value_is_secret, true, marks);
3867
+ mark_params(str, value_is_secret, false, marks);
3868
+ mark_shapes(str, marks);
3869
+ mark_labels(str, marks);
3870
+ let parts = [];
3871
+ let changed = false;
3872
+ let i = 0;
3873
+ while (i < str.length) {
3874
+ let j = i;
3875
+ if (marks[i]) {
3876
+ while (j < str.length && marks[j]) j++;
3567
3877
  parts.push("********");
3568
- copied = end;
3569
3878
  changed = true;
3879
+ } else {
3880
+ while (j < str.length && !marks[j]) j++;
3881
+ parts.push(str.substring(i, j));
3570
3882
  }
3571
- p = end;
3572
- word = p;
3883
+ i = j;
3573
3884
  }
3574
- if (!changed) return null;
3575
- parts.push(str.substring(copied));
3576
- return parts.join("");
3885
+ return changed ? parts.join("") : null;
3577
3886
  }
3578
3887
  /************************************************************
3579
3888
  * A json as a log or a trace may show it: at any depth, the
3580
3889
  * value of a key with a secret's name is "********", whatever
3581
3890
  * its type (not an absent one, a null or an empty string); so is
3582
3891
  * the "value" of a dict whose "attribute" names a secret; and a
3583
- * string is masked as mask_secrets_inline(). Return a masked
3892
+ * string, under any key, is masked as mask_secrets_inline() (a
3893
+ * JWT, a "Bearer" token, a secret name=value). Return a masked
3584
3894
  * copy, or `jn` itself when there was nothing to mask. As the C
3585
3895
  * kernel's json_mask_secrets().
3586
3896
  *
@@ -3609,7 +3919,7 @@ var gobjJs = (function(exports) {
3609
3919
  return MASK_TOO_LARGE;
3610
3920
  }
3611
3921
  budget.left -= jn.length;
3612
- let masked = mask_secrets_inline(jn);
3922
+ let masked = mask_secrets_inline(jn.indexOf("\0") >= 0 ? jn.replace(/\u0000/g, " ") : jn);
3613
3923
  return masked !== null ? masked : jn;
3614
3924
  }
3615
3925
  let is_array = Array.isArray(jn);
@@ -7111,15 +7421,34 @@ var gobjJs = (function(exports) {
7111
7421
  return gobj_save_persistent_attrs(gobj, attr);
7112
7422
  }
7113
7423
  /***************************************************************
7114
- * "set" as the C command reads it: TRUE / set / 1, FALSE / reset / 0
7424
+ * "set" as the C command reads it (trace_set_value() of c_yuno.c):
7425
+ * a boolean; an integer in the range of an int (true unless 0); or
7426
+ * text -- set / reset, a JSON integer -?(0|[1-9][0-9]*), or true /
7427
+ * false, yes / no, on / off, any case. null for anything else: a
7428
+ * real (2.5), " 1", "0x1", "1e3", "+5", "007" and "2.5" are refused,
7429
+ * as in C. Up to gobj-js 7.26.19 the text went through Number(),
7430
+ * which took all of them, and "yes" / "on" were refused.
7115
7431
  ***************************************************************/
7432
+ var INT_MIN = -2147483648;
7433
+ var INT_MAX = 2147483647;
7116
7434
  function parse_set(value) {
7117
7435
  if (value === true || value === false) return value;
7118
- let v = String(value === void 0 || value === null ? "" : value).toLowerCase();
7119
- if (v === "true" || v === "set") return true;
7120
- if (v === "false" || v === "reset") return false;
7121
- if (v === "" || isNaN(Number(v))) return null;
7122
- return Number(v) ? true : false;
7436
+ if (typeof value === "number") {
7437
+ if (!Number.isInteger(value) || value < INT_MIN || value > INT_MAX) return null;
7438
+ return value !== 0;
7439
+ }
7440
+ if (typeof value !== "string" || value === "") return null;
7441
+ let v = value.toLowerCase();
7442
+ if (v === "set") return true;
7443
+ if (v === "reset") return false;
7444
+ if (/^-?(0|[1-9][0-9]*)$/.test(value)) {
7445
+ let n = Number(value);
7446
+ if (n < INT_MIN || n > INT_MAX) return null;
7447
+ return n !== 0;
7448
+ }
7449
+ if (v === "true" || v === "yes" || v === "on") return true;
7450
+ if (v === "false" || v === "no" || v === "off") return false;
7451
+ return null;
7123
7452
  }
7124
7453
  function yuno_prefix() {
7125
7454
  return `${gobj_yuno_role()}^${gobj_yuno_name()}`;