@yuneta/gobj-js 7.26.23 → 7.26.24
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +43 -2
- package/dist/gobj-js.cjs.js +238 -57
- package/dist/gobj-js.cjs.js.map +1 -1
- package/dist/gobj-js.cjs.min.js +1650 -1527
- package/dist/gobj-js.cjs.min.js.map +1 -1
- package/dist/gobj-js.es.js +238 -58
- package/dist/gobj-js.es.js.map +1 -1
- package/dist/gobj-js.es.min.js +1630 -1507
- package/dist/gobj-js.es.min.js.map +1 -1
- package/dist/gobj-js.iife.js +238 -57
- package/dist/gobj-js.iife.js.map +1 -1
- package/dist/gobj-js.iife.min.js +2046 -1923
- package/dist/gobj-js.iife.min.js.map +1 -1
- package/dist/gobj-js.umd.js +238 -57
- package/dist/gobj-js.umd.js.map +1 -1
- package/dist/gobj-js.umd.min.js +2046 -1923
- package/dist/gobj-js.umd.min.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -286,6 +286,29 @@ const attrs_table = [
|
|
|
286
286
|
|
|
287
287
|
**A value is read as the attribute's type, as in C** (`gobj_write_attr()`, the kw of `gobj_create()`, `gobj_write_attrs()`, the persistent attrs; 7.26.22+): a string for a boolean, integer, real, list or dict is read from its text by the C command parser's grammar (`command_parameter_from_json()`: `"yes"` is `true`, `"42"` is 42, `"007"` and `"12abc"` are refused), a number or a boolean as the exact type (`2.7` to an integer is refused). A refused value is not written: one `log_error` names the attr, its type, why and the value (masked, capped; a `SDF_SECRET` one never shown). A key of a kw whose value is `undefined` is an absent key; `gobj_write_attr()` of `undefined` to a typed attr is refused. The typed writers read the value as THEIR type by the same grammar (`gobj_write_integer_attr(g, "x", 2.5)` is refused, `gobj_write_bool_attr(g, "on", "yes")` is `true`), and `gobj_write_str_attr()` writes `null`/`undefined` as `""`, never the text `"null"`.
|
|
288
288
|
|
|
289
|
+
**A refused write keeps the value the attribute had** (BREAKING in 7.26.22, kept
|
|
290
|
+
by decision: the C kernel's `json2item()` does the same). `undefined`, `null`, an
|
|
291
|
+
empty text or a text that is not a boolean, given to `gobj_write_bool_attr()`, is
|
|
292
|
+
not `false`: the function returns -1, logs one ERROR, and the attribute does not
|
|
293
|
+
change. The same for `gobj_write_attr()` of `null` or `""` to a `DTP_REAL`.
|
|
294
|
+
Compute the value before the write when it can be absent:
|
|
295
|
+
|
|
296
|
+
```javascript
|
|
297
|
+
gobj_write_bool_attr(gobj, "selectable", true);
|
|
298
|
+
gobj_write_bool_attr(gobj, "selectable", kw.selectable); // kw has none: -1, ERROR,
|
|
299
|
+
// "selectable" is still true
|
|
300
|
+
gobj_write_bool_attr(gobj, "selectable", kw.selectable === true); // false
|
|
301
|
+
```
|
|
302
|
+
|
|
303
|
+
A value with no json text (a circular object such as a gobj or a DOM node, a
|
|
304
|
+
`BigInt`) given to a string attribute is refused the same way, and is never
|
|
305
|
+
thrown (7.26.24). A json TEXT is read as the C parser reads it: one that C
|
|
306
|
+
refuses is refused in JS too -- an escaped NUL (`"\u0000"`), a lone surrogate,
|
|
307
|
+
an integer out of int64, a real that overflows (`1e309`; to a `DTP_JSON` it is
|
|
308
|
+
the text `"1e309"`, not `Infinity`). Two differences remain, because a JS number
|
|
309
|
+
cannot carry them: an integer beyond 2^53 is rounded, and `2.0` is the integer
|
|
310
|
+
2 (see `tests/fixtures/attr_types_parity.json`).
|
|
311
|
+
|
|
289
312
|
### Events & Pub-Sub
|
|
290
313
|
|
|
291
314
|
GObjects communicate via events with JSON payloads:
|
|
@@ -463,6 +486,7 @@ gobj_current_state(gobj) // → state name string
|
|
|
463
486
|
gobj_change_state(gobj, new_state) // trigger FSM transition
|
|
464
487
|
gobj_has_event(gobj, event, event_flag) // → boolean; pass 0 to ignore flag
|
|
465
488
|
gobj_has_output_event(gobj, event, event_flag) // same; checks EVF_OUTPUT_EVENT
|
|
489
|
+
gobj_find_event_type(event, event_flag, verbose) // the event type in ANY registered gclass, or null
|
|
466
490
|
```
|
|
467
491
|
|
|
468
492
|
### Attribute Access
|
|
@@ -720,6 +744,8 @@ mask_secrets_inline("sent Bearer mF_9.B5f-4.1JqM") // → "sent Bearer ********
|
|
|
720
744
|
mask_secrets_inline("the bearer of this letter") // → null: prose
|
|
721
745
|
mask_secrets_inline("\"password\": hunter2") // → "\"password\": ********"
|
|
722
746
|
mask_secrets_inline("GET https://h/get?token=abc&x=1") // → "GET https://h/get?token=********&x=1"
|
|
747
|
+
mask_secrets_inline("a=1&user%5Bpassword%5D=x") // → "a=1&user%5Bpassword%5D=********"
|
|
748
|
+
mask_secrets_inline("https://bob:hunter2@host/x") // → "https://bob:********@host/x"
|
|
723
749
|
json_mask_secrets({user: "a", password: "x"}) // → {user: "a", password: "********"}
|
|
724
750
|
json_mask_secrets({note: "eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJ4In0.c2ln"})
|
|
725
751
|
// → {note: "********"}: a JWT under any key
|
|
@@ -960,7 +986,11 @@ Events published: `EV_TIMEOUT`, `EV_TIMEOUT_PERIODIC`. They go to the
|
|
|
960
986
|
`subscriber` attr, else, for a pure child, to its parent, which the timer
|
|
961
987
|
subscribes in `mt_create` — the C timer's rule. Up to 7.26.21 a pure child
|
|
962
988
|
SENT the timeout to its parent instead of publishing it (and to its parent
|
|
963
|
-
even when it had a `subscriber`).
|
|
989
|
+
even when it had a `subscriber`). BREAKING in 7.26.22: the parent's
|
|
990
|
+
`EV_TIMEOUT` action now runs inside the timer's publication, so destroying
|
|
991
|
+
the timer or the parent there is the ERROR *"Destroying a gobj while its tree
|
|
992
|
+
is publishing"*. Defer it with `gobj_post_event()` to yourself; re-arming or
|
|
993
|
+
clearing the timer in the action is fine.
|
|
964
994
|
|
|
965
995
|
Attributes: `subscriber`, `periodic`, `msec`
|
|
966
996
|
|
|
@@ -982,7 +1012,18 @@ let remote = gobj_create_service("backend", "C_IEVENT_CLI", {
|
|
|
982
1012
|
|
|
983
1013
|
Key attributes: `url`, `jwt`, `wanted_yuno_role`, `wanted_yuno_name`, `wanted_yuno_service`, `remote_yuno_role`, `remote_yuno_name`, `remote_yuno_service`, `required_services`, `timeout_retry`, `timeout_retry_max`
|
|
984
1014
|
|
|
985
|
-
Its events (`EV_ON_OPEN`, `EV_ON_CLOSE`, `EV_ON_OPEN_ERROR`, `EV_ON_ID_NAK` and every message that names no service) are PUBLISHED: to the `subscriber` attr, else, for a pure child, to its parent, which it subscribes in `mt_create` — one subscription, as the C transport. Up to 7.26.21 a pure child SENT three of them to its parent and subscribed nobody, so its parent never heard `EV_ON_CLOSE` / `EV_ON_OPEN_ERROR
|
|
1015
|
+
Its events (`EV_ON_OPEN`, `EV_ON_CLOSE`, `EV_ON_OPEN_ERROR`, `EV_ON_ID_NAK` and every message that names no service) are PUBLISHED: to the `subscriber` attr, else, for a pure child, to its parent, which it subscribes in `mt_create` — one subscription, as the C transport. Up to 7.26.21 a pure child SENT three of them to its parent and subscribed nobody, so its parent never heard `EV_ON_CLOSE` / `EV_ON_OPEN_ERROR`: a host of a pure child must declare both in its FSM (BREAKING in 7.26.22).
|
|
1016
|
+
|
|
1017
|
+
A message that names no service is published only when its event is declared by some registered gclass (`gobj_find_event_type()`); any other is dropped with a WARNING, its name masked (7.26.24). What the server gets wrong is a WARNING, never an ERROR. Before the session only `EV_IDENTITY_CARD_ACK` is taken; a `dst_role` or `dst_yuno` that is not this yuno's closes the channel too (an empty one is legal: anybody's), as the C transport does; an event that the named service does not take as public is dropped (7.26.24).
|
|
1018
|
+
|
|
1019
|
+
`EV_ON_CLOSE` carries `code`, `reason` (masked) and `was_clean`, and so does `EV_ON_OPEN_ERROR` (7.26.24). A session that ends cleanly (a stop, a logout, the server closing with 1000 or 1001) is logged by nobody; a session CUT -- not clean, or any other code (1006, 1008, 1011) -- is one WARNING with the code and the reason masked:
|
|
1020
|
+
|
|
1021
|
+
```javascript
|
|
1022
|
+
// in the subscriber's EV_ON_CLOSE action
|
|
1023
|
+
if(!kw.was_clean || (kw.code !== 1000 && kw.code !== 1001)) {
|
|
1024
|
+
show_banner(t("connection lost")); // the WARNING is already logged
|
|
1025
|
+
}
|
|
1026
|
+
```
|
|
986
1027
|
|
|
987
1028
|
**`required_services`** (default `[]`) is the list this link advertises in its
|
|
988
1029
|
identity_card, which the remote's `C_AUTHZ` uses to authorize commands. It is
|
package/dist/gobj-js.cjs.js
CHANGED
|
@@ -866,6 +866,75 @@ var JSON_NUMBER_TEXT = /^-?(0|[1-9][0-9]*)(\.[0-9]+)?([eE][+-]?[0-9]+)?$/;
|
|
|
866
866
|
var INT64_MIN = -(2n ** 63n);
|
|
867
867
|
var INT64_MAX = 2n ** 63n - 1n;
|
|
868
868
|
var REFUSED_TEXT = "a text that does not read as one";
|
|
869
|
+
var JSON_NUMBER_TOKEN = /-?(0|[1-9][0-9]*)(\.[0-9]+)?([eE][+-]?[0-9]+)?/y;
|
|
870
|
+
function is_surrogate_pair(high, low) {
|
|
871
|
+
return high >= 55296 && high <= 56319 && low >= 56320 && low <= 57343;
|
|
872
|
+
}
|
|
873
|
+
function json_text_refused_by_c(s) {
|
|
874
|
+
const n = s.length;
|
|
875
|
+
let i = 0;
|
|
876
|
+
while (i < n) {
|
|
877
|
+
const c = s.charCodeAt(i);
|
|
878
|
+
if (c === 34) {
|
|
879
|
+
i++;
|
|
880
|
+
while (i < n) {
|
|
881
|
+
const d = s.charCodeAt(i);
|
|
882
|
+
if (d === 34) {
|
|
883
|
+
i++;
|
|
884
|
+
break;
|
|
885
|
+
}
|
|
886
|
+
if (d === 92 && s[i + 1] === "u") {
|
|
887
|
+
const u = parseInt(s.substring(i + 2, i + 6), 16);
|
|
888
|
+
if (u === 0) return true;
|
|
889
|
+
if (u >= 55296 && u <= 57343) {
|
|
890
|
+
if (!is_surrogate_pair(u, s[i + 6] === "\\" && s[i + 7] === "u" ? parseInt(s.substring(i + 8, i + 12), 16) : -1)) return true;
|
|
891
|
+
i += 12;
|
|
892
|
+
continue;
|
|
893
|
+
}
|
|
894
|
+
i += 6;
|
|
895
|
+
continue;
|
|
896
|
+
}
|
|
897
|
+
if (d === 92) {
|
|
898
|
+
i += 2;
|
|
899
|
+
continue;
|
|
900
|
+
}
|
|
901
|
+
if (d >= 55296 && d <= 57343) {
|
|
902
|
+
if (!is_surrogate_pair(d, s.charCodeAt(i + 1))) return true;
|
|
903
|
+
i += 2;
|
|
904
|
+
continue;
|
|
905
|
+
}
|
|
906
|
+
i++;
|
|
907
|
+
}
|
|
908
|
+
continue;
|
|
909
|
+
}
|
|
910
|
+
if (c === 45 || c >= 48 && c <= 57) {
|
|
911
|
+
JSON_NUMBER_TOKEN.lastIndex = i;
|
|
912
|
+
const m = JSON_NUMBER_TOKEN.exec(s);
|
|
913
|
+
if (!m) return true;
|
|
914
|
+
const token = m[0];
|
|
915
|
+
if (/[.eE]/.test(token)) {
|
|
916
|
+
if (!Number.isFinite(Number(token))) return true;
|
|
917
|
+
} else {
|
|
918
|
+
const big = BigInt(token);
|
|
919
|
+
if (big < INT64_MIN || big > INT64_MAX) return true;
|
|
920
|
+
}
|
|
921
|
+
i += token.length;
|
|
922
|
+
continue;
|
|
923
|
+
}
|
|
924
|
+
i++;
|
|
925
|
+
}
|
|
926
|
+
return false;
|
|
927
|
+
}
|
|
928
|
+
function parse_json_text_as_c(s) {
|
|
929
|
+
let jn;
|
|
930
|
+
try {
|
|
931
|
+
jn = JSON.parse(s);
|
|
932
|
+
} catch (e) {
|
|
933
|
+
return;
|
|
934
|
+
}
|
|
935
|
+
if (json_text_refused_by_c(s)) return;
|
|
936
|
+
return jn;
|
|
937
|
+
}
|
|
869
938
|
function value_has_shape(type, value) {
|
|
870
939
|
if (DTP_IS_STRING(type)) return is_string(value);
|
|
871
940
|
if (DTP_IS_DICT(type)) return is_object(value);
|
|
@@ -969,16 +1038,8 @@ function text2parameter(type, s, from_kw) {
|
|
|
969
1038
|
};
|
|
970
1039
|
}
|
|
971
1040
|
if (DTP_IS_DICT(type) || DTP_IS_LIST(type)) {
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
jn = JSON.parse(s);
|
|
975
|
-
} catch (e) {
|
|
976
|
-
return {
|
|
977
|
-
value: void 0,
|
|
978
|
-
refused: REFUSED_TEXT
|
|
979
|
-
};
|
|
980
|
-
}
|
|
981
|
-
if (!value_has_shape(type, jn)) return {
|
|
1041
|
+
const jn = parse_json_text_as_c(s);
|
|
1042
|
+
if (jn === void 0 || !value_has_shape(type, jn)) return {
|
|
982
1043
|
value: void 0,
|
|
983
1044
|
refused: REFUSED_TEXT
|
|
984
1045
|
};
|
|
@@ -987,12 +1048,12 @@ function text2parameter(type, s, from_kw) {
|
|
|
987
1048
|
refused: null
|
|
988
1049
|
};
|
|
989
1050
|
}
|
|
990
|
-
if (DTP_IS_JSON(type))
|
|
991
|
-
|
|
992
|
-
|
|
1051
|
+
if (DTP_IS_JSON(type)) {
|
|
1052
|
+
const jn = parse_json_text_as_c(s);
|
|
1053
|
+
if (jn !== void 0) return {
|
|
1054
|
+
value: jn,
|
|
993
1055
|
refused: null
|
|
994
1056
|
};
|
|
995
|
-
} catch (e) {
|
|
996
1057
|
const t = s.replace(/^[ \t]+/, "");
|
|
997
1058
|
if (t.startsWith("{") || t.startsWith("[") || t.startsWith("\"")) return {
|
|
998
1059
|
value: void 0,
|
|
@@ -1085,8 +1146,18 @@ var TYPES_READ = [
|
|
|
1085
1146
|
data_type_t.DTP_LIST,
|
|
1086
1147
|
data_type_t.DTP_DICT
|
|
1087
1148
|
];
|
|
1149
|
+
var NO_JSON_TEXT = "a value with no json text";
|
|
1150
|
+
function json_text_of(value) {
|
|
1151
|
+
try {
|
|
1152
|
+
const s = JSON.stringify(value);
|
|
1153
|
+
return is_string(s) ? s : void 0;
|
|
1154
|
+
} catch (e) {
|
|
1155
|
+
return;
|
|
1156
|
+
}
|
|
1157
|
+
}
|
|
1088
1158
|
function log_attr_value_refused(gobj, it, value, refused) {
|
|
1089
1159
|
const types = {
|
|
1160
|
+
[data_type_t.DTP_STRING]: "a string",
|
|
1090
1161
|
[data_type_t.DTP_BOOLEAN]: "a boolean",
|
|
1091
1162
|
[data_type_t.DTP_INTEGER]: "an integer",
|
|
1092
1163
|
[data_type_t.DTP_REAL]: "a real",
|
|
@@ -1096,7 +1167,8 @@ function log_attr_value_refused(gobj, it, value, refused) {
|
|
|
1096
1167
|
let shown;
|
|
1097
1168
|
if (it.flag & sdata_flag_t.SDF_SECRET) shown = "********";
|
|
1098
1169
|
else {
|
|
1099
|
-
shown = is_string(value) ? value :
|
|
1170
|
+
shown = is_string(value) ? value : json_text_of(value === void 0 ? null : value);
|
|
1171
|
+
if (shown === void 0) shown = `<${NO_JSON_TEXT}>`;
|
|
1100
1172
|
const masked = mask_secrets_inline(shown);
|
|
1101
1173
|
if (masked !== null) shown = masked;
|
|
1102
1174
|
if (shown.length > ATTR_VALUE_SHOWN) {
|
|
@@ -1118,8 +1190,11 @@ function json2item(gobj, sdata, it, jn_value_) {
|
|
|
1118
1190
|
if (jn_value_ === null || jn_value_ === void 0) jn_value2 = "";
|
|
1119
1191
|
else if (is_string(jn_value_)) jn_value2 = String(jn_value_);
|
|
1120
1192
|
else {
|
|
1121
|
-
|
|
1122
|
-
if (
|
|
1193
|
+
jn_value2 = json_text_of(jn_value_);
|
|
1194
|
+
if (jn_value2 === void 0) {
|
|
1195
|
+
log_attr_value_refused(gobj, it, jn_value_, NO_JSON_TEXT);
|
|
1196
|
+
return -1;
|
|
1197
|
+
}
|
|
1123
1198
|
}
|
|
1124
1199
|
break;
|
|
1125
1200
|
case data_type_t.DTP_BOOLEAN:
|
|
@@ -2567,15 +2642,20 @@ function write_attr_value(gobj, key, value) {
|
|
|
2567
2642
|
* The value a typed writer writes, read as ITS type by the grammar of
|
|
2568
2643
|
* json2item() (a C writer takes its C type: a string is never read as a
|
|
2569
2644
|
* number there). Return {value} or {refused} (logged): the attr keeps its
|
|
2570
|
-
* value. A string writer
|
|
2571
|
-
*
|
|
2645
|
+
* value. A string writer takes null and undefined as "", any other json
|
|
2646
|
+
* as its text, as a DTP_STRING attr reads them; it refuses only a value
|
|
2647
|
+
* with no json text (circular, a BigInt).
|
|
2572
2648
|
***************************************************************************/
|
|
2573
2649
|
function typed_writer_value(gobj, name, type, value) {
|
|
2650
|
+
let r;
|
|
2574
2651
|
if (DTP_IS_STRING(type)) {
|
|
2575
2652
|
if (value === null || value === void 0) return { value: "" };
|
|
2576
|
-
|
|
2577
|
-
|
|
2578
|
-
|
|
2653
|
+
if (is_string(value)) return { value };
|
|
2654
|
+
r = {
|
|
2655
|
+
value: json_text_of(value),
|
|
2656
|
+
refused: NO_JSON_TEXT
|
|
2657
|
+
};
|
|
2658
|
+
} else r = command_parameter_from_json(type, value);
|
|
2579
2659
|
if (r.value === void 0) {
|
|
2580
2660
|
let holder = gobj;
|
|
2581
2661
|
while (holder && !gobj_has_attr(holder, name)) holder = holder.bottom_gobj;
|
|
@@ -3020,9 +3100,9 @@ function gobj_send_event(dst, event, kw, src) {
|
|
|
3020
3100
|
}
|
|
3021
3101
|
}
|
|
3022
3102
|
const frame = push_dispatch_frame(dst, event, frame_kind_t.FRAME_ACTION);
|
|
3023
|
-
if (event_action.next_state) gobj_change_state(dst, event_action.next_state);
|
|
3024
3103
|
let ret = -1;
|
|
3025
3104
|
try {
|
|
3105
|
+
if (event_action.next_state) gobj_change_state(dst, event_action.next_state);
|
|
3026
3106
|
if (event_action.action) ret = event_action.action(dst, event, kw, src);
|
|
3027
3107
|
} catch (e) {
|
|
3028
3108
|
__inside__--;
|
|
@@ -3046,18 +3126,23 @@ var subs_flag_t = Object.freeze({
|
|
|
3046
3126
|
__own_event__: 4
|
|
3047
3127
|
});
|
|
3048
3128
|
/***************************************************************************
|
|
3049
|
-
* The event type of `event_name` in any registered gclass
|
|
3050
|
-
*
|
|
3129
|
+
* The event type of `event_name` in any registered gclass whose flags
|
|
3130
|
+
* hold one of `event_flag` (0: any), null if none. The C kernel's
|
|
3131
|
+
* gobj_find_event_type(): any case, gclasses only. With `verbose` a miss
|
|
3132
|
+
* is logged, with the name as it was given: never verbose for a name
|
|
3133
|
+
* that came from a peer.
|
|
3051
3134
|
***************************************************************************/
|
|
3052
|
-
function
|
|
3135
|
+
function gobj_find_event_type(event_name, event_flag, verbose) {
|
|
3053
3136
|
let lower = String(event_name).toLowerCase();
|
|
3054
3137
|
for (let gclass_name in _gclass_register) {
|
|
3055
3138
|
let dl = _gclass_register[gclass_name].dl_events;
|
|
3056
3139
|
for (let i = 0; i < dl.length; i++) {
|
|
3057
3140
|
let event_type = dl[i];
|
|
3141
|
+
if (event_flag && !(event_type.event_flag & event_flag)) continue;
|
|
3058
3142
|
if (event_type.event_name && event_type.event_name.toLowerCase() === lower) return event_type;
|
|
3059
3143
|
}
|
|
3060
3144
|
}
|
|
3145
|
+
if (verbose) log_error(`EVENT NOT FOUND: ${event_name}`);
|
|
3061
3146
|
return null;
|
|
3062
3147
|
}
|
|
3063
3148
|
var subscription_desc = [
|
|
@@ -3094,7 +3179,7 @@ function _create_subscription(publisher, event, kw, subscriber) {
|
|
|
3094
3179
|
json_object_set_new(subs, "__config__", kw_clone);
|
|
3095
3180
|
let renamed_event = kw_get_str(publisher, kw_clone, "__rename_event_name__", "");
|
|
3096
3181
|
if (!empty_string(renamed_event)) {
|
|
3097
|
-
let event_type =
|
|
3182
|
+
let event_type = gobj_find_event_type(renamed_event, 0, false);
|
|
3098
3183
|
if (event_type) {
|
|
3099
3184
|
json_object_set_new(subs, "renamed_event", event_type.event_name);
|
|
3100
3185
|
delete kw_clone.__rename_event_name__;
|
|
@@ -3155,7 +3240,7 @@ function _subscription_match_kw(kw, event) {
|
|
|
3155
3240
|
kw_match.__config__ = config_match;
|
|
3156
3241
|
let renamed_event = "";
|
|
3157
3242
|
let rename = config_match.__rename_event_name__;
|
|
3158
|
-
let event_type = typeof rename === "string" && !empty_string(rename) ?
|
|
3243
|
+
let event_type = typeof rename === "string" && !empty_string(rename) ? gobj_find_event_type(rename, 0, false) : null;
|
|
3159
3244
|
if (event_type) {
|
|
3160
3245
|
renamed_event = event_type.event_name;
|
|
3161
3246
|
delete config_match.__rename_event_name__;
|
|
@@ -4319,12 +4404,13 @@ function mark_params(str, value_is_secret, reading, marks, judged) {
|
|
|
4319
4404
|
const name_from = word;
|
|
4320
4405
|
word = p + 1;
|
|
4321
4406
|
const secret = is_secret_name_tail(str, name_from, p, names);
|
|
4322
|
-
if (secret && names === NAMES_NOW && !is_secret_name_tail(str, name_from, p, NAMES_7_26_9)) not_7_26_9 = true;
|
|
4407
|
+
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;
|
|
4323
4408
|
if (!(secret || value_is_secret && p - name_from === 5 && ascii_case_equal(str, name_from, "value"))) {
|
|
4324
|
-
if (judged && query_name_from(str, p) === name_from) judged[p] =
|
|
4409
|
+
if (judged && query_name_from(str, p) === name_from) judged[p] = JUDGED_NOT_SECRET;
|
|
4325
4410
|
p++;
|
|
4326
4411
|
continue;
|
|
4327
4412
|
}
|
|
4413
|
+
if (judged && secret && query_name_from(str, p) === name_from) judged[p] = JUDGED_SECRET;
|
|
4328
4414
|
p++;
|
|
4329
4415
|
let end;
|
|
4330
4416
|
const quote = p < str.length && (str[p] === "\"" || str[p] === "'") ? str[p] : "";
|
|
@@ -4387,23 +4473,99 @@ function query_name_from(str, eq) {
|
|
|
4387
4473
|
while (n > 0 && eq - n < MASK_MAX_NAME && is_name_char_code(str.charCodeAt(n - 1))) n--;
|
|
4388
4474
|
return n;
|
|
4389
4475
|
}
|
|
4476
|
+
var JUDGED_NOT_SECRET = 1;
|
|
4477
|
+
var JUDGED_SECRET = 2;
|
|
4478
|
+
function hex_digit_value(code) {
|
|
4479
|
+
if (code >= 48 && code <= 57) return code - 48;
|
|
4480
|
+
if (code >= 97 && code <= 102) return code - 87;
|
|
4481
|
+
if (code >= 65 && code <= 70) return code - 55;
|
|
4482
|
+
return -1;
|
|
4483
|
+
}
|
|
4484
|
+
function is_written_name_bracket_code(code) {
|
|
4485
|
+
return code === 91 || code === 93 || code === 39 || code === 34;
|
|
4486
|
+
}
|
|
4487
|
+
function is_written_name_code(code) {
|
|
4488
|
+
return is_name_char_code(code) || code === 37 || is_written_name_bracket_code(code);
|
|
4489
|
+
}
|
|
4490
|
+
function written_name_is_secret(str, eq) {
|
|
4491
|
+
let n = eq;
|
|
4492
|
+
let plain = -1;
|
|
4493
|
+
while (n > 0 && eq - n < MASK_MAX_NAME && is_written_name_code(str.charCodeAt(n - 1))) {
|
|
4494
|
+
n--;
|
|
4495
|
+
if (plain < 0 && !is_name_char_code(str.charCodeAt(n))) plain = n + 1;
|
|
4496
|
+
}
|
|
4497
|
+
if (plain < 0) return false;
|
|
4498
|
+
const to = str.charCodeAt(plain - 1) === 37 ? eq : plain - 1;
|
|
4499
|
+
let encoded = false;
|
|
4500
|
+
for (let s = n; s < to && !encoded; s++) encoded = str.charCodeAt(s) === 37;
|
|
4501
|
+
let name = str;
|
|
4502
|
+
let from = n;
|
|
4503
|
+
let end = to;
|
|
4504
|
+
if (encoded) {
|
|
4505
|
+
name = "";
|
|
4506
|
+
for (let s = n; s < to; s++) {
|
|
4507
|
+
const hi = str.charCodeAt(s) === 37 && to - s > 2 ? hex_digit_value(str.charCodeAt(s + 1)) : -1;
|
|
4508
|
+
const lo = hi >= 0 ? hex_digit_value(str.charCodeAt(s + 2)) : -1;
|
|
4509
|
+
if (lo >= 0) {
|
|
4510
|
+
name += String.fromCharCode(hi * 16 + lo);
|
|
4511
|
+
s += 2;
|
|
4512
|
+
} else name += str[s];
|
|
4513
|
+
}
|
|
4514
|
+
from = 0;
|
|
4515
|
+
end = name.length;
|
|
4516
|
+
}
|
|
4517
|
+
let seg = from;
|
|
4518
|
+
for (let i = from; i <= end; i++) {
|
|
4519
|
+
if (i < end && !is_written_name_bracket_code(name.charCodeAt(i))) continue;
|
|
4520
|
+
if (i - seg >= 3 && secret_name_check(name, seg, i, true, true)) return true;
|
|
4521
|
+
seg = i + 1;
|
|
4522
|
+
}
|
|
4523
|
+
return false;
|
|
4524
|
+
}
|
|
4525
|
+
function mark_query_value(str, eq, marks) {
|
|
4526
|
+
const v = eq + 1;
|
|
4527
|
+
if (v < str.length && (str[v] === "\"" || str[v] === "'")) return mark_run(str, v + 1, QUOTE_STOPS[str[v]], marks);
|
|
4528
|
+
mark_scheme_value(str, v, PARAM_VALUE_STOPS, marks);
|
|
4529
|
+
return mark_run(str, v, PARAM_VALUE_STOPS, marks);
|
|
4530
|
+
}
|
|
4531
|
+
var WRITTEN_NAME_MARKS = /[[\]%'"]/;
|
|
4390
4532
|
function mark_query_params(str, marks, judged) {
|
|
4391
4533
|
let frontier = 0;
|
|
4392
|
-
|
|
4393
|
-
|
|
4394
|
-
|
|
4395
|
-
|
|
4396
|
-
|
|
4397
|
-
|
|
4398
|
-
|
|
4399
|
-
|
|
4400
|
-
|
|
4401
|
-
|
|
4402
|
-
|
|
4403
|
-
|
|
4404
|
-
|
|
4405
|
-
|
|
4534
|
+
let frontier_written = WRITTEN_NAME_MARKS.test(str) ? 0 : str.length;
|
|
4535
|
+
let p = str.indexOf("=", 1);
|
|
4536
|
+
while (p > 0) {
|
|
4537
|
+
if (p >= frontier) {
|
|
4538
|
+
let secret = judged[p] === JUDGED_SECRET;
|
|
4539
|
+
if (!judged[p]) {
|
|
4540
|
+
const n = query_name_from(str, p);
|
|
4541
|
+
secret = n < p && secret_name_check(str, n, p, true, true);
|
|
4542
|
+
}
|
|
4543
|
+
if (secret) frontier = mark_query_value(str, p, marks);
|
|
4544
|
+
}
|
|
4545
|
+
if (p >= frontier_written && written_name_is_secret(str, p)) frontier_written = mark_query_value(str, p, marks);
|
|
4546
|
+
p = str.indexOf("=", p + 1);
|
|
4547
|
+
}
|
|
4548
|
+
}
|
|
4549
|
+
var URL_AUTHORITY_STOPS = stop_table("/?#\"'<> ");
|
|
4550
|
+
function mark_url_passwords(str, marks) {
|
|
4551
|
+
let p = str.indexOf("://", 1);
|
|
4552
|
+
while (p > 0) {
|
|
4553
|
+
let next = p + 1;
|
|
4554
|
+
if (is_ascii_alnum_code(str.charCodeAt(p - 1))) {
|
|
4555
|
+
let colon = -1;
|
|
4556
|
+
let at = -1;
|
|
4557
|
+
let e = p + 3;
|
|
4558
|
+
while (e < str.length) {
|
|
4559
|
+
const code = str.charCodeAt(e);
|
|
4560
|
+
if (code < 128 && URL_AUTHORITY_STOPS[code]) break;
|
|
4561
|
+
if (code === 64) at = e;
|
|
4562
|
+
else if (code === 58 && colon < 0) colon = e;
|
|
4563
|
+
e++;
|
|
4564
|
+
}
|
|
4565
|
+
if (colon >= 0 && at > colon) mark_range(marks, colon + 1, at);
|
|
4566
|
+
next = e - 1;
|
|
4406
4567
|
}
|
|
4568
|
+
p = str.indexOf("://", next);
|
|
4407
4569
|
}
|
|
4408
4570
|
}
|
|
4409
4571
|
function mark_shapes(str, marks) {
|
|
@@ -4464,6 +4626,7 @@ function mark_inline_secrets(str, marks) {
|
|
|
4464
4626
|
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);
|
|
4465
4627
|
if (has_shape_js_7_26_20(str)) mark_params(str, value_is_secret, READ_AS_GOBJ_JS_7_26_20, marks, null);
|
|
4466
4628
|
mark_query_params(str, marks, judged);
|
|
4629
|
+
mark_url_passwords(str, marks);
|
|
4467
4630
|
mark_shapes(str, marks);
|
|
4468
4631
|
mark_labels(str, marks);
|
|
4469
4632
|
}
|
|
@@ -8502,7 +8665,7 @@ function close_websocket(gobj, code = 1e3, reason = "") {
|
|
|
8502
8665
|
* show its first characters). As the C kernel shows the name of an
|
|
8503
8666
|
* event that is not public (mask_secrets_inline_capped()).
|
|
8504
8667
|
***************************************************************/
|
|
8505
|
-
var PEER_NAME_SHOWN =
|
|
8668
|
+
var PEER_NAME_SHOWN = 128;
|
|
8506
8669
|
var PEER_FRAME_SHOWN = 256;
|
|
8507
8670
|
function peer_text_shown(text, max) {
|
|
8508
8671
|
let s = String(text);
|
|
@@ -8725,7 +8888,8 @@ function ac_on_close(gobj, event, kw, src) {
|
|
|
8725
8888
|
let url = kw.url;
|
|
8726
8889
|
if (kw.ws_seq !== void 0 && kw.ws_seq !== priv.ws_seq) return 0;
|
|
8727
8890
|
set_remote_log_functions();
|
|
8728
|
-
|
|
8891
|
+
const reason_shown = peer_text_shown(kw.reason === void 0 ? "" : kw.reason, PEER_FRAME_SHOWN);
|
|
8892
|
+
if (is_traffic_tracing(gobj)) trace_msg(`${gobj_short_name(gobj)}: WebSocket closed ${url} (Code: ${kw.code}, Reason: "${reason_shown}", Clean: ${kw.was_clean})`);
|
|
8729
8893
|
if (priv.websocket) {
|
|
8730
8894
|
priv.websocket.onopen = null;
|
|
8731
8895
|
priv.websocket.onmessage = null;
|
|
@@ -8735,21 +8899,25 @@ function ac_on_close(gobj, event, kw, src) {
|
|
|
8735
8899
|
}
|
|
8736
8900
|
if (priv.inform_on_close) {
|
|
8737
8901
|
priv.inform_on_close = false;
|
|
8902
|
+
if ((!kw.was_clean || kw.code !== 1e3 && kw.code !== 1001) && gobj_is_running(gobj)) log_warning(`${gobj_short_name(gobj)}: session closed ${url} (Code: ${kw.code}, Reason: "${reason_shown}", Clean: ${kw.was_clean})`);
|
|
8738
8903
|
gobj_publish_event(gobj, "EV_ON_CLOSE", {
|
|
8739
8904
|
url,
|
|
8740
8905
|
remote_yuno_name: priv.remote_yuno_name,
|
|
8741
8906
|
remote_yuno_role: priv.remote_yuno_role,
|
|
8742
|
-
remote_yuno_service: priv.remote_yuno_service
|
|
8907
|
+
remote_yuno_service: priv.remote_yuno_service,
|
|
8908
|
+
code: kw.code,
|
|
8909
|
+
reason: reason_shown,
|
|
8910
|
+
was_clean: kw.was_clean
|
|
8743
8911
|
});
|
|
8744
8912
|
} else if (!gobj_is_running(gobj)) {} else {
|
|
8745
|
-
log_warning(`${gobj_short_name(gobj)}: EV_ON_OPEN_ERROR cannot open ${url} (Code: ${kw.code}, Reason: "${
|
|
8913
|
+
log_warning(`${gobj_short_name(gobj)}: EV_ON_OPEN_ERROR cannot open ${url} (Code: ${kw.code}, Reason: "${reason_shown}", Clean: ${kw.was_clean})`);
|
|
8746
8914
|
gobj_publish_event(gobj, "EV_ON_OPEN_ERROR", {
|
|
8747
8915
|
url,
|
|
8748
8916
|
remote_yuno_name: priv.remote_yuno_name,
|
|
8749
8917
|
remote_yuno_role: priv.remote_yuno_role,
|
|
8750
8918
|
remote_yuno_service: priv.remote_yuno_service,
|
|
8751
8919
|
code: kw.code,
|
|
8752
|
-
reason:
|
|
8920
|
+
reason: reason_shown,
|
|
8753
8921
|
was_clean: kw.was_clean
|
|
8754
8922
|
});
|
|
8755
8923
|
}
|
|
@@ -8858,9 +9026,9 @@ function ac_on_message(gobj, event, kw, src) {
|
|
|
8858
9026
|
let iev_event = iev_msg.event;
|
|
8859
9027
|
let iev_kw = iev_msg.kw;
|
|
8860
9028
|
if (gobj_current_state(gobj) !== "ST_SESSION") {
|
|
8861
|
-
if (
|
|
8862
|
-
if (!(gobj_send_event(gobj,
|
|
8863
|
-
} else
|
|
9029
|
+
if (String(iev_event).toLowerCase() === "ev_identity_card_ack") {
|
|
9030
|
+
if (!(gobj_send_event(gobj, "EV_IDENTITY_CARD_ACK", iev_kw, gobj) < 0)) return 0;
|
|
9031
|
+
} else log_warning(`${gobj_short_name(gobj)}: event UNKNOWN in not-session state ${peer_text_shown(iev_event, PEER_NAME_SHOWN)}`);
|
|
8864
9032
|
close_websocket(gobj);
|
|
8865
9033
|
return -1;
|
|
8866
9034
|
}
|
|
@@ -8868,9 +9036,16 @@ function ac_on_message(gobj, event, kw, src) {
|
|
|
8868
9036
|
let msg_type = msg_iev_get_msg_type(gobj, iev_kw);
|
|
8869
9037
|
let event_id = msg_iev_get_stack(gobj, iev_kw, IEVENT_STACK_ID);
|
|
8870
9038
|
let iev_dst_role = kw_get_str(gobj, event_id, "dst_role", "");
|
|
8871
|
-
if (iev_dst_role.toLowerCase() !== gobj_yuno_role().toLowerCase()) {
|
|
8872
|
-
|
|
8873
|
-
|
|
9039
|
+
if (!empty_string(iev_dst_role) && iev_dst_role.toLowerCase() !== String(gobj_yuno_role()).toLowerCase()) {
|
|
9040
|
+
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)}`);
|
|
9041
|
+
close_websocket(gobj);
|
|
9042
|
+
return -1;
|
|
9043
|
+
}
|
|
9044
|
+
let iev_dst_yuno = kw_get_str(gobj, event_id, "dst_yuno", "");
|
|
9045
|
+
if (!empty_string(iev_dst_yuno) && iev_dst_yuno.toLowerCase() !== String(gobj_yuno_name()).toLowerCase()) {
|
|
9046
|
+
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)}`);
|
|
9047
|
+
close_websocket(gobj);
|
|
9048
|
+
return -1;
|
|
8874
9049
|
}
|
|
8875
9050
|
let iev_dst_service = kw_get_str(gobj, event_id, "dst_service", "");
|
|
8876
9051
|
if (msg_type === "__subscribing__") {
|
|
@@ -8892,13 +9067,18 @@ function ac_on_message(gobj, event, kw, src) {
|
|
|
8892
9067
|
return 0;
|
|
8893
9068
|
}
|
|
8894
9069
|
if (!gobj_has_event(gobj_service, iev_event, event_flag_t.EVF_PUBLIC_EVENT)) {
|
|
8895
|
-
|
|
9070
|
+
log_warning(`${gobj_short_name(gobj)}: Service found but no event or not public, DROPPED: service '${gobj_short_name(gobj_service)}', ev '${peer_text_shown(iev_event, PEER_NAME_SHOWN)}'`);
|
|
8896
9071
|
return -1;
|
|
8897
9072
|
}
|
|
8898
9073
|
gobj_send_event(gobj_service, iev_event, iev_kw, gobj);
|
|
8899
9074
|
return 0;
|
|
8900
9075
|
}
|
|
8901
|
-
|
|
9076
|
+
let event_type = gobj_find_event_type(iev_event, 0, false);
|
|
9077
|
+
if (!event_type) {
|
|
9078
|
+
log_warning(`${gobj_short_name(gobj)}: event that no gclass declares, DROPPED: ev '${peer_text_shown(iev_event, PEER_NAME_SHOWN)}'`);
|
|
9079
|
+
return -1;
|
|
9080
|
+
}
|
|
9081
|
+
gobj_publish_event(gobj, event_type.event_name, iev_kw);
|
|
8902
9082
|
return 0;
|
|
8903
9083
|
}
|
|
8904
9084
|
/***************************************************************************
|
|
@@ -9113,6 +9293,7 @@ exports.gobj_default_service = gobj_default_service;
|
|
|
9113
9293
|
exports.gobj_deliver_posted_events = gobj_deliver_posted_events;
|
|
9114
9294
|
exports.gobj_destroy = gobj_destroy;
|
|
9115
9295
|
exports.gobj_find_child = gobj_find_child;
|
|
9296
|
+
exports.gobj_find_event_type = gobj_find_event_type;
|
|
9116
9297
|
exports.gobj_find_gobj = gobj_find_gobj;
|
|
9117
9298
|
exports.gobj_find_service = gobj_find_service;
|
|
9118
9299
|
exports.gobj_find_subscribings = gobj_find_subscribings;
|