@yuneta/gobj-js 7.26.19 → 7.26.20

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,17 +3521,63 @@ var gobjJs = (function(exports) {
3510
3521
  }
3511
3522
  }
3512
3523
  /************************************************************
3524
+ * A credential by its SHAPE, whatever names it -- the C kernel's
3525
+ * jwt_len() / bearer_token_len(), the shapes the agent's audit
3526
+ * record redacts:
3527
+ * - a JWT: "eyJ" (the base64url of '{"') at the start of a
3528
+ * word, and three parts of base64url joined by '.'; the dots
3529
+ * at the end of the run are not its own (a JWT ends a
3530
+ * sentence: "... eyJ.eyJ.sig.");
3531
+ * - the token after "Bearer " (any case, a word of its own).
3532
+ ************************************************************/
3533
+ function is_ascii_alnum_code(code) {
3534
+ return code >= 48 && code <= 57 || code >= 65 && code <= 90 || code >= 97 && code <= 122;
3535
+ }
3536
+ function is_base64url_code(code) {
3537
+ return is_ascii_alnum_code(code) || code === 45 || code === 95;
3538
+ }
3539
+ function jwt_len(str, p) {
3540
+ if (str.length - p < 3 || str[p] !== "e" || str[p + 1] !== "y" || str[p + 2] !== "J") return 0;
3541
+ if (p > 0 && (is_base64url_code(str.charCodeAt(p - 1)) || str[p - 1] === ".")) return 0;
3542
+ let e = p;
3543
+ let dots = 0;
3544
+ while (e < str.length && (is_base64url_code(str.charCodeAt(e)) || str[e] === ".")) {
3545
+ if (str[e] === ".") dots++;
3546
+ e++;
3547
+ }
3548
+ while (str[e - 1] === ".") {
3549
+ e--;
3550
+ dots--;
3551
+ }
3552
+ return dots === 2 ? e - p : 0;
3553
+ }
3554
+ var BEARER_STOPS = " \r\n'\",;}]\0";
3555
+ function bearer_token(str, p) {
3556
+ const word_len = 6;
3557
+ if (str.length - p <= word_len || str.slice(p, p + word_len).toLowerCase() !== "bearer") return [0, 0];
3558
+ if (p > 0 && is_ascii_alnum_code(str.charCodeAt(p - 1))) return [0, 0];
3559
+ let t = p + word_len;
3560
+ if (str[t] !== " " && str[t] !== " ") return [0, 0];
3561
+ while (t < str.length && (str[t] === " " || str[t] === " ")) t++;
3562
+ let e = t;
3563
+ while (e < str.length && BEARER_STOPS.indexOf(str[e]) < 0) e++;
3564
+ return [t - p, e - t];
3565
+ }
3566
+ /************************************************************
3513
3567
  * A text (a command line) with the value of every "name=value"
3514
3568
  * whose name is a secret's written as "********", quoted or not
3515
3569
  * (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().
3570
+ * secret); and a JWT or the token after "Bearer ", wherever they
3571
+ * are, whatever names them. The rest as it is. Return null when
3572
+ * there was nothing to mask. As the C kernel's
3573
+ * mask_secrets_inline().
3518
3574
  ************************************************************/
3519
3575
  var MASK_MAX_NAME = 128;
3520
3576
  var MASK_MAX_BYTES = 4194304;
3521
3577
  var MASK_TOO_LARGE = "<not shown: too large to mask>";
3522
3578
  function mask_secrets_inline(str) {
3523
- if (typeof str !== "string" || str.indexOf("=") < 0) return null;
3579
+ if (typeof str !== "string") return null;
3580
+ if (str.indexOf("=") < 0 && str.indexOf("eyJ") < 0 && !/bearer/i.test(str)) return null;
3524
3581
  if (str.length > MASK_MAX_BYTES) return MASK_TOO_LARGE;
3525
3582
  let value_is_secret = false;
3526
3583
  let re_attr = /(^|[ \t])attribute=["']?([^ \t"']*)/g;
@@ -3544,6 +3601,18 @@ var gobjJs = (function(exports) {
3544
3601
  if (!outer && (p === 0 || str[p - 1] === " " || str[p - 1] === " " || str[p - 1] === "=")) outer = c;
3545
3602
  else if (c === outer && is_blank_or_end(p + 1)) outer = "";
3546
3603
  }
3604
+ let shape = c === "e" ? jwt_len(str, p) : 0;
3605
+ let token_offset = 0;
3606
+ if (c === "b" || c === "B") [token_offset, shape] = bearer_token(str, p);
3607
+ if (shape) {
3608
+ parts.push(str.substring(copied, p + token_offset));
3609
+ parts.push("********");
3610
+ p += token_offset + shape;
3611
+ copied = p;
3612
+ changed = true;
3613
+ word = p;
3614
+ continue;
3615
+ }
3547
3616
  if (c !== "=") {
3548
3617
  p++;
3549
3618
  continue;
@@ -3580,7 +3649,8 @@ var gobjJs = (function(exports) {
3580
3649
  * value of a key with a secret's name is "********", whatever
3581
3650
  * its type (not an absent one, a null or an empty string); so is
3582
3651
  * the "value" of a dict whose "attribute" names a secret; and a
3583
- * string is masked as mask_secrets_inline(). Return a masked
3652
+ * string, under any key, is masked as mask_secrets_inline() (a
3653
+ * JWT, a "Bearer" token, a secret name=value). Return a masked
3584
3654
  * copy, or `jn` itself when there was nothing to mask. As the C
3585
3655
  * kernel's json_mask_secrets().
3586
3656
  *
@@ -3609,7 +3679,7 @@ var gobjJs = (function(exports) {
3609
3679
  return MASK_TOO_LARGE;
3610
3680
  }
3611
3681
  budget.left -= jn.length;
3612
- let masked = mask_secrets_inline(jn);
3682
+ let masked = mask_secrets_inline(jn.indexOf("\0") >= 0 ? jn.replace(/\u0000/g, " ") : jn);
3613
3683
  return masked !== null ? masked : jn;
3614
3684
  }
3615
3685
  let is_array = Array.isArray(jn);
@@ -7111,15 +7181,34 @@ var gobjJs = (function(exports) {
7111
7181
  return gobj_save_persistent_attrs(gobj, attr);
7112
7182
  }
7113
7183
  /***************************************************************
7114
- * "set" as the C command reads it: TRUE / set / 1, FALSE / reset / 0
7184
+ * "set" as the C command reads it (trace_set_value() of c_yuno.c):
7185
+ * a boolean; an integer in the range of an int (true unless 0); or
7186
+ * text -- set / reset, a JSON integer -?(0|[1-9][0-9]*), or true /
7187
+ * false, yes / no, on / off, any case. null for anything else: a
7188
+ * real (2.5), " 1", "0x1", "1e3", "+5", "007" and "2.5" are refused,
7189
+ * as in C. Up to gobj-js 7.26.19 the text went through Number(),
7190
+ * which took all of them, and "yes" / "on" were refused.
7115
7191
  ***************************************************************/
7192
+ var INT_MIN = -2147483648;
7193
+ var INT_MAX = 2147483647;
7116
7194
  function parse_set(value) {
7117
7195
  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;
7196
+ if (typeof value === "number") {
7197
+ if (!Number.isInteger(value) || value < INT_MIN || value > INT_MAX) return null;
7198
+ return value !== 0;
7199
+ }
7200
+ if (typeof value !== "string" || value === "") return null;
7201
+ let v = value.toLowerCase();
7202
+ if (v === "set") return true;
7203
+ if (v === "reset") return false;
7204
+ if (/^-?(0|[1-9][0-9]*)$/.test(value)) {
7205
+ let n = Number(value);
7206
+ if (n < INT_MIN || n > INT_MAX) return null;
7207
+ return n !== 0;
7208
+ }
7209
+ if (v === "true" || v === "yes" || v === "on") return true;
7210
+ if (v === "false" || v === "no" || v === "off") return false;
7211
+ return null;
7123
7212
  }
7124
7213
  function yuno_prefix() {
7125
7214
  return `${gobj_yuno_role()}^${gobj_yuno_name()}`;