@yuneta/gobj-js 7.26.24 → 7.26.25

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.
@@ -871,12 +871,48 @@ var gobjJs = (function(exports) {
871
871
  function is_surrogate_pair(high, low) {
872
872
  return high >= 55296 && high <= 56319 && low >= 56320 && low <= 57343;
873
873
  }
874
+ var JSON_MAX_DEPTH = 2048;
874
875
  function json_text_refused_by_c(s) {
875
876
  const n = s.length;
876
877
  let i = 0;
878
+ let depth = 0;
879
+ const in_object = [];
880
+ let key_next = false;
877
881
  while (i < n) {
878
882
  const c = s.charCodeAt(i);
883
+ if (c === 123 || c === 91) {
884
+ depth++;
885
+ if (depth > JSON_MAX_DEPTH) return true;
886
+ in_object.push(c === 123);
887
+ key_next = c === 123;
888
+ i++;
889
+ continue;
890
+ }
891
+ if (c === 125 || c === 93) {
892
+ depth--;
893
+ in_object.pop();
894
+ key_next = false;
895
+ i++;
896
+ continue;
897
+ }
898
+ if (c === 44) {
899
+ key_next = in_object.length > 0 && in_object[in_object.length - 1];
900
+ i++;
901
+ continue;
902
+ }
903
+ if (c === 58) {
904
+ key_next = false;
905
+ i++;
906
+ continue;
907
+ }
908
+ if (c === 116 || c === 102 || c === 110) {
909
+ if (depth + 1 > JSON_MAX_DEPTH) return true;
910
+ i += c === 102 ? 5 : 4;
911
+ continue;
912
+ }
879
913
  if (c === 34) {
914
+ if (!key_next && depth + 1 > JSON_MAX_DEPTH) return true;
915
+ key_next = false;
880
916
  i++;
881
917
  while (i < n) {
882
918
  const d = s.charCodeAt(i);
@@ -909,6 +945,7 @@ var gobjJs = (function(exports) {
909
945
  continue;
910
946
  }
911
947
  if (c === 45 || c >= 48 && c <= 57) {
948
+ if (depth + 1 > JSON_MAX_DEPTH) return true;
912
949
  JSON_NUMBER_TOKEN.lastIndex = i;
913
950
  const m = JSON_NUMBER_TOKEN.exec(s);
914
951
  if (!m) return true;
@@ -947,7 +984,7 @@ var gobjJs = (function(exports) {
947
984
  if (is_array(value)) return "an array";
948
985
  if (is_object(value)) return "an object";
949
986
  if (is_string(value)) return REFUSED_TEXT;
950
- if (typeof value === "number") return Number.isInteger(value) ? "an integer" : "a real";
987
+ if (typeof value === "number") return Number.isInteger(value) && Math.abs(value) <= 0x8000000000000000 ? "an integer" : "a real";
951
988
  if (typeof value === "boolean") return "a boolean";
952
989
  return "null";
953
990
  }
@@ -968,7 +1005,7 @@ var gobjJs = (function(exports) {
968
1005
  value: value ? 1 : 0,
969
1006
  refused: null
970
1007
  };
971
- if (!(value >= -0x8000000000000000 && value < 0x8000000000000000)) return {
1008
+ if (!(value >= -0x8000000000000000 && value <= 0x8000000000000000)) return {
972
1009
  value: void 0,
973
1010
  refused: "a number out of its range"
974
1011
  };
@@ -1129,6 +1166,10 @@ var gobjJs = (function(exports) {
1129
1166
  refused: shape_of_value(value)
1130
1167
  };
1131
1168
  if (DTP_IS_NUMBER(type)) return number_as_type(type, value);
1169
+ if (!is_json_value(value)) return {
1170
+ value: void 0,
1171
+ refused: NO_JSON_TEXT
1172
+ };
1132
1173
  return {
1133
1174
  value,
1134
1175
  refused: null
@@ -1147,8 +1188,34 @@ var gobjJs = (function(exports) {
1147
1188
  data_type_t.DTP_LIST,
1148
1189
  data_type_t.DTP_DICT
1149
1190
  ];
1191
+ var LEAVE_NODE = Symbol("leave");
1192
+ function is_json_value(value) {
1193
+ const on_path = /* @__PURE__ */ new Set();
1194
+ const stack = [value];
1195
+ while (stack.length) {
1196
+ const v = stack.pop();
1197
+ if (v === LEAVE_NODE) {
1198
+ on_path.delete(stack.pop());
1199
+ continue;
1200
+ }
1201
+ if (typeof v === "bigint") return false;
1202
+ if (v === null || typeof v !== "object") continue;
1203
+ if (on_path.has(v)) return false;
1204
+ const array = Array.isArray(v);
1205
+ if (!array) {
1206
+ const proto = Object.getPrototypeOf(v);
1207
+ if (proto !== Object.prototype && proto !== null) return false;
1208
+ }
1209
+ on_path.add(v);
1210
+ stack.push(v, LEAVE_NODE);
1211
+ if (array) for (let i = 0; i < v.length; i++) stack.push(v[i]);
1212
+ else for (const key of Object.keys(v)) stack.push(v[key]);
1213
+ }
1214
+ return true;
1215
+ }
1150
1216
  var NO_JSON_TEXT = "a value with no json text";
1151
1217
  function json_text_of(value) {
1218
+ if (!is_json_value(value)) return;
1152
1219
  try {
1153
1220
  const s = JSON.stringify(value);
1154
1221
  return is_string(s) ? s : void 0;
@@ -4107,6 +4174,35 @@ var gobjJs = (function(exports) {
4107
4174
  }
4108
4175
  return secret_name_check(str, i, to, true, by_segments);
4109
4176
  }
4177
+ function param_name_tail_from(str, from, to) {
4178
+ let bytes = 0;
4179
+ let i = to;
4180
+ while (i > from) {
4181
+ const code = str.charCodeAt(i - 1);
4182
+ let n = 3;
4183
+ let units = 1;
4184
+ if (code < 128) n = 1;
4185
+ else if (code < 2048) n = 2;
4186
+ else if (code >= 56320 && code <= 57343 && i - 2 >= from) {
4187
+ const high = str.charCodeAt(i - 2);
4188
+ if (high >= 55296 && high <= 56319) {
4189
+ n = 4;
4190
+ units = 2;
4191
+ }
4192
+ }
4193
+ if (bytes + n > MASK_MAX_NAME) return -1;
4194
+ if (code === 38 || code === 63 || code === 59) return i;
4195
+ bytes += n;
4196
+ i -= units;
4197
+ }
4198
+ return -1;
4199
+ }
4200
+ function is_param_name_secret(str, from, to, names) {
4201
+ const tail = names === NAMES_NOW ? param_name_tail_from(str, from, to) : -1;
4202
+ if (tail < 0) return is_secret_name_tail(str, from, to, names);
4203
+ if (is_secret_name_tail(str, from, to, NAMES_7_26_9)) return true;
4204
+ return is_secret_name_tail(str, from, to, NAMES_NOW) && secret_name_check(str, tail, to, false, true);
4205
+ }
4110
4206
  /************************************************************
4111
4207
  * Where an unquoted secret value that begins at `p` ends: at
4112
4208
  * the end, at the quote that closes an outer quoted value, or
@@ -4404,7 +4500,7 @@ var gobjJs = (function(exports) {
4404
4500
  }
4405
4501
  const name_from = word;
4406
4502
  word = p + 1;
4407
- const secret = is_secret_name_tail(str, name_from, p, names);
4503
+ const secret = is_param_name_secret(str, name_from, p, names);
4408
4504
  if (secret && names === NAMES_NOW && !not_7_26_9 && !is_secret_name_tail(str, name_from, p, NAMES_7_26_9)) not_7_26_9 = true;
4409
4505
  if (!(secret || value_is_secret && p - name_from === 5 && ascii_case_equal(str, name_from, "value"))) {
4410
4506
  if (judged && query_name_from(str, p) === name_from) judged[p] = JUDGED_NOT_SECRET;
@@ -4591,7 +4687,7 @@ var gobjJs = (function(exports) {
4591
4687
  p++;
4592
4688
  continue;
4593
4689
  }
4594
- if (!is_secret_name_tail(str, word, p, NAMES_NOW)) {
4690
+ if (!is_param_name_secret(str, word, p, NAMES_NOW)) {
4595
4691
  p++;
4596
4692
  word = p;
4597
4693
  continue;
@@ -4620,6 +4716,50 @@ var gobjJs = (function(exports) {
4620
4716
  }
4621
4717
  return false;
4622
4718
  }
4719
+ function mark_inline_rules_of_now(str, marks) {
4720
+ const value_is_secret = inline_value_is_secret(str, NAMES_NOW);
4721
+ const judged = new Uint8Array(str.length);
4722
+ mark_params(str, value_is_secret, READ_NOW, marks, judged);
4723
+ mark_query_params(str, marks, judged);
4724
+ mark_url_passwords(str, marks);
4725
+ mark_shapes(str, marks);
4726
+ mark_labels(str, marks);
4727
+ }
4728
+ var MASK_MAX_DECODINGS = 2;
4729
+ function encoded_ascii_at(str, p) {
4730
+ if (p + 3 > str.length || str.charCodeAt(p) !== 37) return -1;
4731
+ const hi = hex_digit_value(str.charCodeAt(p + 1));
4732
+ const lo = hi >= 0 ? hex_digit_value(str.charCodeAt(p + 2)) : -1;
4733
+ if (lo < 0) return -1;
4734
+ const c = hi * 16 + lo;
4735
+ return c > 0 && c < 128 ? c : -1;
4736
+ }
4737
+ function mark_decoded_view(str, marks, decodings) {
4738
+ if (decodings >= MASK_MAX_DECODINGS) return;
4739
+ const pieces = [];
4740
+ let last = 0;
4741
+ let p = str.indexOf("%");
4742
+ while (p >= 0) {
4743
+ const c = encoded_ascii_at(str, p);
4744
+ if (c >= 0) {
4745
+ pieces.push(str.substring(last, p), String.fromCharCode(c));
4746
+ last = p + 3;
4747
+ p = str.indexOf("%", last);
4748
+ } else p = str.indexOf("%", p + 1);
4749
+ }
4750
+ if (pieces.length === 0) return;
4751
+ pieces.push(str.substring(last));
4752
+ const view = pieces.join("");
4753
+ const view_marks = new Uint8Array(view.length);
4754
+ mark_inline_rules_of_now(view, view_marks);
4755
+ mark_decoded_view(view, view_marks, decodings + 1);
4756
+ let q = 0;
4757
+ for (let i = 0; i < view.length; i++) {
4758
+ const n = encoded_ascii_at(str, q) >= 0 ? 3 : 1;
4759
+ if (view_marks[i]) mark_range(marks, q, q + n);
4760
+ q += n;
4761
+ }
4762
+ }
4623
4763
  function mark_inline_secrets(str, marks) {
4624
4764
  const value_is_secret = inline_value_is_secret(str, NAMES_NOW);
4625
4765
  const value_is_secret_7_26_9 = inline_value_is_secret(str, NAMES_7_26_9);
@@ -4630,6 +4770,7 @@ var gobjJs = (function(exports) {
4630
4770
  mark_url_passwords(str, marks);
4631
4771
  mark_shapes(str, marks);
4632
4772
  mark_labels(str, marks);
4773
+ mark_decoded_view(str, marks, 0);
4633
4774
  }
4634
4775
  /************************************************************
4635
4776
  * A text (a command line) with the secrets that can be told
@@ -4641,13 +4782,14 @@ var gobjJs = (function(exports) {
4641
4782
  * same for a "name: value", its name in quotes or not (a json, a
4642
4783
  * header, a label: "password": x, Authorization: Basic x, bearer:
4643
4784
  * tok); and a JWT or the credential after "Bearer " or "Basic ",
4644
- * wherever they are, whatever names them. Each rule judges the text
4645
- * as it came. Return null when there was nothing to mask. As the C
4646
- * kernel's mask_secrets_inline().
4785
+ * wherever they are, whatever names them; in a URL or a query
4786
+ * %-encoded inside a value, the same read decoded (mark_decoded_view()).
4787
+ * Each rule judges the text as it came. Return null when there was
4788
+ * nothing to mask. As the C kernel's mask_secrets_inline().
4647
4789
  ************************************************************/
4648
4790
  function mask_secrets_inline(str) {
4649
4791
  if (typeof str !== "string") return null;
4650
- if (str.indexOf("=") < 0 && str.indexOf(":") < 0 && str.indexOf("eyJ") < 0 && !/bearer|basic/i.test(str)) return null;
4792
+ if (str.indexOf("=") < 0 && str.indexOf(":") < 0 && str.indexOf("%") < 0 && str.indexOf("eyJ") < 0 && !/bearer|basic/i.test(str)) return null;
4651
4793
  if (str.length > MASK_MAX_BYTES) return MASK_TOO_LARGE;
4652
4794
  const marks = new Uint8Array(str.length);
4653
4795
  mark_inline_secrets(str, marks);
@@ -8410,7 +8552,8 @@ var gobjJs = (function(exports) {
8410
8552
  inform_on_close: false,
8411
8553
  websocket: null,
8412
8554
  inside_on_open: false,
8413
- retry_ms: 0
8555
+ retry_ms: 0,
8556
+ retry_ms_before_session: 0
8414
8557
  };
8415
8558
  var __gclass__ = null;
8416
8559
  /******************************
@@ -8461,6 +8604,7 @@ var gobjJs = (function(exports) {
8461
8604
  function mt_start(gobj) {
8462
8605
  let priv = gobj.priv;
8463
8606
  priv.retry_ms = 0;
8607
+ priv.retry_ms_before_session = 0;
8464
8608
  if (gobj_current_state(gobj) !== "ST_DISCONNECTED") {
8465
8609
  gobj_send_event(gobj, "EV_ON_CLOSE", {
8466
8610
  url: priv.url,
@@ -8660,6 +8804,26 @@ var gobjJs = (function(exports) {
8660
8804
  }
8661
8805
  }
8662
8806
  /***************************************************************
8807
+ * Close the channel for a fault of the server: a message for a role
8808
+ * or a yuno that is not this one, an event out of its place.
8809
+ *
8810
+ * Not with 1000: EV_ON_CLOSE would say the session ended well. A
8811
+ * browser closes a WebSocket only with 1000 or 3000-4999 (1002, the
8812
+ * protocol error, throws there), so it is 4002 -- and the server
8813
+ * echoes it, so EV_ON_CLOSE carries it.
8814
+ *
8815
+ * And a session the server broke was not a session reached: the
8816
+ * backoff the ack reset is put back, or a server that breaks every
8817
+ * session is reconnected at the first delay for ever, with an
8818
+ * EV_ON_OPEN and an EV_ON_CLOSE in the app per round.
8819
+ ***************************************************************/
8820
+ var CLOSE_PEER_FAULT = 4002;
8821
+ function close_for_peer_fault(gobj, reason) {
8822
+ let priv = gobj.priv;
8823
+ if (gobj_current_state(gobj) === "ST_SESSION") priv.retry_ms = priv.retry_ms_before_session;
8824
+ close_websocket(gobj, CLOSE_PEER_FAULT, reason);
8825
+ }
8826
+ /***************************************************************
8663
8827
  * A text of the server -- a frame, the name of an event, of a
8664
8828
  * service, of a role -- as a log shows it: masked, then capped on a
8665
8829
  * whole character (capped first, a credential the cap cut would
@@ -8941,7 +9105,8 @@ var gobjJs = (function(exports) {
8941
9105
  *
8942
9106
  * Reset to zero when a session is actually reached
8943
9107
  * (ac_identity_card_ack), so a link that flaps once does not carry a
8944
- * minute-long penalty into its next real drop.
9108
+ * minute-long penalty into its next real drop -- and put back when the
9109
+ * server breaks that session (close_for_peer_fault()).
8945
9110
  ***************************************************************/
8946
9111
  function next_retry(gobj) {
8947
9112
  let priv = gobj.priv;
@@ -8991,6 +9156,7 @@ var gobjJs = (function(exports) {
8991
9156
  } else {
8992
9157
  gobj_change_state(gobj, "ST_SESSION");
8993
9158
  priv.inside_on_open = true;
9159
+ priv.retry_ms_before_session = priv.retry_ms;
8994
9160
  priv.retry_ms = 0;
8995
9161
  if (!priv.inform_on_close) {
8996
9162
  priv.inform_on_close = true;
@@ -9030,7 +9196,7 @@ var gobjJs = (function(exports) {
9030
9196
  if (String(iev_event).toLowerCase() === "ev_identity_card_ack") {
9031
9197
  if (!(gobj_send_event(gobj, "EV_IDENTITY_CARD_ACK", iev_kw, gobj) < 0)) return 0;
9032
9198
  } else log_warning(`${gobj_short_name(gobj)}: event UNKNOWN in not-session state ${peer_text_shown(iev_event, PEER_NAME_SHOWN)}`);
9033
- close_websocket(gobj);
9199
+ close_for_peer_fault(gobj, "event out of session");
9034
9200
  return -1;
9035
9201
  }
9036
9202
  iev_msg = null;
@@ -9039,13 +9205,13 @@ var gobjJs = (function(exports) {
9039
9205
  let iev_dst_role = kw_get_str(gobj, event_id, "dst_role", "");
9040
9206
  if (!empty_string(iev_dst_role) && iev_dst_role.toLowerCase() !== String(gobj_yuno_role()).toLowerCase()) {
9041
9207
  log_warning(`${gobj_short_name(gobj)}: It's not my role, dst_role: ${peer_text_shown(iev_dst_role, PEER_NAME_SHOWN)}, my_role: ${gobj_yuno_role()}, event: ${peer_text_shown(iev_event, PEER_NAME_SHOWN)}`);
9042
- close_websocket(gobj);
9208
+ close_for_peer_fault(gobj, "not my role");
9043
9209
  return -1;
9044
9210
  }
9045
9211
  let iev_dst_yuno = kw_get_str(gobj, event_id, "dst_yuno", "");
9046
9212
  if (!empty_string(iev_dst_yuno) && iev_dst_yuno.toLowerCase() !== String(gobj_yuno_name()).toLowerCase()) {
9047
9213
  log_warning(`${gobj_short_name(gobj)}: It's not my name, dst_yuno: ${peer_text_shown(iev_dst_yuno, PEER_NAME_SHOWN)}, my_name: ${gobj_yuno_name()}, event: ${peer_text_shown(iev_event, PEER_NAME_SHOWN)}`);
9048
- close_websocket(gobj);
9214
+ close_for_peer_fault(gobj, "not my name");
9049
9215
  return -1;
9050
9216
  }
9051
9217
  let iev_dst_service = kw_get_str(gobj, event_id, "dst_service", "");
@@ -9057,8 +9223,14 @@ var gobjJs = (function(exports) {
9057
9223
  log_warning(`${gobj_short_name(gobj)}: unsubscription event ignored, I'm client (service: ${peer_text_shown(iev_dst_service, PEER_NAME_SHOWN)}, event: ${peer_text_shown(iev_event, PEER_NAME_SHOWN)})`);
9058
9224
  return -1;
9059
9225
  }
9060
- if (gobj_has_event(gobj, iev_event, event_flag_t.EVF_PUBLIC_EVENT)) {
9061
- gobj_send_event(gobj, iev_event, iev_kw, gobj);
9226
+ const declared = gobj_find_event_type(iev_event, 0, false);
9227
+ if (declared && gobj_has_event(gobj, declared.event_name, 0)) {
9228
+ const own_event = declared.event_name;
9229
+ if (!gobj_has_event(gobj, own_event, event_flag_t.EVF_PUBLIC_EVENT) || own_event === "EV_IDENTITY_CARD_ACK") {
9230
+ log_warning(`${gobj_short_name(gobj)}: event of the transport itself, or out of its place, DROPPED: ev '${peer_text_shown(iev_event, PEER_NAME_SHOWN)}'`);
9231
+ return -1;
9232
+ }
9233
+ gobj_send_event(gobj, own_event, iev_kw, gobj);
9062
9234
  return 0;
9063
9235
  }
9064
9236
  if (!empty_string(iev_dst_service)) {
@@ -9074,9 +9246,9 @@ var gobjJs = (function(exports) {
9074
9246
  gobj_send_event(gobj_service, iev_event, iev_kw, gobj);
9075
9247
  return 0;
9076
9248
  }
9077
- let event_type = gobj_find_event_type(iev_event, 0, false);
9249
+ let event_type = gobj_find_event_type(iev_event, event_flag_t.EVF_PUBLIC_EVENT, false);
9078
9250
  if (!event_type) {
9079
- log_warning(`${gobj_short_name(gobj)}: event that no gclass declares, DROPPED: ev '${peer_text_shown(iev_event, PEER_NAME_SHOWN)}'`);
9251
+ log_warning(`${gobj_short_name(gobj)}: event that no gclass declares public, DROPPED: ev '${peer_text_shown(iev_event, PEER_NAME_SHOWN)}'`);
9080
9252
  return -1;
9081
9253
  }
9082
9254
  gobj_publish_event(gobj, event_type.event_name, iev_kw);
@@ -9199,7 +9371,7 @@ var gobjJs = (function(exports) {
9199
9371
  __gclass__ = gclass_create(gclass_name, [
9200
9372
  ["EV_ON_MESSAGE", event_flag_t.EVF_OUTPUT_EVENT],
9201
9373
  ["EV_IDENTITY_CARD_ACK", event_flag_t.EVF_PUBLIC_EVENT],
9202
- ["EV_ON_ID_NAK", event_flag_t.EVF_PUBLIC_EVENT | event_flag_t.EVF_OUTPUT_EVENT],
9374
+ ["EV_ON_ID_NAK", event_flag_t.EVF_OUTPUT_EVENT],
9203
9375
  ["EV_MT_STATS", event_flag_t.EVF_PUBLIC_EVENT],
9204
9376
  ["EV_MT_COMMAND", event_flag_t.EVF_PUBLIC_EVENT],
9205
9377
  ["EV_ON_OPEN", event_flag_t.EVF_OUTPUT_EVENT | event_flag_t.EVF_NO_WARN_SUBS],