@yuneta/gobj-js 7.26.20 → 7.26.22

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.
@@ -217,6 +217,13 @@ var gobjJs = (function(exports) {
217
217
  var __yuno__ = null;
218
218
  var __default_service__ = null;
219
219
  var __inside__ = 0;
220
+ var frame_kind_t = Object.freeze({
221
+ FRAME_ACTION: 0,
222
+ FRAME_PUBLICATION: 1,
223
+ FRAME_METHOD: 2,
224
+ FRAME_WATCH: 3
225
+ });
226
+ var __dispatch_top__ = null;
220
227
  /**************************************************************************
221
228
  * SData - Structured Data
222
229
  **************************************************************************/
@@ -230,7 +237,15 @@ var gobjJs = (function(exports) {
230
237
  DTP_JSON: 7,
231
238
  DTP_POINTER: 8
232
239
  });
240
+ var DTP_IS_STRING = (type) => type === data_type_t.DTP_STRING;
241
+ var DTP_IS_BOOLEAN = (type) => type === data_type_t.DTP_BOOLEAN;
242
+ var DTP_IS_INTEGER = (type) => type === data_type_t.DTP_INTEGER;
243
+ var DTP_IS_REAL = (type) => type === data_type_t.DTP_REAL;
244
+ var DTP_IS_LIST = (type) => type === data_type_t.DTP_LIST;
245
+ var DTP_IS_DICT = (type) => type === data_type_t.DTP_DICT;
246
+ var DTP_IS_JSON = (type) => type === data_type_t.DTP_JSON;
233
247
  data_type_t.DTP_POINTER;
248
+ var DTP_IS_NUMBER = (type) => DTP_IS_INTEGER(type) || DTP_IS_REAL(type) || DTP_IS_BOOLEAN(type);
234
249
  var sdata_flag_t = Object.freeze({
235
250
  SDF_NOTACCESS: 1,
236
251
  SDF_RD: 2,
@@ -252,7 +267,8 @@ var gobjJs = (function(exports) {
252
267
  SDF_AUTHZ_X: 131072,
253
268
  SDF_AUTHZ_P: 262144,
254
269
  SDF_AUTHZ_S: 524288,
255
- SDF_AUTHZ_RS: 1048576
270
+ SDF_AUTHZ_RS: 1048576,
271
+ SDF_SECRET: 2097152
256
272
  });
257
273
  sdata_flag_t.SDF_RD | sdata_flag_t.SDF_WR | sdata_flag_t.SDF_STATS | sdata_flag_t.SDF_PERSIST | sdata_flag_t.SDF_VOLATIL | sdata_flag_t.SDF_RSTATS | sdata_flag_t.SDF_PSTATS;
258
274
  sdata_flag_t.SDF_WR | sdata_flag_t.SDF_PERSIST;
@@ -840,6 +856,260 @@ var gobjJs = (function(exports) {
840
856
  return 0;
841
857
  }
842
858
  /***************************************************************************
859
+ * A value of a type, written as text or given as json, read as the C
860
+ * command parser reads a parameter (command_parser.c): the same grammar,
861
+ * the same refusals, so that a C client and a JS client read an attribute
862
+ * value the same way (json2item()). A refusal says why in a short phrase,
863
+ * never the value: it may be a secret.
864
+ ***************************************************************************/
865
+ var JSON_INTEGER_TEXT = /^-?(0|[1-9][0-9]*)$/;
866
+ var JSON_NUMBER_TEXT = /^-?(0|[1-9][0-9]*)(\.[0-9]+)?([eE][+-]?[0-9]+)?$/;
867
+ var INT64_MIN = -(2n ** 63n);
868
+ var INT64_MAX = 2n ** 63n - 1n;
869
+ var REFUSED_TEXT = "a text that does not read as one";
870
+ function value_has_shape(type, value) {
871
+ if (DTP_IS_STRING(type)) return is_string(value);
872
+ if (DTP_IS_DICT(type)) return is_object(value);
873
+ if (DTP_IS_LIST(type)) return is_array(value);
874
+ if (DTP_IS_NUMBER(type)) return typeof value === "number" || typeof value === "boolean";
875
+ return true;
876
+ }
877
+ function shape_of_value(value) {
878
+ if (is_array(value)) return "an array";
879
+ if (is_object(value)) return "an object";
880
+ if (is_string(value)) return REFUSED_TEXT;
881
+ if (typeof value === "number") return Number.isInteger(value) ? "an integer" : "a real";
882
+ if (typeof value === "boolean") return "a boolean";
883
+ return "null";
884
+ }
885
+ function number_as_type(type, value) {
886
+ if (typeof value === "number" && !Number.isFinite(value)) return {
887
+ value: void 0,
888
+ refused: "a number out of its range"
889
+ };
890
+ if (DTP_IS_BOOLEAN(type)) return {
891
+ value: typeof value === "boolean" ? value : value !== 0,
892
+ refused: null
893
+ };
894
+ if (DTP_IS_REAL(type)) return {
895
+ value: typeof value === "boolean" ? value ? 1 : 0 : value,
896
+ refused: null
897
+ };
898
+ if (typeof value === "boolean") return {
899
+ value: value ? 1 : 0,
900
+ refused: null
901
+ };
902
+ if (!(value >= -0x8000000000000000 && value < 0x8000000000000000)) return {
903
+ value: void 0,
904
+ refused: "a number out of its range"
905
+ };
906
+ if (!Number.isInteger(value)) return {
907
+ value: void 0,
908
+ refused: "a real with decimals"
909
+ };
910
+ return {
911
+ value,
912
+ refused: null
913
+ };
914
+ }
915
+ function text2parameter(type, s, from_kw) {
916
+ if (!is_string(s)) s = "";
917
+ if (DTP_IS_STRING(type)) return {
918
+ value: s,
919
+ refused: null
920
+ };
921
+ if (DTP_IS_NUMBER(type)) {
922
+ if (s.length === 0) {
923
+ if (from_kw) return {
924
+ value: void 0,
925
+ refused: null
926
+ };
927
+ return {
928
+ value: DTP_IS_BOOLEAN(type) ? false : 0,
929
+ refused: null
930
+ };
931
+ }
932
+ if (DTP_IS_BOOLEAN(type)) {
933
+ const lower = s.toLowerCase();
934
+ if (lower === "true" || lower === "yes" || lower === "on") return {
935
+ value: true,
936
+ refused: null
937
+ };
938
+ if (lower === "false" || lower === "no" || lower === "off") return {
939
+ value: false,
940
+ refused: null
941
+ };
942
+ }
943
+ if (!(DTP_IS_REAL(type) ? JSON_NUMBER_TEXT : JSON_INTEGER_TEXT).test(s)) return {
944
+ value: void 0,
945
+ refused: REFUSED_TEXT
946
+ };
947
+ if (DTP_IS_REAL(type)) {
948
+ const d = Number(s);
949
+ if (!Number.isFinite(d)) return {
950
+ value: void 0,
951
+ refused: "a number out of its range"
952
+ };
953
+ return {
954
+ value: d,
955
+ refused: null
956
+ };
957
+ }
958
+ const n = BigInt(s);
959
+ if (n < INT64_MIN || n > INT64_MAX) return {
960
+ value: void 0,
961
+ refused: "a number out of its range"
962
+ };
963
+ if (DTP_IS_BOOLEAN(type)) return {
964
+ value: n !== 0n,
965
+ refused: null
966
+ };
967
+ return {
968
+ value: Number(n),
969
+ refused: null
970
+ };
971
+ }
972
+ if (DTP_IS_DICT(type) || DTP_IS_LIST(type)) {
973
+ let jn;
974
+ try {
975
+ jn = JSON.parse(s);
976
+ } catch (e) {
977
+ return {
978
+ value: void 0,
979
+ refused: REFUSED_TEXT
980
+ };
981
+ }
982
+ if (!value_has_shape(type, jn)) return {
983
+ value: void 0,
984
+ refused: REFUSED_TEXT
985
+ };
986
+ return {
987
+ value: jn,
988
+ refused: null
989
+ };
990
+ }
991
+ if (DTP_IS_JSON(type)) try {
992
+ return {
993
+ value: JSON.parse(s),
994
+ refused: null
995
+ };
996
+ } catch (e) {
997
+ const t = s.replace(/^[ \t]+/, "");
998
+ if (t.startsWith("{") || t.startsWith("[") || t.startsWith("\"")) return {
999
+ value: void 0,
1000
+ refused: REFUSED_TEXT
1001
+ };
1002
+ return {
1003
+ value: s,
1004
+ refused: null
1005
+ };
1006
+ }
1007
+ return {
1008
+ value: void 0,
1009
+ refused: REFUSED_TEXT
1010
+ };
1011
+ }
1012
+ /***************************************************************************
1013
+ * A value of `type` written as TEXT, read as the C parser reads a
1014
+ * parameter on the command line (command_parameter_from_text()): an empty
1015
+ * text is 0 or false. Return {value, refused}: `value` undefined when the
1016
+ * text does not read as one, `refused` saying why.
1017
+ ***************************************************************************/
1018
+ function command_parameter_from_text(type, text) {
1019
+ const r = text2parameter(type, text, false);
1020
+ if (r.value === void 0 && !r.refused) r.refused = REFUSED_TEXT;
1021
+ return r;
1022
+ }
1023
+ /***************************************************************************
1024
+ * A value of `type` given as JSON, read as the C parser reads a
1025
+ * parameter given in kw (command_parameter_from_json()): a string as
1026
+ * command_parameter_from_text() reads a text (a string with a NUL inside
1027
+ * refused), a number or a boolean as the EXACT type (an integer to a
1028
+ * DTP_REAL is its real, a boolean to a DTP_INTEGER 1 or 0, 2.7 to a
1029
+ * DTP_INTEGER refused), an object or a list of its shape as it is, any
1030
+ * other shape refused. Return {value, refused}: `value` undefined and
1031
+ * `refused` saying why, or `refused` null when there is NO value (a null,
1032
+ * undefined, or an empty text given to a number).
1033
+ ***************************************************************************/
1034
+ function command_parameter_from_json(type, value) {
1035
+ if (value === void 0 || value === null) {
1036
+ if (DTP_IS_JSON(type) && value === null) return {
1037
+ value: null,
1038
+ refused: null
1039
+ };
1040
+ return {
1041
+ value: void 0,
1042
+ refused: null
1043
+ };
1044
+ }
1045
+ const nul_inside = is_string(value) && value.indexOf("\0") >= 0;
1046
+ if (DTP_IS_JSON(type)) {
1047
+ if (!is_string(value) || nul_inside) return {
1048
+ value,
1049
+ refused: null
1050
+ };
1051
+ const r = text2parameter(type, value, true);
1052
+ return r.value === void 0 ? {
1053
+ value,
1054
+ refused: null
1055
+ } : r;
1056
+ }
1057
+ if (!(DTP_IS_STRING(type) || DTP_IS_DICT(type) || DTP_IS_LIST(type) || DTP_IS_NUMBER(type))) return {
1058
+ value,
1059
+ refused: null
1060
+ };
1061
+ if (nul_inside) return {
1062
+ value: void 0,
1063
+ refused: "a text with a NUL in it"
1064
+ };
1065
+ if (is_string(value) && !DTP_IS_STRING(type)) return text2parameter(type, value, true);
1066
+ if (!value_has_shape(type, value)) return {
1067
+ value: void 0,
1068
+ refused: shape_of_value(value)
1069
+ };
1070
+ if (DTP_IS_NUMBER(type)) return number_as_type(type, value);
1071
+ return {
1072
+ value,
1073
+ refused: null
1074
+ };
1075
+ }
1076
+ /***************************************************************************
1077
+ * A value json2item() refuses: the attr, its type and why, and the value
1078
+ * as a log may show it (a SDF_SECRET one never; any other masked, then
1079
+ * capped on a whole character, as in C)
1080
+ ***************************************************************************/
1081
+ var ATTR_VALUE_SHOWN = 64;
1082
+ var TYPES_READ = [
1083
+ data_type_t.DTP_BOOLEAN,
1084
+ data_type_t.DTP_INTEGER,
1085
+ data_type_t.DTP_REAL,
1086
+ data_type_t.DTP_LIST,
1087
+ data_type_t.DTP_DICT
1088
+ ];
1089
+ function log_attr_value_refused(gobj, it, value, refused) {
1090
+ const types = {
1091
+ [data_type_t.DTP_BOOLEAN]: "a boolean",
1092
+ [data_type_t.DTP_INTEGER]: "an integer",
1093
+ [data_type_t.DTP_REAL]: "a real",
1094
+ [data_type_t.DTP_LIST]: "a json array",
1095
+ [data_type_t.DTP_DICT]: "a json object"
1096
+ };
1097
+ let shown;
1098
+ if (it.flag & sdata_flag_t.SDF_SECRET) shown = "********";
1099
+ else {
1100
+ shown = is_string(value) ? value : String(JSON.stringify(value === void 0 ? null : value));
1101
+ const masked = mask_secrets_inline(shown);
1102
+ if (masked !== null) shown = masked;
1103
+ if (shown.length > ATTR_VALUE_SHOWN) {
1104
+ let n = ATTR_VALUE_SHOWN;
1105
+ const code = shown.charCodeAt(n);
1106
+ if (code >= 56320 && code <= 57343) n--;
1107
+ shown = shown.substring(0, n);
1108
+ }
1109
+ }
1110
+ log_error(`${gobj_short_name(gobj)}: Attribute value of the wrong type, not written: attr '${it.name}', type ${types[it.type] || "a value of its type"}, got ${refused || "no value (a null, or an empty text)"}, value '${shown}'`);
1111
+ }
1112
+ /***************************************************************************
843
1113
  * Set array values to sdata, from json or binary
844
1114
  ***************************************************************************/
845
1115
  function json2item(gobj, sdata, it, jn_value_) {
@@ -854,44 +1124,18 @@ var gobjJs = (function(exports) {
854
1124
  }
855
1125
  break;
856
1126
  case data_type_t.DTP_BOOLEAN:
857
- jn_value2 = parseBoolean(jn_value_);
858
- break;
859
1127
  case data_type_t.DTP_INTEGER:
860
- jn_value2 = parseInt(jn_value_);
861
- if (isNaN(jn_value2)) {
862
- log_error(`${gobj_short_name(gobj)}: attr NaN: ${it.name}`);
863
- return -1;
864
- }
865
- break;
866
1128
  case data_type_t.DTP_REAL:
867
- jn_value2 = Number(jn_value_);
868
- if (isNaN(jn_value2)) {
869
- log_error(`${gobj_short_name(gobj)}: attr NaN: ${it.name}`);
870
- return -1;
871
- }
872
- break;
873
1129
  case data_type_t.DTP_LIST:
874
- if (is_string(jn_value_)) try {
875
- jn_value2 = JSON.parse(jn_value_);
876
- } catch (error) {
877
- log_error(`JSON parse error: ${error.message}`);
878
- }
879
- else jn_value2 = jn_value_;
880
- if (!is_array(jn_value2)) {
881
- log_error(`attr must be an array: ${it.name}`);
882
- return -1;
883
- }
884
- break;
885
1130
  case data_type_t.DTP_DICT:
886
- if (is_string(jn_value_)) try {
887
- jn_value2 = JSON.parse(jn_value_);
888
- } catch (error) {
889
- log_error(`JSON parse error: ${error.message}`);
890
- }
891
- else jn_value2 = jn_value_;
892
- if (!is_object(jn_value2)) {
893
- log_error(`attr must be an object: ${it.name}`);
894
- return -1;
1131
+ {
1132
+ if (jn_value_ === void 0) return 0;
1133
+ const r = command_parameter_from_json(it.type, jn_value_);
1134
+ if (r.value === void 0) {
1135
+ log_attr_value_refused(gobj, it, jn_value_, r.refused);
1136
+ return -1;
1137
+ }
1138
+ jn_value2 = r.value;
895
1139
  }
896
1140
  break;
897
1141
  case data_type_t.DTP_JSON:
@@ -1466,6 +1710,8 @@ var gobjJs = (function(exports) {
1466
1710
  return;
1467
1711
  }
1468
1712
  if (gobj.__refs__ > 0) log_error(`${gobj_short_name(gobj)}: gobj DESTROYING with references: ${gobj.__refs__}`);
1713
+ if (!(gobj.parent && gobj_is_destroying(gobj.parent))) check_destroy_under_running_code(gobj);
1714
+ mark_dispatch_frames_destroyed(gobj);
1469
1715
  if (gobj.playing) {
1470
1716
  log_error(`Destroying a PLAYING gobj: ${gobj_full_name(gobj)}`);
1471
1717
  gobj_pause(gobj);
@@ -1530,10 +1776,44 @@ var gobjJs = (function(exports) {
1530
1776
  if (__trace_gobj_start_stop__(gobj)) trace_machine(sprintf("⏺ ⏺ start: %s", gobj_full_name(gobj)));
1531
1777
  gobj.running = true;
1532
1778
  let ret = 0;
1533
- if (gobj.gclass.gmt.mt_start) ret = gobj.gclass.gmt.mt_start(gobj);
1779
+ if (gobj.gclass.gmt.mt_start) {
1780
+ const frame = push_dispatch_frame(gobj, "mt_start", frame_kind_t.FRAME_METHOD);
1781
+ try {
1782
+ ret = gobj.gclass.gmt.mt_start(gobj);
1783
+ } finally {
1784
+ pop_dispatch_frame(frame);
1785
+ }
1786
+ }
1534
1787
  return ret;
1535
1788
  }
1536
1789
  /***************************************************************************
1790
+ * Start a gobj in a walk of its tree, and say whether that destroyed it.
1791
+ *
1792
+ * A gclass may end itself in its own mt_start or mt_stop, and a walk of
1793
+ * the tree must not go down into the children of a gobj that is gone.
1794
+ ***************************************************************************/
1795
+ function start_destroys_it(gobj) {
1796
+ const frame = push_dispatch_frame(gobj, "gobj_start", frame_kind_t.FRAME_WATCH);
1797
+ try {
1798
+ gobj_start(gobj);
1799
+ } finally {
1800
+ pop_dispatch_frame(frame);
1801
+ }
1802
+ return frame.destroyed;
1803
+ }
1804
+ /***************************************************************************
1805
+ * Stop a gobj in a walk of its tree, and say whether that destroyed it.
1806
+ ***************************************************************************/
1807
+ function stop_destroys_it(gobj) {
1808
+ const frame = push_dispatch_frame(gobj, "gobj_stop", frame_kind_t.FRAME_WATCH);
1809
+ try {
1810
+ gobj_stop(gobj);
1811
+ } finally {
1812
+ pop_dispatch_frame(frame);
1813
+ }
1814
+ return frame.destroyed;
1815
+ }
1816
+ /***************************************************************************
1537
1817
  * Start all children of the gobj.
1538
1818
  ***************************************************************************/
1539
1819
  function cb_start_child(child, user_data, user_data2) {
@@ -1554,7 +1834,9 @@ var gobjJs = (function(exports) {
1554
1834
  function cb_start_child_tree(child, user_data, user_data2) {
1555
1835
  if (child.gclass.gclass_flag & gclass_flag_t.gcflag_manual_start) return 1;
1556
1836
  if (gobj_is_disabled(child)) return 1;
1557
- if (!gobj_is_running(child)) gobj_start(child);
1837
+ if (!gobj_is_running(child)) {
1838
+ if (start_destroys_it(child)) return 1;
1839
+ }
1558
1840
  return 0;
1559
1841
  }
1560
1842
  function gobj_start_tree(gobj) {
@@ -1565,7 +1847,9 @@ var gobjJs = (function(exports) {
1565
1847
  if (__trace_gobj_start_stop__(gobj)) trace_machine(sprintf("⏺ ⏺ ⏺ ⏺ start_tree: %s", gobj_full_name(gobj)));
1566
1848
  if (gobj.gclass.gclass_flag & gclass_flag_t.gcflag_manual_start) return 0;
1567
1849
  else if (gobj.disabled) return 0;
1568
- else if (!gobj.running) gobj_start(gobj);
1850
+ else if (!gobj.running) {
1851
+ if (start_destroys_it(gobj)) return 0;
1852
+ }
1569
1853
  return gobj_walk_gobj_children_tree(gobj, walk_type_t.WALK_TOP2BOTTOM, cb_start_child_tree, 0, 0);
1570
1854
  }
1571
1855
  /************************************************************
@@ -1587,14 +1871,23 @@ var gobjJs = (function(exports) {
1587
1871
  if (__trace_gobj_start_stop__(gobj)) trace_machine(sprintf("⏹ ⏹ stop: %s", gobj_full_name(gobj)));
1588
1872
  gobj.running = false;
1589
1873
  let ret = 0;
1590
- if (gobj.gclass.gmt.mt_stop) ret = gobj.gclass.gmt.mt_stop(gobj);
1874
+ if (gobj.gclass.gmt.mt_stop) {
1875
+ const frame = push_dispatch_frame(gobj, "mt_stop", frame_kind_t.FRAME_METHOD);
1876
+ try {
1877
+ ret = gobj.gclass.gmt.mt_stop(gobj);
1878
+ } finally {
1879
+ pop_dispatch_frame(frame);
1880
+ }
1881
+ }
1591
1882
  return ret;
1592
1883
  }
1593
1884
  /***************************************************************************
1594
1885
  * Stop all children of the gobj.
1595
1886
  ***************************************************************************/
1596
1887
  function cb_stop_child(child, user_data, user_data2) {
1597
- if (gobj_is_running(child)) gobj_stop(child);
1888
+ if (gobj_is_running(child)) {
1889
+ if (stop_destroys_it(child)) return 1;
1890
+ }
1598
1891
  return 0;
1599
1892
  }
1600
1893
  function gobj_stop_children(gobj) {
@@ -1613,7 +1906,9 @@ var gobjJs = (function(exports) {
1613
1906
  return -1;
1614
1907
  }
1615
1908
  if (__trace_gobj_start_stop__(gobj)) trace_machine(sprintf("⏹ ⏹ ⏹ ⏹ stop_tree: %s", gobj_full_name(gobj)));
1616
- if (gobj_is_running(gobj)) gobj_stop(gobj);
1909
+ if (gobj_is_running(gobj)) {
1910
+ if (stop_destroys_it(gobj)) return 0;
1911
+ }
1617
1912
  return gobj_walk_gobj_children_tree(gobj, walk_type_t.WALK_TOP2BOTTOM, cb_stop_child, 0, 0);
1618
1913
  }
1619
1914
  /************************************************************
@@ -1645,8 +1940,13 @@ var gobjJs = (function(exports) {
1645
1940
  gobj.playing = true;
1646
1941
  let ret = 0;
1647
1942
  if (gobj.gclass.gmt.mt_play) {
1648
- ret = gobj.gclass.gmt.mt_play(gobj);
1649
- if (ret < 0 || ret === false) gobj.playing = false;
1943
+ const frame = push_dispatch_frame(gobj, "mt_play", frame_kind_t.FRAME_METHOD);
1944
+ try {
1945
+ ret = gobj.gclass.gmt.mt_play(gobj);
1946
+ } finally {
1947
+ pop_dispatch_frame(frame);
1948
+ }
1949
+ if ((ret < 0 || ret === false) && !frame.destroyed) gobj.playing = false;
1650
1950
  }
1651
1951
  return ret;
1652
1952
  }
@@ -1664,8 +1964,14 @@ var gobjJs = (function(exports) {
1664
1964
  }
1665
1965
  if (__trace_gobj_start_stop__(gobj)) trace_machine(sprintf("⏸ ⏸ pause: %s", gobj_full_name(gobj)));
1666
1966
  gobj.playing = false;
1667
- if (gobj.gclass.gmt.mt_pause) return gobj.gclass.gmt.mt_pause(gobj);
1668
- else return 0;
1967
+ if (gobj.gclass.gmt.mt_pause) {
1968
+ const frame = push_dispatch_frame(gobj, "mt_pause", frame_kind_t.FRAME_METHOD);
1969
+ try {
1970
+ return gobj.gclass.gmt.mt_pause(gobj);
1971
+ } finally {
1972
+ pop_dispatch_frame(frame);
1973
+ }
1974
+ } else return 0;
1669
1975
  }
1670
1976
  /************************************************************
1671
1977
  *
@@ -2218,14 +2524,7 @@ var gobjJs = (function(exports) {
2218
2524
  if (ss.length <= 1) {
2219
2525
  let key = path;
2220
2526
  if (key in jn_attrs) {
2221
- if (Object.prototype.hasOwnProperty.call(jn_attrs, key)) {
2222
- jn_attrs[key] = value;
2223
- if (is_object(gobj.priv) && Object.prototype.hasOwnProperty.call(gobj.priv, key)) gobj.priv[key] = value;
2224
- if (gobj.obflag & obflag_t.obflag_created && !(gobj.obflag & obflag_t.obflag_destroyed)) {
2225
- if (gobj.gclass.gmt.mt_writing) gobj.gclass.gmt.mt_writing(gobj, key);
2226
- }
2227
- return 0;
2228
- }
2527
+ if (Object.prototype.hasOwnProperty.call(jn_attrs, key)) return write_attr_value(gobj, key, value);
2229
2528
  }
2230
2529
  log_error(sprintf("gobj_write_attr(%s): attr not found '%s'", gobj_short_name(gobj), key));
2231
2530
  return -1;
@@ -2241,14 +2540,7 @@ var gobjJs = (function(exports) {
2241
2540
  }
2242
2541
  let jn_attrs = gobj.jn_attrs;
2243
2542
  if (key in jn_attrs) {
2244
- if (Object.prototype.hasOwnProperty.call(jn_attrs, key)) {
2245
- jn_attrs[key] = value;
2246
- if (is_object(gobj.priv) && Object.prototype.hasOwnProperty.call(gobj.priv, key)) gobj.priv[key] = value;
2247
- if (gobj.obflag & obflag_t.obflag_created && !(gobj.obflag & obflag_t.obflag_destroyed)) {
2248
- if (gobj.gclass.gmt.mt_writing) gobj.gclass.gmt.mt_writing(gobj, key);
2249
- }
2250
- return 0;
2251
- }
2543
+ if (Object.prototype.hasOwnProperty.call(jn_attrs, key)) return write_attr_value(gobj, key, value);
2252
2544
  }
2253
2545
  break;
2254
2546
  }
@@ -2256,6 +2548,49 @@ var gobjJs = (function(exports) {
2256
2548
  return -1;
2257
2549
  }
2258
2550
  /***************************************************************************
2551
+ * The value written to the attr `key` of `gobj`, read as its type as the C
2552
+ * kernel reads it (json2item(): it writes priv and calls mt_writing too).
2553
+ * Up to 7.26.21 gobj_write_attr() wrote it raw.
2554
+ ***************************************************************************/
2555
+ function write_attr_value(gobj, key, value) {
2556
+ const it = gobj_attr_desc(gobj, key, false);
2557
+ if (!it) {
2558
+ log_error(sprintf("gobj_write_attr(%s): attr without description '%s'", gobj_short_name(gobj), key));
2559
+ return -1;
2560
+ }
2561
+ if (value === void 0 && TYPES_READ.includes(it.type)) {
2562
+ log_attr_value_refused(gobj, it, value, null);
2563
+ return -1;
2564
+ }
2565
+ return json2item(gobj, gobj.jn_attrs, it, value);
2566
+ }
2567
+ /***************************************************************************
2568
+ * The value a typed writer writes, read as ITS type by the grammar of
2569
+ * json2item() (a C writer takes its C type: a string is never read as a
2570
+ * number there). Return {value} or {refused} (logged): the attr keeps its
2571
+ * value. A string writer never refuses: null and undefined are "", any
2572
+ * other json its text, as a DTP_STRING attr reads them.
2573
+ ***************************************************************************/
2574
+ function typed_writer_value(gobj, name, type, value) {
2575
+ if (DTP_IS_STRING(type)) {
2576
+ if (value === null || value === void 0) return { value: "" };
2577
+ return { value: is_string(value) ? value : String(JSON.stringify(value)) };
2578
+ }
2579
+ const r = command_parameter_from_json(type, value);
2580
+ if (r.value === void 0) {
2581
+ let holder = gobj;
2582
+ while (holder && !gobj_has_attr(holder, name)) holder = holder.bottom_gobj;
2583
+ const it = holder ? gobj_attr_desc(holder, name, false) : null;
2584
+ log_attr_value_refused(gobj, {
2585
+ name,
2586
+ type,
2587
+ flag: it ? it.flag : 0
2588
+ }, value, r.refused);
2589
+ return { refused: true };
2590
+ }
2591
+ return { value: r.value };
2592
+ }
2593
+ /***************************************************************************
2259
2594
  * WRITE - high level
2260
2595
  ***************************************************************************/
2261
2596
  function sdata_write_default_values(gobj, include_flag, exclude_flag) {
@@ -2303,7 +2638,9 @@ var gobjJs = (function(exports) {
2303
2638
  function gobj_write_bool_attr(gobj, name, value) {
2304
2639
  let hs = gobj_hsdata2(gobj, name, false);
2305
2640
  if (hs) {
2306
- hs[name] = parseBoolean(value);
2641
+ const v = typed_writer_value(gobj, name, data_type_t.DTP_BOOLEAN, value);
2642
+ if (v.refused) return -1;
2643
+ hs[name] = v.value;
2307
2644
  if (is_object(gobj.priv) && Object.prototype.hasOwnProperty.call(gobj.priv, name)) gobj.priv[name] = hs[name];
2308
2645
  if (gobj.obflag & obflag_t.obflag_created && !(gobj.obflag & obflag_t.obflag_destroyed)) {
2309
2646
  if (gobj.gclass.gmt.mt_writing) gobj.gclass.gmt.mt_writing(gobj, name);
@@ -2319,7 +2656,9 @@ var gobjJs = (function(exports) {
2319
2656
  function gobj_write_integer_attr(gobj, name, value) {
2320
2657
  let hs = gobj_hsdata2(gobj, name, false);
2321
2658
  if (hs) {
2322
- hs[name] = parseInt(value);
2659
+ const v = typed_writer_value(gobj, name, data_type_t.DTP_INTEGER, value);
2660
+ if (v.refused) return -1;
2661
+ hs[name] = v.value;
2323
2662
  if (is_object(gobj.priv) && Object.prototype.hasOwnProperty.call(gobj.priv, name)) gobj.priv[name] = hs[name];
2324
2663
  if (gobj.obflag & obflag_t.obflag_created && !(gobj.obflag & obflag_t.obflag_destroyed)) {
2325
2664
  if (gobj.gclass.gmt.mt_writing) gobj.gclass.gmt.mt_writing(gobj, name);
@@ -2335,7 +2674,9 @@ var gobjJs = (function(exports) {
2335
2674
  function gobj_write_str_attr(gobj, name, value) {
2336
2675
  let hs = gobj_hsdata2(gobj, name, false);
2337
2676
  if (hs) {
2338
- hs[name] = String(value);
2677
+ const v = typed_writer_value(gobj, name, data_type_t.DTP_STRING, value);
2678
+ if (v.refused) return -1;
2679
+ hs[name] = v.value;
2339
2680
  if (is_object(gobj.priv) && Object.prototype.hasOwnProperty.call(gobj.priv, name)) gobj.priv[name] = hs[name];
2340
2681
  if (gobj.obflag & obflag_t.obflag_created && !(gobj.obflag & obflag_t.obflag_destroyed)) {
2341
2682
  if (gobj.gclass.gmt.mt_writing) gobj.gclass.gmt.mt_writing(gobj, name);
@@ -2545,6 +2886,84 @@ var gobjJs = (function(exports) {
2545
2886
  __dl_posted_events__ = __dl_posted_events__.filter((msg) => msg.dst !== gobj);
2546
2887
  }
2547
2888
  /************************************************************
2889
+ * A dispatch begins: its frame goes on top of the chain.
2890
+ * Every push is paired with a pop in a `finally`: an action
2891
+ * that throws must not leave its frame on the chain.
2892
+ ************************************************************/
2893
+ function push_dispatch_frame(gobj, event, kind) {
2894
+ const frame = {
2895
+ prev: __dispatch_top__,
2896
+ gobj,
2897
+ event,
2898
+ kind,
2899
+ destroyed: false
2900
+ };
2901
+ __dispatch_top__ = frame;
2902
+ return frame;
2903
+ }
2904
+ function pop_dispatch_frame(frame) {
2905
+ __dispatch_top__ = frame.prev;
2906
+ }
2907
+ /************************************************************
2908
+ * Every dispatch in progress of `gobj` learns that it is
2909
+ * destroyed. Only its own frames: each child destroyed with
2910
+ * it marks its own, in its own gobj_destroy().
2911
+ ************************************************************/
2912
+ function mark_dispatch_frames_destroyed(gobj) {
2913
+ for (let f = __dispatch_top__; f; f = f.prev) if (f.gobj === gobj) f.destroyed = true;
2914
+ }
2915
+ /************************************************************
2916
+ * Is the innermost live publication of `gobj` its EV_STOPPED?
2917
+ * Then the stop contract holds for it: that is the last thing
2918
+ * it does with itself.
2919
+ ************************************************************/
2920
+ function said_farewell(gobj) {
2921
+ for (let f = __dispatch_top__; f; f = f.prev) if (f.kind === frame_kind_t.FRAME_PUBLICATION && !f.destroyed && f.gobj === gobj) return f.event === "EV_STOPPED";
2922
+ return false;
2923
+ }
2924
+ /************************************************************
2925
+ * A gobj must not be destroyed under code that is still
2926
+ * running on it -- the C kernel's check, with its exemptions
2927
+ * and its fields, so both runtimes report the same defect the
2928
+ * same way.
2929
+ *
2930
+ * `gobj` is about to be destroyed, and with it its whole
2931
+ * subtree. Every live frame of a gobj of that subtree is code
2932
+ * that goes on when the destroy returns, on a gobj that is gone
2933
+ * (C_TIMER right after its EV_TIMEOUT). It is an ERROR, except
2934
+ * for:
2935
+ *
2936
+ * - the innermost frame: it is the code that destroys, and
2937
+ * knows it (a gobj that destroys itself in its own action);
2938
+ *
2939
+ * - the frames of a gobj whose innermost publication is
2940
+ * EV_STOPPED: the stop contract, its host destroys it there;
2941
+ *
2942
+ * - the watch frames, which run no gclass code of their own.
2943
+ *
2944
+ * The destroy goes on: this only says it, once. The fix is to
2945
+ * defer the destroy with gobj_post_event().
2946
+ ************************************************************/
2947
+ function check_destroy_under_running_code(gobj) {
2948
+ const top = __dispatch_top__;
2949
+ if (!top) return;
2950
+ for (let f = top.prev; f; f = f.prev) {
2951
+ if (f.destroyed || f.kind === frame_kind_t.FRAME_WATCH) continue;
2952
+ let in_tree = false;
2953
+ for (let p = f.gobj; p; p = p.parent) if (p === gobj) {
2954
+ in_tree = true;
2955
+ break;
2956
+ }
2957
+ if (!in_tree) continue;
2958
+ if (said_farewell(f.gobj)) continue;
2959
+ const destroyer = top.destroyed ? "(destroyed)" : gobj_full_name(top.gobj);
2960
+ const stack = String((/* @__PURE__ */ new Error()).stack || "").split("\n").slice(2).join("\n");
2961
+ if (f.kind === frame_kind_t.FRAME_PUBLICATION) log_error(`Destroying a gobj while its tree is publishing: destroying ${gobj_full_name(gobj)}, publisher ${gobj_full_name(f.gobj)}, event ${f.event || ""}, destroyer ${destroyer}, inner_event ${top.event || ""}. Defer it with gobj_post_event(): a subscriber must not destroy the tree of its publisher synchronously. stack:\n${stack}`);
2962
+ else log_error(`Destroying a gobj while one of its actions is still running: destroying ${gobj_full_name(gobj)}, running ${gobj_full_name(f.gobj)}, event ${f.event || ""}, destroyer ${destroyer}, inner_event ${top.event || ""}. Defer it with gobj_post_event(): an inner dispatch must not destroy a gobj that an outer one is running on. stack:\n${stack}`);
2963
+ return;
2964
+ }
2965
+ }
2966
+ /************************************************************
2548
2967
  * send_event
2549
2968
  ************************************************************/
2550
2969
  function gobj_send_event(dst, event, kw, src) {
@@ -2576,7 +2995,12 @@ var gobjJs = (function(exports) {
2576
2995
  }
2577
2996
  }
2578
2997
  }
2579
- return dst.gclass.gmt.mt_inject_event(dst, event, kw, src);
2998
+ const frame = push_dispatch_frame(dst, event, frame_kind_t.FRAME_ACTION);
2999
+ try {
3000
+ return dst.gclass.gmt.mt_inject_event(dst, event, kw, src);
3001
+ } finally {
3002
+ pop_dispatch_frame(frame);
3003
+ }
2580
3004
  }
2581
3005
  if (tracea) trace_machine(sprintf("📛 mach(%s%s^%s), st: %s, ev: %s, 📛📛ERROR Event NOT DEFINED in state📛📛, from(%s%s^%s)", !dst.running ? "!!" : "", gobj_gclass_name(dst), gobj_name(dst), state.state_name, event ? event : "", src && !src.running ? "!!" : "", gobj_gclass_name(src), gobj_name(src)));
2582
3006
  log_error(`📛📛 Event NOT DEFINED in state 📛📛: ${gobj_short_name(dst)}, ${state.state_name}, ${event}`);
@@ -2596,6 +3020,7 @@ var gobjJs = (function(exports) {
2596
3020
  }
2597
3021
  }
2598
3022
  }
3023
+ const frame = push_dispatch_frame(dst, event, frame_kind_t.FRAME_ACTION);
2599
3024
  if (event_action.next_state) gobj_change_state(dst, event_action.next_state);
2600
3025
  let ret = -1;
2601
3026
  try {
@@ -2609,8 +3034,10 @@ var gobjJs = (function(exports) {
2609
3034
  } catch (e2) {}
2610
3035
  }
2611
3036
  throw e;
3037
+ } finally {
3038
+ pop_dispatch_frame(frame);
2612
3039
  }
2613
- if (tracea && __trace_machine_format__ !== 1 && !(dst.obflag & obflag_t.obflag_destroyed)) trace_machine(sprintf("<- mach(%s%s^%s), st: %s, ev: %s, ret: %d", !dst.running ? "!!" : "", gobj_gclass_name(dst), gobj_name(dst), dst.current_state.state_name, event ? event : "", is_number(ret) ? ret : 0));
3040
+ if (tracea && __trace_machine_format__ !== 1 && !frame.destroyed) trace_machine(sprintf("<- mach(%s%s^%s), st: %s, ev: %s, ret: %d", !dst.running ? "!!" : "", gobj_gclass_name(dst), gobj_name(dst), dst.current_state.state_name, event ? event : "", is_number(ret) ? ret : 0));
2614
3041
  __inside__--;
2615
3042
  return ret;
2616
3043
  }
@@ -3073,62 +3500,67 @@ var gobjJs = (function(exports) {
3073
3500
  let dl_subs = [...publisher.dl_subscriptions];
3074
3501
  let sent_count = 0;
3075
3502
  let ret = 0;
3076
- for (let idx = 0; idx < dl_subs.length; idx++) {
3077
- let subs = dl_subs[idx];
3078
- if (publisher.gclass.gmt.mt_publication_pre_filter) {
3079
- let topublish = publisher.gclass.gmt.mt_publication_pre_filter(publisher, subs, event, kw);
3080
- if (topublish < 0) break;
3081
- else if (!topublish) continue;
3082
- }
3083
- let subscriber = kw_get_pointer(publisher, subs, "subscriber", null, kw_flag_t.KW_REQUIRED);
3084
- if (!(subscriber && !gobj_is_destroying(subscriber))) continue;
3085
- let subs_flag = kw_get_int(publisher, subs, "subs_flag", 0, kw_flag_t.KW_REQUIRED);
3086
- let event_ = kw_get_str(publisher, subs, "event", "", kw_flag_t.KW_REQUIRED);
3087
- if (empty_string(event_) || strcasecmp(event_, event) === 0) {
3088
- let __config__ = kw_get_dict(publisher, subs, "__config__", null, 0);
3089
- let __global__ = kw_get_dict(publisher, subs, "__global__", null, 0);
3090
- let __local__ = kw_get_dict(publisher, subs, "__local__", null, 0);
3091
- let __filter__ = kw_get_dict_value(publisher, subs, "__filter__", null, 0);
3092
- let event_name = subs.renamed_event;
3093
- if (empty_string(event_name)) event_name = event;
3094
- let topublish = 1;
3095
- if (publisher.gclass.gmt.mt_publication_filter) topublish = publisher.gclass.gmt.mt_publication_filter(publisher, event, kw, subscriber);
3096
- else if (json_size(__filter__) > 0) {
3097
- topublish = kw_match_simple(kw, __filter__) ? 1 : 0;
3503
+ const frame = push_dispatch_frame(publisher, event, frame_kind_t.FRAME_PUBLICATION);
3504
+ try {
3505
+ for (let idx = 0; idx < dl_subs.length; idx++) {
3506
+ let subs = dl_subs[idx];
3507
+ if (publisher.gclass.gmt.mt_publication_pre_filter) {
3508
+ let topublish = publisher.gclass.gmt.mt_publication_pre_filter(publisher, subs, event, kw);
3509
+ if (topublish < 0) break;
3510
+ else if (!topublish) continue;
3511
+ }
3512
+ let subscriber = kw_get_pointer(publisher, subs, "subscriber", null, kw_flag_t.KW_REQUIRED);
3513
+ if (!(subscriber && !gobj_is_destroying(subscriber))) continue;
3514
+ let subs_flag = kw_get_int(publisher, subs, "subs_flag", 0, kw_flag_t.KW_REQUIRED);
3515
+ let event_ = kw_get_str(publisher, subs, "event", "", kw_flag_t.KW_REQUIRED);
3516
+ if (empty_string(event_) || strcasecmp(event_, event) === 0) {
3517
+ let __config__ = kw_get_dict(publisher, subs, "__config__", null, 0);
3518
+ let __global__ = kw_get_dict(publisher, subs, "__global__", null, 0);
3519
+ let __local__ = kw_get_dict(publisher, subs, "__local__", null, 0);
3520
+ let __filter__ = kw_get_dict_value(publisher, subs, "__filter__", null, 0);
3521
+ let event_name = subs.renamed_event;
3522
+ if (empty_string(event_name)) event_name = event;
3523
+ let topublish = 1;
3524
+ if (publisher.gclass.gmt.mt_publication_filter) topublish = publisher.gclass.gmt.mt_publication_filter(publisher, event, kw, subscriber);
3525
+ else if (json_size(__filter__) > 0) {
3526
+ topublish = kw_match_simple(kw, __filter__) ? 1 : 0;
3527
+ if (tracea) {
3528
+ trace_machine(sprintf("💜💜🔄%s publishing with filter, event '%s', subscriber'%s', publisher %s", topublish ? "👍" : "👎", event ? event : "", gobj_short_name(subscriber), gobj_short_name(publisher)));
3529
+ trace_json(__filter__);
3530
+ }
3531
+ }
3532
+ if (topublish < 0) break;
3533
+ else if (!topublish) continue;
3534
+ let ev_ = gobj_event_type(subscriber, event, true);
3535
+ if (ev_) {
3536
+ if (ev_.event_flag & event_flag_t.EVF_SYSTEM_EVENT) {
3537
+ if (!gobj_has_event(subscriber, ev_.event_name, 0)) continue;
3538
+ }
3539
+ }
3540
+ let kw2publish = kw;
3541
+ if (json_size(__local__) > 0 || json_size(__global__) > 0) kw2publish = json_object_update({}, kw);
3542
+ if (json_size(__local__) > 0) kw_pop(kw2publish, __local__);
3543
+ if (__config__) {}
3544
+ if (json_size(__global__) > 0) json_object_update(kw2publish, json_deep_copy(__global__));
3098
3545
  if (tracea) {
3099
- trace_machine(sprintf("💜💜🔄%s publishing with filter, event '%s', subscriber'%s', publisher %s", topublish ? "👍" : "👎", event ? event : "", gobj_short_name(subscriber), gobj_short_name(publisher)));
3100
- trace_json(__filter__);
3546
+ if (__trace_machine_format__ === 1) trace_machine(sprintf("🔝🔄 %s (%s) %s%s", event ? event : "", event_name ? event_name : "", !subscriber.running ? "!!" : "", gobj_short_name(subscriber)));
3547
+ else trace_machine(sprintf("🔝🔄 mach(%s%s), st: %s, ev: %s (%s), from(%s%s)", !subscriber.running ? "!!" : "", gobj_short_name(subscriber), gobj_current_state(subscriber), event ? event : "", event_name ? event_name : "", publisher && !publisher.running ? "!!" : "", gobj_short_name(publisher)));
3548
+ if (__trace_gobj_ev_kw__(publisher) && json_object_size(kw2publish)) trace_json_masked(kw2publish);
3101
3549
  }
3102
- }
3103
- if (topublish < 0) break;
3104
- else if (!topublish) continue;
3105
- let ev_ = gobj_event_type(subscriber, event, true);
3106
- if (ev_) {
3107
- if (ev_.event_flag & event_flag_t.EVF_SYSTEM_EVENT) {
3108
- if (!gobj_has_event(subscriber, ev_.event_name, 0)) continue;
3550
+ let ret_ = gobj_send_event(subscriber, event_name, kw2publish, publisher);
3551
+ if (ret_ < 0 && subs_flag & subs_flag_t.__own_event__) {
3552
+ sent_count = -1;
3553
+ break;
3109
3554
  }
3555
+ ret += ret_;
3556
+ sent_count++;
3557
+ if (frame.destroyed || gobj_is_destroying(publisher)) break;
3110
3558
  }
3111
- let kw2publish = kw;
3112
- if (json_size(__local__) > 0 || json_size(__global__) > 0) kw2publish = json_object_update({}, kw);
3113
- if (json_size(__local__) > 0) kw_pop(kw2publish, __local__);
3114
- if (__config__) {}
3115
- if (json_size(__global__) > 0) json_object_update(kw2publish, json_deep_copy(__global__));
3116
- if (tracea) {
3117
- if (__trace_machine_format__ === 1) trace_machine(sprintf("🔝🔄 %s (%s) %s%s", event ? event : "", event_name ? event_name : "", !subscriber.running ? "!!" : "", gobj_short_name(subscriber)));
3118
- else trace_machine(sprintf("🔝🔄 mach(%s%s), st: %s, ev: %s (%s), from(%s%s)", !subscriber.running ? "!!" : "", gobj_short_name(subscriber), gobj_current_state(subscriber), event ? event : "", event_name ? event_name : "", publisher && !publisher.running ? "!!" : "", gobj_short_name(publisher)));
3119
- if (__trace_gobj_ev_kw__(publisher) && json_object_size(kw2publish)) trace_json_masked(kw2publish);
3120
- }
3121
- let ret_ = gobj_send_event(subscriber, event_name, kw2publish, publisher);
3122
- if (ret_ < 0 && subs_flag & subs_flag_t.__own_event__) {
3123
- sent_count = -1;
3124
- break;
3125
- }
3126
- ret += ret_;
3127
- sent_count++;
3128
- if (gobj_is_destroying(publisher)) break;
3129
3559
  }
3560
+ } finally {
3561
+ pop_dispatch_frame(frame);
3130
3562
  }
3131
- if (!sent_count) {
3563
+ if (!sent_count && !frame.destroyed) {
3132
3564
  if (!ev || !(ev.event_flag & event_flag_t.EVF_NO_WARN_SUBS)) log_warning(`${gobj_short_name(publisher)}: Publish event WITHOUT subscribers, ev ${event}`);
3133
3565
  }
3134
3566
  return ret;
@@ -3437,12 +3869,12 @@ var gobjJs = (function(exports) {
3437
3869
  "sessionkey",
3438
3870
  "authdata"
3439
3871
  ];
3440
- var SECRET_NAME_SEGMENTS = /* @__PURE__ */ new Set([
3872
+ var SECRET_NAME_SEGMENTS = [
3441
3873
  "pass",
3442
3874
  "pin",
3443
3875
  "otp"
3444
- ]);
3445
- var NOT_SECRET_SEGMENTS = /* @__PURE__ */ new Set([
3876
+ ];
3877
+ var NOT_SECRET_SEGMENTS = [
3446
3878
  "endpoint",
3447
3879
  "url",
3448
3880
  "uri",
@@ -3465,36 +3897,130 @@ var gobjJs = (function(exports) {
3465
3897
  "expiry",
3466
3898
  "expires",
3467
3899
  "mode"
3468
- ]);
3900
+ ];
3901
+ function words_by_letter(list) {
3902
+ const by_letter = new Array(128).fill(null);
3903
+ for (const word of list) {
3904
+ const c = word.charCodeAt(0);
3905
+ if (!by_letter[c]) by_letter[c] = [];
3906
+ by_letter[c].push(word);
3907
+ }
3908
+ return by_letter;
3909
+ }
3910
+ var SECRET_PARTS_BY_LETTER = words_by_letter(SECRET_NAME_PARTS);
3911
+ var SECRET_JOINED_BY_LETTER = words_by_letter(SECRET_NAME_JOINED);
3912
+ var SECRET_SEGMENTS_BY_LETTER = words_by_letter(SECRET_NAME_SEGMENTS);
3913
+ var NOT_SECRET_BY_LETTER = words_by_letter(NOT_SECRET_SEGMENTS);
3914
+ function ascii_lower_code(code) {
3915
+ return code >= 65 && code <= 90 ? code + 32 : code;
3916
+ }
3917
+ function is_name_joiner_code(code) {
3918
+ return code === 95 || code === 45 || code === 46 || code === 32 || code === 9;
3919
+ }
3920
+ function name_segment_in(str, from, to, by_letter) {
3921
+ const n = to - from;
3922
+ if (n === 0) return false;
3923
+ const c0 = ascii_lower_code(str.charCodeAt(from));
3924
+ const words = c0 < 128 ? by_letter[c0] : null;
3925
+ if (!words) return false;
3926
+ for (let w = 0; w < words.length; w++) {
3927
+ const word = words[w];
3928
+ if (word.length !== n) continue;
3929
+ let i = 1;
3930
+ while (i < n && ascii_lower_code(str.charCodeAt(from + i)) === word.charCodeAt(i)) i++;
3931
+ if (i === n) return true;
3932
+ }
3933
+ return false;
3934
+ }
3935
+ function name_part_at(str, to, i, part, joined) {
3936
+ let j = i;
3937
+ let k = 0;
3938
+ while (k < part.length) {
3939
+ if (j >= to) return false;
3940
+ const code = str.charCodeAt(j);
3941
+ if (joined && k > 0 && is_name_joiner_code(code)) {
3942
+ j++;
3943
+ continue;
3944
+ }
3945
+ if (ascii_lower_code(code) !== part.charCodeAt(k)) return false;
3946
+ j++;
3947
+ k++;
3948
+ }
3949
+ return true;
3950
+ }
3951
+ function secret_name_check(str, from, to, about_wins, by_segments) {
3952
+ if (to - from < 3) return false;
3953
+ if (about_wins) {
3954
+ let seg = from;
3955
+ for (let i = from; i <= to; i++) {
3956
+ if (i < to && !is_name_joiner_code(str.charCodeAt(i))) continue;
3957
+ if (name_segment_in(str, seg, i, NOT_SECRET_BY_LETTER)) return false;
3958
+ seg = i + 1;
3959
+ }
3960
+ }
3961
+ if (by_segments) {
3962
+ let seg = from;
3963
+ for (let i = from; i <= to; i++) {
3964
+ if (i < to && is_ascii_alnum_code(str.charCodeAt(i))) continue;
3965
+ if (name_segment_in(str, seg, i, SECRET_SEGMENTS_BY_LETTER)) return true;
3966
+ seg = i + 1;
3967
+ }
3968
+ }
3969
+ let has_priv = false;
3970
+ let has_key = false;
3971
+ for (let i = from; i < to; i++) {
3972
+ const c = ascii_lower_code(str.charCodeAt(i));
3973
+ if (c >= 128) continue;
3974
+ const parts = SECRET_PARTS_BY_LETTER[c];
3975
+ for (let k = 0; parts && k < parts.length; k++) if (name_part_at(str, to, i, parts[k], false)) return true;
3976
+ const joined = SECRET_JOINED_BY_LETTER[c];
3977
+ for (let k = 0; joined && k < joined.length; k++) if (name_part_at(str, to, i, joined[k], true)) return true;
3978
+ if (c === 112 && !has_priv) has_priv = name_part_at(str, to, i, "priv", false);
3979
+ else if (c === 107 && !has_key) has_key = name_part_at(str, to, i, "key", false);
3980
+ }
3981
+ return has_priv && has_key;
3982
+ }
3469
3983
  /************************************************************
3470
3984
  * TRUE if `name` is the name of a secret: a password, a token,
3471
3985
  * a key... Any case. As the C kernel's is_secret_name().
3472
3986
  ************************************************************/
3473
3987
  function is_secret_name(name) {
3474
- if (typeof name !== "string" || name.length < 3) return false;
3475
- let lower = name.toLowerCase();
3476
- let hit = false;
3477
- for (const segment of lower.split(/[^a-z0-9]+/)) if (SECRET_NAME_SEGMENTS.has(segment)) {
3478
- hit = true;
3479
- break;
3480
- }
3481
- if (!hit) {
3482
- for (const part of SECRET_NAME_PARTS) if (lower.indexOf(part) >= 0) {
3483
- hit = true;
3484
- break;
3988
+ if (typeof name !== "string") return false;
3989
+ return secret_name_check(name, 0, name.length, true, true);
3990
+ }
3991
+ var NAMES_NOW = 0;
3992
+ var NAMES_7_26_9 = 1;
3993
+ function is_secret_name_tail(str, from, to, names) {
3994
+ const by_segments = names === NAMES_NOW;
3995
+ if ((to - from) * 3 <= MASK_MAX_NAME) return secret_name_check(str, from, to, true, by_segments);
3996
+ let bytes = 0;
3997
+ let i = to;
3998
+ let partial = false;
3999
+ while (i > from) {
4000
+ const code = str.charCodeAt(i - 1);
4001
+ let n = 3;
4002
+ let units = 1;
4003
+ if (code < 128) n = 1;
4004
+ else if (code < 2048) n = 2;
4005
+ else if (code >= 56320 && code <= 57343 && i - 2 >= from) {
4006
+ const high = str.charCodeAt(i - 2);
4007
+ if (high >= 55296 && high <= 56319) {
4008
+ n = 4;
4009
+ units = 2;
4010
+ }
3485
4011
  }
3486
- }
3487
- if (!hit) {
3488
- let joined = lower.replace(/[_\-. \t]/g, "");
3489
- for (const part of SECRET_NAME_JOINED) if (joined.indexOf(part) >= 0) {
3490
- hit = true;
4012
+ if (bytes + n > MASK_MAX_NAME) {
4013
+ partial = bytes < MASK_MAX_NAME;
3491
4014
  break;
3492
4015
  }
4016
+ bytes += n;
4017
+ i -= units;
3493
4018
  }
3494
- if (!hit) hit = lower.indexOf("priv") >= 0 && lower.indexOf("key") >= 0;
3495
- if (!hit) return false;
3496
- for (const segment of lower.split(/[_\-. \t]/)) if (NOT_SECRET_SEGMENTS.has(segment)) return false;
3497
- return true;
4019
+ if (partial) {
4020
+ const name = "€" + str.substring(i, to);
4021
+ return secret_name_check(name, 0, name.length, true, by_segments);
4022
+ }
4023
+ return secret_name_check(str, i, to, true, by_segments);
3498
4024
  }
3499
4025
  /************************************************************
3500
4026
  * Where an unquoted secret value that begins at `p` ends: at
@@ -3522,77 +4048,255 @@ var gobjJs = (function(exports) {
3522
4048
  }
3523
4049
  /************************************************************
3524
4050
  * 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
- ************************************************************/
4051
+ * jwt_len() / scheme_credential(), the shapes the agent's audit
4052
+ * record redacts, and the schemes of an HTTP Authorization:
4053
+ * - a JWT or a JWE: "eyJ" (the base64url of '{"') at the start
4054
+ * of a word, base64url, and a '.' of its own after it -- three
4055
+ * parts joined by '.' (a JWS), five (a JWE), or fewer when a cap
4056
+ * cut it; the dots at the end of the run are not its own (a JWT
4057
+ * ends a sentence: "... eyJ.eyJ.sig."), so a run whose only
4058
+ * dots end it is a header and no JWT ("eyJhIjoxfQ.");
4059
+ * - the credential after the scheme word "Bearer" or "Basic"
4060
+ * (any case, a word of its own): scheme_credential().
4061
+ ************************************************************/
4062
+ var MASK_TOKEN_MIN = 8;
4063
+ var MASK_PROSE_MAX = 24;
3533
4064
  function is_ascii_alnum_code(code) {
3534
4065
  return code >= 48 && code <= 57 || code >= 65 && code <= 90 || code >= 97 && code <= 122;
3535
4066
  }
4067
+ function is_ascii_letter_code(code) {
4068
+ return code >= 65 && code <= 90 || code >= 97 && code <= 122;
4069
+ }
4070
+ function is_ascii_upper_code(code) {
4071
+ return code >= 65 && code <= 90;
4072
+ }
3536
4073
  function is_base64url_code(code) {
3537
4074
  return is_ascii_alnum_code(code) || code === 45 || code === 95;
3538
4075
  }
4076
+ function ascii_case_equal(str, p, word) {
4077
+ if (str.length - p < word.length) return false;
4078
+ for (let i = 0; i < word.length; i++) {
4079
+ let code = str.charCodeAt(p + i);
4080
+ if (code >= 65 && code <= 90) code += 32;
4081
+ if (code !== word.charCodeAt(i)) return false;
4082
+ }
4083
+ return true;
4084
+ }
3539
4085
  function jwt_len(str, p) {
3540
4086
  if (str.length - p < 3 || str[p] !== "e" || str[p + 1] !== "y" || str[p + 2] !== "J") return 0;
3541
4087
  if (p > 0 && (is_base64url_code(str.charCodeAt(p - 1)) || str[p - 1] === ".")) return 0;
3542
4088
  let e = p;
3543
- let dots = 0;
4089
+ let dotted = false;
3544
4090
  while (e < str.length && (is_base64url_code(str.charCodeAt(e)) || str[e] === ".")) {
3545
- if (str[e] === ".") dots++;
4091
+ if (e > p && str[e] !== "." && str[e - 1] === ".") dotted = true;
3546
4092
  e++;
3547
4093
  }
3548
- while (str[e - 1] === ".") {
3549
- e--;
3550
- dots--;
4094
+ if (!dotted) return 0;
4095
+ while (str[e - 1] === ".") e--;
4096
+ return e - p;
4097
+ }
4098
+ function scheme_word_len(str, p) {
4099
+ if (p > 0 && is_ascii_alnum_code(str.charCodeAt(p - 1))) return 0;
4100
+ for (const scheme of ["bearer", "basic"]) {
4101
+ const n = scheme.length;
4102
+ if (str.length - p > n && ascii_case_equal(str, p, scheme) && (str[p + n] === " " || str[p + n] === " ")) return n;
4103
+ }
4104
+ return 0;
4105
+ }
4106
+ function code_points(str, w, n) {
4107
+ let count = 0;
4108
+ for (let i = w; i < w + n; i++) {
4109
+ const code = str.charCodeAt(i);
4110
+ if (code < 56320 || code > 57343) count++;
4111
+ }
4112
+ return count;
4113
+ }
4114
+ function is_prose_word(str, w, n) {
4115
+ if (n === 0 || n >= MASK_PROSE_MAX) return false;
4116
+ let i = w;
4117
+ const end = w + n;
4118
+ while (true) {
4119
+ let r = i;
4120
+ let upper_rest = true;
4121
+ let lower_rest = true;
4122
+ while (r < end && is_ascii_letter_code(str.charCodeAt(r))) {
4123
+ if (r > i) {
4124
+ if (is_ascii_upper_code(str.charCodeAt(r))) lower_rest = false;
4125
+ else upper_rest = false;
4126
+ }
4127
+ r++;
4128
+ }
4129
+ if (r === i) return false;
4130
+ if (!lower_rest && !(upper_rest && is_ascii_upper_code(str.charCodeAt(i)))) return false;
4131
+ if (r === end) return true;
4132
+ if (str[r] !== "-" && str[r] !== "." && str[r] !== "/" || r + 1 === end) return false;
4133
+ i = r + 1;
4134
+ }
4135
+ }
4136
+ function base64_digit(code) {
4137
+ if (code >= 65 && code <= 90) return code - 65;
4138
+ if (code >= 97 && code <= 122) return code - 97 + 26;
4139
+ if (code >= 48 && code <= 57) return code - 48 + 52;
4140
+ if (code === 43) return 62;
4141
+ if (code === 47) return 63;
4142
+ return -1;
4143
+ }
4144
+ function is_basic_credential(str, w, n) {
4145
+ let bits = 0;
4146
+ let n_bits = 0;
4147
+ for (let i = 0; i < n; i++) {
4148
+ const v = base64_digit(str.charCodeAt(w + i));
4149
+ if (v < 0) return false;
4150
+ bits = (bits << 6 | v) & 16383;
4151
+ n_bits += 6;
4152
+ if (n_bits >= 8) {
4153
+ n_bits -= 8;
4154
+ if ((bits >> n_bits & 255) === 58) return true;
4155
+ }
3551
4156
  }
3552
- return dots === 2 ? e - p : 0;
4157
+ return false;
3553
4158
  }
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];
4159
+ var SCHEME_WORD_STOPS = " \r\n\"',;}]\0";
4160
+ function scheme_credential(str, p) {
4161
+ const n = scheme_word_len(str, p);
4162
+ if (!n) return [0, 0];
4163
+ const scheme = n === 5 ? "basic" : "bearer";
4164
+ let context = false;
4165
+ let t = p + n;
3561
4166
  while (t < str.length && (str[t] === " " || str[t] === " ")) t++;
4167
+ if (t < str.length && scheme_word_len(str, t) === n && ascii_case_equal(str, t, scheme)) {
4168
+ t += n;
4169
+ context = true;
4170
+ while (t < str.length && (str[t] === " " || str[t] === " ")) t++;
4171
+ }
4172
+ if (t >= str.length) return [0, 0];
4173
+ if (str[t] === "\"" || str[t] === "'") {
4174
+ let q = t + 1;
4175
+ while (q < str.length && str[q] !== str[t] && str[q] !== " " && str[q] !== " " && str[q] !== "\r" && str[q] !== "\n" && str[q] !== "\0") q++;
4176
+ if (q < str.length && str[q] === str[t] && q > t + 1) return [t - p, q + 1 - t];
4177
+ return [0, 0];
4178
+ }
3562
4179
  let e = t;
3563
- while (e < str.length && BEARER_STOPS.indexOf(str[e]) < 0) e++;
4180
+ while (e < str.length && SCHEME_WORD_STOPS.indexOf(str[e]) < 0) e++;
4181
+ if (e === t) return [0, 0];
4182
+ if (!context) {
4183
+ let w_end = e;
4184
+ while (w_end > t && str[w_end - 1] === ".") w_end--;
4185
+ const len = w_end - t;
4186
+ if (len === 0 || is_prose_word(str, t, len)) return [0, 0];
4187
+ if (n === 5) {
4188
+ if (!is_basic_credential(str, t, len)) return [0, 0];
4189
+ } else if (code_points(str, t, len) < MASK_TOKEN_MIN) return [0, 0];
4190
+ }
3564
4191
  return [t - p, e - t];
3565
4192
  }
3566
- /************************************************************
3567
- * A text (a command line) with the value of every "name=value"
3568
- * whose name is a secret's written as "********", quoted or not
3569
- * (and the "value" of a write-attr whose attribute names a
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().
3574
- ************************************************************/
4193
+ function shape_len(str, p) {
4194
+ const c = str[p];
4195
+ if (c === "e") return [0, jwt_len(str, p)];
4196
+ if (c === "b" || c === "B") return scheme_credential(str, p);
4197
+ return [0, 0];
4198
+ }
4199
+ function shape_len_js_7_26_20(str, p) {
4200
+ const c = str[p];
4201
+ if (c === "e") {
4202
+ if (str.length - p < 3 || str[p + 1] !== "y" || str[p + 2] !== "J") return [0, 0];
4203
+ if (p > 0 && (is_base64url_code(str.charCodeAt(p - 1)) || str[p - 1] === ".")) return [0, 0];
4204
+ let e = p;
4205
+ let dots = 0;
4206
+ while (e < str.length && (is_base64url_code(str.charCodeAt(e)) || str[e] === ".")) {
4207
+ if (str[e] === ".") dots++;
4208
+ e++;
4209
+ }
4210
+ while (str[e - 1] === ".") {
4211
+ e--;
4212
+ dots--;
4213
+ }
4214
+ return dots === 2 ? [0, e - p] : [0, 0];
4215
+ }
4216
+ if (c === "b" || c === "B") {
4217
+ if (str.length - p <= 6 || !ascii_case_equal(str, p, "bearer")) return [0, 0];
4218
+ if (p > 0 && is_ascii_alnum_code(str.charCodeAt(p - 1))) return [0, 0];
4219
+ let t = p + 6;
4220
+ if (str[t] !== " " && str[t] !== " ") return [0, 0];
4221
+ while (t < str.length && (str[t] === " " || str[t] === " ")) t++;
4222
+ let e = t;
4223
+ while (e < str.length && " \r\n'\",;}]\0".indexOf(str[e]) < 0) e++;
4224
+ return [t - p, e - t];
4225
+ }
4226
+ return [0, 0];
4227
+ }
4228
+ var COLON_VALUE_STOPS = " \r\n,;&)]}<>\"'\0";
4229
+ function colon_value_end(str, v) {
4230
+ if (v >= str.length) return v;
4231
+ const c = str[v];
4232
+ if (c === "\"" || c === "'") {
4233
+ let e = v + 1;
4234
+ while (e < str.length && str[e] !== c) {
4235
+ if (str[e] === "\\" && e + 1 < str.length) e++;
4236
+ e++;
4237
+ }
4238
+ return e < str.length ? e + 1 : str.length;
4239
+ }
4240
+ if (c === "{" || c === "[") {
4241
+ let depth = 0;
4242
+ let in_string = false;
4243
+ for (let e = v; e < str.length; e++) if (in_string) {
4244
+ if (str[e] === "\\" && e + 1 < str.length) e++;
4245
+ else if (str[e] === "\"") in_string = false;
4246
+ } else if (str[e] === "\"") in_string = true;
4247
+ else if (str[e] === "{" || str[e] === "[") depth++;
4248
+ else if (str[e] === "}" || str[e] === "]") {
4249
+ depth--;
4250
+ if (depth === 0) return e + 1;
4251
+ }
4252
+ return str.length;
4253
+ }
4254
+ if (c === "\\") {
4255
+ let q = v;
4256
+ while (q < str.length && str[q] === "\\") q++;
4257
+ if (q < str.length && (str[q] === "\"" || str[q] === "'")) {
4258
+ const level = q - v;
4259
+ let run = 0;
4260
+ for (let e = q + 1; e < str.length; e++) {
4261
+ if (str[e] === "\\") {
4262
+ run++;
4263
+ continue;
4264
+ }
4265
+ if (str[e] === str[q] && run === level) return e + 1;
4266
+ run = 0;
4267
+ }
4268
+ return str.length;
4269
+ }
4270
+ }
4271
+ let e = v;
4272
+ const n = scheme_word_len(str, v);
4273
+ if (n) {
4274
+ e = v + n;
4275
+ while (e < str.length && (str[e] === " " || str[e] === " ")) e++;
4276
+ if (e < str.length && (str[e] === "\"" || str[e] === "'")) return colon_value_end(str, e);
4277
+ }
4278
+ while (e < str.length && COLON_VALUE_STOPS.indexOf(str[e]) < 0) e++;
4279
+ return e;
4280
+ }
3575
4281
  var MASK_MAX_NAME = 128;
3576
4282
  var MASK_MAX_BYTES = 4194304;
3577
4283
  var MASK_TOO_LARGE = "<not shown: too large to mask>";
3578
- function mask_secrets_inline(str) {
3579
- if (typeof str !== "string") return null;
3580
- if (str.indexOf("=") < 0 && str.indexOf("eyJ") < 0 && !/bearer/i.test(str)) return null;
3581
- if (str.length > MASK_MAX_BYTES) return MASK_TOO_LARGE;
3582
- let value_is_secret = false;
3583
- let re_attr = /(^|[ \t])attribute=["']?([^ \t"']*)/g;
3584
- let m;
3585
- while ((m = re_attr.exec(str)) !== null) if (is_secret_name(m[2].slice(-128))) value_is_secret = true;
3586
- let parts = [];
3587
- let copied = 0;
3588
- let changed = false;
4284
+ function mark_range(marks, from, to) {
4285
+ for (let i = from; i < to; i++) marks[i] = 1;
4286
+ }
4287
+ var READ_NOW = 0;
4288
+ var READ_AS_GOBJ_JS_7_26_20 = 1;
4289
+ var READ_AS_7_26_9 = 2;
4290
+ function mark_params(str, value_is_secret, reading, marks, judged) {
4291
+ const names = reading === READ_AS_7_26_9 ? NAMES_7_26_9 : NAMES_NOW;
4292
+ let not_7_26_9 = false;
4293
+ const is_blank_or_end = (i) => i >= str.length || str[i] === " " || str[i] === " " || str[i] === "\0";
3589
4294
  let outer = "";
3590
4295
  let word = 0;
3591
4296
  let p = 0;
3592
- const is_blank_or_end = (i) => i >= str.length || str[i] === " " || str[i] === " ";
3593
4297
  while (p < str.length) {
3594
- let c = str[p];
3595
- if (c === " " || c === " ") {
4298
+ const c = str[p];
4299
+ if (c === " " || c === " " || c === "\0") {
3596
4300
  p++;
3597
4301
  word = p;
3598
4302
  continue;
@@ -3601,48 +4305,205 @@ var gobjJs = (function(exports) {
3601
4305
  if (!outer && (p === 0 || str[p - 1] === " " || str[p - 1] === " " || str[p - 1] === "=")) outer = c;
3602
4306
  else if (c === outer && is_blank_or_end(p + 1)) outer = "";
3603
4307
  }
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;
4308
+ if (reading === READ_AS_GOBJ_JS_7_26_20 && (c === "e" || c === "b" || c === "B")) {
4309
+ const [offset, n] = shape_len_js_7_26_20(str, p);
4310
+ if (n) {
4311
+ p += offset + n;
4312
+ word = p;
4313
+ continue;
4314
+ }
3615
4315
  }
3616
4316
  if (c !== "=") {
3617
4317
  p++;
3618
4318
  continue;
3619
4319
  }
3620
- let name = str.substring(Math.max(word, p - MASK_MAX_NAME), p);
4320
+ const name_from = word;
3621
4321
  word = p + 1;
3622
- if (!(is_secret_name(name) || value_is_secret && name.toLowerCase() === "value")) {
4322
+ const secret = is_secret_name_tail(str, name_from, p, names);
4323
+ if (secret && names === NAMES_NOW && !is_secret_name_tail(str, name_from, p, NAMES_7_26_9)) not_7_26_9 = true;
4324
+ if (!(secret || value_is_secret && p - name_from === 5 && ascii_case_equal(str, name_from, "value"))) {
4325
+ if (judged && query_name_from(str, p) === name_from) judged[p] = 1;
3623
4326
  p++;
3624
4327
  continue;
3625
4328
  }
3626
4329
  p++;
3627
- let quote = str[p] === "\"" || str[p] === "'" ? str[p] : "";
3628
4330
  let end;
4331
+ const quote = p < str.length && (str[p] === "\"" || str[p] === "'") ? str[p] : "";
3629
4332
  if (quote) {
3630
4333
  end = p + 1;
3631
- while (end < str.length && str[end] !== quote) end++;
3632
- if (str[end] === quote) end++;
4334
+ while (end < str.length && str[end] !== quote && str[end] !== "\0") end++;
4335
+ if (end < str.length && str[end] === quote) end++;
3633
4336
  } else end = inline_secret_value_end(str, p, outer);
3634
- if (end > p) {
3635
- parts.push(str.substring(copied, p));
4337
+ mark_range(marks, p, end);
4338
+ p = end;
4339
+ word = p;
4340
+ }
4341
+ return not_7_26_9;
4342
+ }
4343
+ function has_shape_js_7_26_20(str) {
4344
+ for (let p = 0; p < str.length; p++) {
4345
+ const code = str.charCodeAt(p);
4346
+ if ((code === 101 || code === 98 || code === 66) && shape_len_js_7_26_20(str, p)[1]) return true;
4347
+ }
4348
+ return false;
4349
+ }
4350
+ function stop_table(chars) {
4351
+ const table = /* @__PURE__ */ new Uint8Array(128);
4352
+ for (const c of chars + "\r\n\0") table[c.charCodeAt(0)] = 1;
4353
+ return table;
4354
+ }
4355
+ var PARAM_VALUE_STOPS = stop_table("&; ,\"'<>");
4356
+ var QUOTE_STOPS = {
4357
+ "\"": stop_table("\""),
4358
+ "'": stop_table("'")
4359
+ };
4360
+ function mark_run(str, p, stops, marks) {
4361
+ let e = p;
4362
+ while (e < str.length) {
4363
+ const code = str.charCodeAt(e);
4364
+ if (code < 128 && stops[code]) break;
4365
+ e++;
4366
+ }
4367
+ mark_range(marks, p, e);
4368
+ return e;
4369
+ }
4370
+ function mark_scheme_value(str, v, stops, marks) {
4371
+ const n = scheme_word_len(str, v);
4372
+ if (!n) return -1;
4373
+ let w = v + n;
4374
+ while (w < str.length && (str[w] === " " || str[w] === " ")) w++;
4375
+ mark_range(marks, v, w);
4376
+ if (w < str.length && (str[w] === "\"" || str[w] === "'")) {
4377
+ const e = colon_value_end(str, w);
4378
+ mark_range(marks, w, e);
4379
+ return e;
4380
+ }
4381
+ return mark_run(str, w, stops, marks);
4382
+ }
4383
+ function is_name_char_code(code) {
4384
+ return is_ascii_alnum_code(code) || code === 95 || code === 45 || code === 46;
4385
+ }
4386
+ function query_name_from(str, eq) {
4387
+ let n = eq;
4388
+ while (n > 0 && eq - n < MASK_MAX_NAME && is_name_char_code(str.charCodeAt(n - 1))) n--;
4389
+ return n;
4390
+ }
4391
+ function mark_query_params(str, marks, judged) {
4392
+ let frontier = 0;
4393
+ for (let p = 1; p < str.length; p++) {
4394
+ if (p < frontier) {
4395
+ p = frontier - 1;
4396
+ continue;
4397
+ }
4398
+ if (str.charCodeAt(p) !== 61) continue;
4399
+ if (judged[p]) continue;
4400
+ const n = query_name_from(str, p);
4401
+ if (n === p || !secret_name_check(str, n, p, true, true)) continue;
4402
+ const v = p + 1;
4403
+ if (v < str.length && (str[v] === "\"" || str[v] === "'")) frontier = mark_run(str, v + 1, QUOTE_STOPS[str[v]], marks);
4404
+ else {
4405
+ mark_scheme_value(str, v, PARAM_VALUE_STOPS, marks);
4406
+ frontier = mark_run(str, v, PARAM_VALUE_STOPS, marks);
4407
+ }
4408
+ }
4409
+ }
4410
+ function mark_shapes(str, marks) {
4411
+ for (let p = 0; p < str.length; p++) {
4412
+ const code = str.charCodeAt(p);
4413
+ if (code !== 101 && code !== 98 && code !== 66) continue;
4414
+ const [offset, n] = shape_len(str, p);
4415
+ if (n) mark_range(marks, p + offset, p + offset + n);
4416
+ }
4417
+ }
4418
+ function mark_labels(str, marks) {
4419
+ let word = 0;
4420
+ let p = 0;
4421
+ while (p < str.length) {
4422
+ const code = str.charCodeAt(p);
4423
+ if (code === 32 || code === 9 || code === 0 || code === 61) {
4424
+ p++;
4425
+ word = p;
4426
+ continue;
4427
+ }
4428
+ if (code !== 58) {
4429
+ p++;
4430
+ continue;
4431
+ }
4432
+ if (!is_secret_name_tail(str, word, p, NAMES_NOW)) {
4433
+ p++;
4434
+ word = p;
4435
+ continue;
4436
+ }
4437
+ let v = p + 1;
4438
+ while (v < str.length && (str[v] === " " || str[v] === " ")) v++;
4439
+ const e = colon_value_end(str, v);
4440
+ mark_range(marks, v, e);
4441
+ const n_scheme = scheme_word_len(str, v);
4442
+ if (n_scheme) p = v + n_scheme;
4443
+ else p = e > v ? e : p + 1;
4444
+ word = p;
4445
+ }
4446
+ }
4447
+ function inline_value_is_secret(str, names) {
4448
+ let p = str.indexOf("attribute=");
4449
+ while (p >= 0) {
4450
+ if (p === 0 || str[p - 1] === " " || str[p - 1] === " ") {
4451
+ let v = p + 10;
4452
+ if (v < str.length && (str[v] === "\"" || str[v] === "'")) v++;
4453
+ let e = v;
4454
+ while (e < str.length && " \"'\0".indexOf(str[e]) < 0) e++;
4455
+ if (is_secret_name_tail(str, v, e, names)) return true;
4456
+ }
4457
+ p = str.indexOf("attribute=", p + 1);
4458
+ }
4459
+ return false;
4460
+ }
4461
+ function mark_inline_secrets(str, marks) {
4462
+ const value_is_secret = inline_value_is_secret(str, NAMES_NOW);
4463
+ const value_is_secret_7_26_9 = inline_value_is_secret(str, NAMES_7_26_9);
4464
+ const judged = new Uint8Array(str.length);
4465
+ if (mark_params(str, value_is_secret, READ_NOW, marks, judged) || value_is_secret !== value_is_secret_7_26_9) mark_params(str, value_is_secret_7_26_9, READ_AS_7_26_9, marks, null);
4466
+ if (has_shape_js_7_26_20(str)) mark_params(str, value_is_secret, READ_AS_GOBJ_JS_7_26_20, marks, null);
4467
+ mark_query_params(str, marks, judged);
4468
+ mark_shapes(str, marks);
4469
+ mark_labels(str, marks);
4470
+ }
4471
+ /************************************************************
4472
+ * A text (a command line) with the secrets that can be told
4473
+ * written as "********" (each run of them as one), the rest as it
4474
+ * is: the value of every "name=value" whose name is a secret's,
4475
+ * quoted or not (and the "value" of a write-attr whose attribute
4476
+ * names a secret) -- the name is the word before the '=', and also
4477
+ * the run of name characters before it, as in a query string; the
4478
+ * same for a "name: value", its name in quotes or not (a json, a
4479
+ * header, a label: "password": x, Authorization: Basic x, bearer:
4480
+ * tok); and a JWT or the credential after "Bearer " or "Basic ",
4481
+ * wherever they are, whatever names them. Each rule judges the text
4482
+ * as it came. Return null when there was nothing to mask. As the C
4483
+ * kernel's mask_secrets_inline().
4484
+ ************************************************************/
4485
+ function mask_secrets_inline(str) {
4486
+ if (typeof str !== "string") return null;
4487
+ if (str.indexOf("=") < 0 && str.indexOf(":") < 0 && str.indexOf("eyJ") < 0 && !/bearer|basic/i.test(str)) return null;
4488
+ if (str.length > MASK_MAX_BYTES) return MASK_TOO_LARGE;
4489
+ const marks = new Uint8Array(str.length);
4490
+ mark_inline_secrets(str, marks);
4491
+ let parts = [];
4492
+ let changed = false;
4493
+ let i = 0;
4494
+ while (i < str.length) {
4495
+ let j = i;
4496
+ if (marks[i]) {
4497
+ while (j < str.length && marks[j]) j++;
3636
4498
  parts.push("********");
3637
- copied = end;
3638
4499
  changed = true;
4500
+ } else {
4501
+ while (j < str.length && !marks[j]) j++;
4502
+ parts.push(str.substring(i, j));
3639
4503
  }
3640
- p = end;
3641
- word = p;
4504
+ i = j;
3642
4505
  }
3643
- if (!changed) return null;
3644
- parts.push(str.substring(copied));
3645
- return parts.join("");
4506
+ return changed ? parts.join("") : null;
3646
4507
  }
3647
4508
  /************************************************************
3648
4509
  * A json as a log or a trace may show it: at any depth, the
@@ -3710,7 +4571,12 @@ var gobjJs = (function(exports) {
3710
4571
  if (truncated) result.push(MASK_TOO_LARGE);
3711
4572
  } else {
3712
4573
  result = Object.create(Object.getPrototypeOf(jn));
3713
- let value_is_secret = typeof jn.attribute === "string" && is_secret_name(jn.attribute.slice(-128));
4574
+ let value_is_secret = false;
4575
+ if (typeof jn.attribute === "string") {
4576
+ let nul = jn.attribute.indexOf("\0");
4577
+ let attribute = nul >= 0 ? jn.attribute.substring(0, nul) : jn.attribute;
4578
+ value_is_secret = is_secret_name_tail(attribute, 0, attribute.length, NAMES_NOW);
4579
+ }
3714
4580
  for (const key in jn) {
3715
4581
  if (!Object.prototype.hasOwnProperty.call(jn, key)) continue;
3716
4582
  if (budget.left <= 0) {
@@ -3720,7 +4586,7 @@ var gobjJs = (function(exports) {
3720
4586
  budget.left -= 1 + key.length;
3721
4587
  let value = jn[key];
3722
4588
  let shown;
3723
- if ((is_secret_name(key.slice(-128)) || value_is_secret && key === "value") && value !== void 0 && value !== null && value !== "") shown = "********";
4589
+ if ((is_secret_name_tail(key, 0, key.length, NAMES_NOW) || value_is_secret && key === "value") && value !== void 0 && value !== null && value !== "") shown = "********";
3724
4590
  else shown = _json_mask_secrets(value, memo, depth + 1, budget);
3725
4591
  if (shown !== value) changed = true;
3726
4592
  set_own_key(result, key, shown);
@@ -6869,8 +7735,12 @@ var gobjJs = (function(exports) {
6869
7735
  ***************************************************************/
6870
7736
  function mt_create$2(gobj) {
6871
7737
  let priv = gobj.priv;
6872
- const subscriber = gobj_read_pointer_attr(gobj, "subscriber");
7738
+ let subscriber = gobj_read_pointer_attr(gobj, "subscriber");
6873
7739
  if (subscriber) gobj_subscribe_event(gobj, null, {}, subscriber);
7740
+ else if (gobj_is_pure_child(gobj)) {
7741
+ subscriber = gobj_parent(gobj);
7742
+ gobj_subscribe_event(gobj, null, {}, subscriber);
7743
+ }
6874
7744
  priv.periodic = gobj_read_bool_attr(gobj, "periodic");
6875
7745
  priv.msec = gobj_read_integer_attr(gobj, "msec");
6876
7746
  }
@@ -6927,8 +7797,7 @@ var gobjJs = (function(exports) {
6927
7797
  gobj_send_event(gobj, "EV_TIMEOUT", {}, gobj);
6928
7798
  }, priv.msec);
6929
7799
  else priv.timer_id = -1;
6930
- if (gobj_is_pure_child(gobj)) gobj_send_event(gobj_parent(gobj), ev, {}, gobj);
6931
- else gobj_publish_event(gobj, ev, {});
7800
+ gobj_publish_event(gobj, ev, {});
6932
7801
  if (!priv.periodic && priv.timer_id === -1) {
6933
7802
  if (gobj_is_running(gobj)) gobj_stop(gobj);
6934
7803
  }
@@ -6975,6 +7844,15 @@ var gobjJs = (function(exports) {
6975
7844
  * Helpers
6976
7845
  ***************************/
6977
7846
  /***************************************************************************
7847
+ * A number of milliseconds as the integer `msec` holds it: C takes an
7848
+ * integer, and a time computed in JS can carry a float error (0.3 * 1000
7849
+ * is 300.00000000000006, which an integer attr refuses). Anything that is
7850
+ * not a number goes as it is, to be refused loudly by the attr.
7851
+ ***************************************************************************/
7852
+ function whole_msec(msec) {
7853
+ return typeof msec === "number" && Number.isFinite(msec) ? Math.round(msec) : msec;
7854
+ }
7855
+ /***************************************************************************
6978
7856
  * Set timeout
6979
7857
  ***************************************************************************/
6980
7858
  function set_timeout(gobj, msec) {
@@ -6987,7 +7865,7 @@ var gobjJs = (function(exports) {
6987
7865
  return -1;
6988
7866
  }
6989
7867
  gobj_write_bool_attr(gobj, "periodic", false);
6990
- gobj_write_integer_attr(gobj, "msec", msec);
7868
+ gobj_write_integer_attr(gobj, "msec", whole_msec(msec));
6991
7869
  }
6992
7870
  /***************************************************************************
6993
7871
  * Set periodic timeout
@@ -7002,7 +7880,7 @@ var gobjJs = (function(exports) {
7002
7880
  return -1;
7003
7881
  }
7004
7882
  gobj_write_bool_attr(gobj, "periodic", true);
7005
- gobj_write_integer_attr(gobj, "msec", msec);
7883
+ gobj_write_integer_attr(gobj, "msec", whole_msec(msec));
7006
7884
  }
7007
7885
  /***************************************************************************
7008
7886
  * Clear timeout
@@ -7389,8 +8267,12 @@ var gobjJs = (function(exports) {
7389
8267
  gobj_write_str_attr(gobj, "wanted_yuno_name", priv.remote_yuno_name);
7390
8268
  gobj_write_str_attr(gobj, "wanted_yuno_role", priv.remote_yuno_role);
7391
8269
  gobj_write_str_attr(gobj, "wanted_yuno_service", priv.remote_yuno_service);
7392
- const subscriber = gobj_read_pointer_attr(gobj, "subscriber");
8270
+ let subscriber = gobj_read_pointer_attr(gobj, "subscriber");
7393
8271
  if (subscriber) gobj_subscribe_event(gobj, null, {}, subscriber);
8272
+ else if (gobj_is_pure_child(gobj)) {
8273
+ subscriber = gobj_parent(gobj);
8274
+ gobj_subscribe_event(gobj, null, {}, subscriber);
8275
+ }
7394
8276
  }
7395
8277
  /***************************************************************
7396
8278
  * Framework Method: Writing
@@ -7615,6 +8497,27 @@ var gobjJs = (function(exports) {
7615
8497
  }
7616
8498
  }
7617
8499
  /***************************************************************
8500
+ * A text of the server -- a frame, the name of an event, of a
8501
+ * service, of a role -- as a log shows it: masked, then capped on a
8502
+ * whole character (capped first, a credential the cap cut would
8503
+ * show its first characters). As the C kernel shows the name of an
8504
+ * event that is not public (mask_secrets_inline_capped()).
8505
+ ***************************************************************/
8506
+ var PEER_NAME_SHOWN = 64;
8507
+ var PEER_FRAME_SHOWN = 256;
8508
+ function peer_text_shown(text, max) {
8509
+ let s = String(text);
8510
+ let masked = mask_secrets_inline(s);
8511
+ if (masked !== null) s = masked;
8512
+ if (s.length > max) {
8513
+ let n = max;
8514
+ let code = s.charCodeAt(n);
8515
+ if (code >= 56320 && code <= 57343) n--;
8516
+ s = s.substring(0, n);
8517
+ }
8518
+ return s;
8519
+ }
8520
+ /***************************************************************
7618
8521
  * Trace intra event
7619
8522
  ***************************************************************/
7620
8523
  function trace_inter_event(gobj, prefix, iev) {
@@ -7737,7 +8640,8 @@ var gobjJs = (function(exports) {
7737
8640
  try {
7738
8641
  x = JSON.parse(data);
7739
8642
  } catch (e) {
7740
- log_warning(`${gobj_short_name(gobj)}: parsing inter_event json: ${e}`);
8643
+ let at = /position (\d+)/.exec(String(e && e.message));
8644
+ log_warning(`${gobj_short_name(gobj)}: parsing inter_event json: frame is not json${at ? ", at position " + at[1] : ""}, ${String(data).length} characters`);
7741
8645
  return null;
7742
8646
  }
7743
8647
  if (!(x instanceof Object)) {
@@ -7822,7 +8726,7 @@ var gobjJs = (function(exports) {
7822
8726
  let url = kw.url;
7823
8727
  if (kw.ws_seq !== void 0 && kw.ws_seq !== priv.ws_seq) return 0;
7824
8728
  set_remote_log_functions();
7825
- log_warning(`${gobj_short_name(gobj)}: WebSocket closed ${url} (Code: ${kw.code}, Reason: "${kw.reason}", Clean: ${kw.was_clean})`);
8729
+ log_warning(`${gobj_short_name(gobj)}: WebSocket closed ${url} (Code: ${kw.code}, Reason: "${peer_text_shown(kw.reason, PEER_FRAME_SHOWN)}", Clean: ${kw.was_clean})`);
7826
8730
  if (priv.websocket) {
7827
8731
  priv.websocket.onopen = null;
7828
8732
  priv.websocket.onmessage = null;
@@ -7907,7 +8811,7 @@ var gobjJs = (function(exports) {
7907
8811
  let services_roles = kw_get_dict_value(gobj, kw, "services_roles", {});
7908
8812
  if (result < 0) {
7909
8813
  close_websocket(gobj);
7910
- let kw_nak = {
8814
+ gobj_publish_event(gobj, "EV_ON_ID_NAK", {
7911
8815
  "url": gobj_read_str_attr(gobj, "url"),
7912
8816
  "result": result,
7913
8817
  "comment": comment,
@@ -7915,24 +8819,20 @@ var gobjJs = (function(exports) {
7915
8819
  "remote_yuno_name": src_yuno,
7916
8820
  "remote_yuno_role": src_role,
7917
8821
  "remote_yuno_service": src_service
7918
- };
7919
- if (gobj_is_pure_child(gobj)) gobj_send_event(gobj_parent(gobj), "EV_ON_ID_NAK", kw_nak, gobj);
7920
- else gobj_publish_event(gobj, "EV_ON_ID_NAK", kw_nak);
8822
+ });
7921
8823
  } else {
7922
8824
  gobj_change_state(gobj, "ST_SESSION");
7923
8825
  priv.inside_on_open = true;
7924
8826
  priv.retry_ms = 0;
7925
8827
  if (!priv.inform_on_close) {
7926
8828
  priv.inform_on_close = true;
7927
- let kw_on_open = {
8829
+ gobj_publish_event(gobj, "EV_ON_OPEN", {
7928
8830
  "username": username_,
7929
8831
  "remote_yuno_name": src_yuno,
7930
8832
  "remote_yuno_role": src_role,
7931
8833
  "remote_yuno_service": src_service,
7932
8834
  "services_roles": services_roles
7933
- };
7934
- if (gobj_is_pure_child(gobj)) gobj_send_event(gobj_parent(gobj), "EV_ON_OPEN", kw_on_open, gobj);
7935
- else gobj_publish_event(gobj, "EV_ON_OPEN", kw_on_open);
8835
+ });
7936
8836
  }
7937
8837
  priv.inside_on_open = false;
7938
8838
  resend_subscriptions(gobj);
@@ -7946,7 +8846,7 @@ var gobjJs = (function(exports) {
7946
8846
  let url = gobj.priv.url;
7947
8847
  let iev_msg = iev_create_from_json(gobj, kw.data);
7948
8848
  if (!iev_msg) {
7949
- log_warning(`${gobj_short_name(gobj)}: frame dropped from ${url}: ${String(kw.data).substring(0, 256)}`);
8849
+ log_warning(`${gobj_short_name(gobj)}: frame dropped from ${url}: ${peer_text_shown(kw.data, PEER_FRAME_SHOWN)}`);
7950
8850
  return -1;
7951
8851
  }
7952
8852
  if (is_traffic_tracing(gobj)) {
@@ -7961,7 +8861,7 @@ var gobjJs = (function(exports) {
7961
8861
  if (gobj_current_state(gobj) !== "ST_SESSION") {
7962
8862
  if (gobj_has_event(gobj, iev_event, event_flag_t.EVF_PUBLIC_EVENT)) {
7963
8863
  if (!(gobj_send_event(gobj, iev_event, iev_kw, gobj) < 0)) return 0;
7964
- } else log_error(`${gobj_short_name(gobj)}: event UNKNOWN in not-session state ${iev_event}`);
8864
+ } else log_error(`${gobj_short_name(gobj)}: event UNKNOWN in not-session state ${peer_text_shown(iev_event, PEER_NAME_SHOWN)}`);
7965
8865
  close_websocket(gobj);
7966
8866
  return -1;
7967
8867
  }
@@ -7970,16 +8870,16 @@ var gobjJs = (function(exports) {
7970
8870
  let event_id = msg_iev_get_stack(gobj, iev_kw, IEVENT_STACK_ID);
7971
8871
  let iev_dst_role = kw_get_str(gobj, event_id, "dst_role", "");
7972
8872
  if (iev_dst_role.toLowerCase() !== gobj_yuno_role().toLowerCase()) {
7973
- log_error(`"It's not my role, dst_role: ${iev_dst_role}, my_role: ${gobj_yuno_role()}`);
8873
+ log_error(`"It's not my role, dst_role: ${peer_text_shown(iev_dst_role, PEER_NAME_SHOWN)}, my_role: ${gobj_yuno_role()}`);
7974
8874
  return 0;
7975
8875
  }
7976
8876
  let iev_dst_service = kw_get_str(gobj, event_id, "dst_service", "");
7977
8877
  if (msg_type === "__subscribing__") {
7978
- log_warning(`${gobj_short_name(gobj)}: subscription event ignored, I'm client (service: ${iev_dst_service}, event: ${iev_event})`);
8878
+ log_warning(`${gobj_short_name(gobj)}: subscription event ignored, I'm client (service: ${peer_text_shown(iev_dst_service, PEER_NAME_SHOWN)}, event: ${peer_text_shown(iev_event, PEER_NAME_SHOWN)})`);
7979
8879
  return -1;
7980
8880
  }
7981
8881
  if (msg_type === "__unsubscribing__") {
7982
- log_warning(`${gobj_short_name(gobj)}: unsubscription event ignored, I'm client (service: ${iev_dst_service}, event: ${iev_event})`);
8882
+ 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)})`);
7983
8883
  return -1;
7984
8884
  }
7985
8885
  if (gobj_has_event(gobj, iev_event, event_flag_t.EVF_PUBLIC_EVENT)) {
@@ -7989,18 +8889,17 @@ var gobjJs = (function(exports) {
7989
8889
  if (!empty_string(iev_dst_service)) {
7990
8890
  let gobj_service = gobj_find_service(iev_dst_service, false);
7991
8891
  if (!gobj_service) {
7992
- log_warning(`${gobj_short_name(gobj)}: event for a service that is gone, DROPPED: service '${iev_dst_service}', ev '${iev_event}'`);
8892
+ log_warning(`${gobj_short_name(gobj)}: event for a service that is gone, DROPPED: service '${peer_text_shown(iev_dst_service, PEER_NAME_SHOWN)}', ev '${peer_text_shown(iev_event, PEER_NAME_SHOWN)}'`);
7993
8893
  return 0;
7994
8894
  }
7995
8895
  if (!gobj_has_event(gobj_service, iev_event, event_flag_t.EVF_PUBLIC_EVENT)) {
7996
- log_error(`${gobj_short_name(gobj)}: Service found but no event or not public, service '${gobj_short_name(gobj_service)}', ev '${iev_event}'`);
8896
+ log_error(`${gobj_short_name(gobj)}: Service found but no event or not public, service '${gobj_short_name(gobj_service)}', ev '${peer_text_shown(iev_event, PEER_NAME_SHOWN)}'`);
7997
8897
  return -1;
7998
8898
  }
7999
8899
  gobj_send_event(gobj_service, iev_event, iev_kw, gobj);
8000
8900
  return 0;
8001
8901
  }
8002
- if (gobj_is_pure_child(gobj)) gobj_send_event(gobj_parent(gobj), iev_event, iev_kw, gobj);
8003
- else gobj_publish_event(gobj, iev_event, iev_kw);
8902
+ gobj_publish_event(gobj, iev_event, iev_kw);
8004
8903
  return 0;
8005
8904
  }
8006
8905
  /***************************************************************************
@@ -8162,6 +9061,8 @@ var gobjJs = (function(exports) {
8162
9061
  exports.clean_name = clean_name;
8163
9062
  exports.clear_timeout = clear_timeout;
8164
9063
  exports.cmp_two_simple_json = cmp_two_simple_json;
9064
+ exports.command_parameter_from_json = command_parameter_from_json;
9065
+ exports.command_parameter_from_text = command_parameter_from_text;
8165
9066
  exports.command_parser = command_parser;
8166
9067
  exports.createElement2 = createElement2;
8167
9068
  exports.createOneHtml = createOneHtml;