@kehto/runtime 0.12.0 → 0.13.0
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 +5 -5
- package/dist/index.d.ts +31 -48
- package/dist/index.js +90 -135
- package/dist/index.js.map +1 -1
- package/package.json +7 -7
package/dist/index.js
CHANGED
|
@@ -1,12 +1,5 @@
|
|
|
1
1
|
// src/enforce.ts
|
|
2
|
-
import {
|
|
3
|
-
import { resolveCapabilitiesNub } from "@kehto/acl";
|
|
4
|
-
var CLASS_CAPABILITY_ALLOWLIST = Object.freeze({
|
|
5
|
-
"class-1": new Set(ALL_CAPABILITIES),
|
|
6
|
-
"class-2": new Set(ALL_CAPABILITIES.filter(
|
|
7
|
-
(c) => c !== "relay:write" && c !== "outbox:write" && c !== "intent:write"
|
|
8
|
-
))
|
|
9
|
-
});
|
|
2
|
+
import { resolveCapabilitiesNap } from "@kehto/acl";
|
|
10
3
|
function createEnforceGate(config) {
|
|
11
4
|
const { checkAcl, resolveIdentity, onAclCheck } = config;
|
|
12
5
|
return function enforce(pubkey, capability, message) {
|
|
@@ -23,29 +16,12 @@ function createEnforceGate(config) {
|
|
|
23
16
|
return { allowed, capability, reason };
|
|
24
17
|
};
|
|
25
18
|
}
|
|
26
|
-
function
|
|
19
|
+
function createNapEnforceGate(config) {
|
|
27
20
|
const { checkAcl, resolveIdentityByWindowId, onAclCheck } = config;
|
|
28
|
-
return function
|
|
21
|
+
return function enforceNap(windowId, capability, message) {
|
|
29
22
|
const entry = resolveIdentityByWindowId(windowId);
|
|
30
23
|
const dTag = entry?.dTag ?? "";
|
|
31
24
|
const aggregateHash = entry?.aggregateHash ?? "";
|
|
32
|
-
const nappletClass = entry?.class ?? null;
|
|
33
|
-
if (nappletClass !== null) {
|
|
34
|
-
const allowlist = CLASS_CAPABILITY_ALLOWLIST[nappletClass];
|
|
35
|
-
if (!allowlist || !allowlist.has(capability)) {
|
|
36
|
-
const identity2 = { pubkey: "", dTag, hash: aggregateHash };
|
|
37
|
-
if (onAclCheck) {
|
|
38
|
-
onAclCheck({
|
|
39
|
-
identity: identity2,
|
|
40
|
-
capability,
|
|
41
|
-
decision: "deny",
|
|
42
|
-
message,
|
|
43
|
-
reason: "class-forbidden"
|
|
44
|
-
});
|
|
45
|
-
}
|
|
46
|
-
return { allowed: false, capability, reason: "class-forbidden" };
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
25
|
const allowed = checkAcl("", dTag, aggregateHash, capability);
|
|
50
26
|
const identity = { pubkey: "", dTag, hash: aggregateHash };
|
|
51
27
|
const decision = allowed ? "allow" : "deny";
|
|
@@ -513,12 +489,12 @@ function routeServiceMessage(windowId, message, services, sendToNapplet) {
|
|
|
513
489
|
handler.handleMessage(windowId, message, (msg) => sendToNapplet(windowId, msg));
|
|
514
490
|
return true;
|
|
515
491
|
}
|
|
516
|
-
const
|
|
517
|
-
if (message.type === "
|
|
518
|
-
const prefix =
|
|
519
|
-
const
|
|
520
|
-
if (
|
|
521
|
-
|
|
492
|
+
const incMessage = message;
|
|
493
|
+
if (message.type === "inc.emit" && typeof incMessage.topic === "string") {
|
|
494
|
+
const prefix = incMessage.topic.split(":")[0];
|
|
495
|
+
const incHandler = services[prefix];
|
|
496
|
+
if (incHandler) {
|
|
497
|
+
incHandler.handleMessage(windowId, message, (msg) => sendToNapplet(windowId, msg));
|
|
522
498
|
return true;
|
|
523
499
|
}
|
|
524
500
|
}
|
|
@@ -600,9 +576,10 @@ function handleRelaySubscribe(context, windowId, msg, m) {
|
|
|
600
576
|
}
|
|
601
577
|
return;
|
|
602
578
|
}
|
|
603
|
-
|
|
579
|
+
const relayHint = typeof m.relay === "string" && m.relay.length > 0 ? m.relay : void 0;
|
|
580
|
+
deliverFromRuntimeBackends(context, windowId, subId, subKey, filters, isShellKind, deliver, relayHint);
|
|
604
581
|
}
|
|
605
|
-
function deliverFromRuntimeBackends(context, windowId, subId, subKey, filters, isShellKind, deliver) {
|
|
582
|
+
function deliverFromRuntimeBackends(context, windowId, subId, subKey, filters, isShellKind, deliver, relayHint) {
|
|
606
583
|
const { hooks } = context;
|
|
607
584
|
const cache = hooks.cache;
|
|
608
585
|
if (cache?.isAvailable() && !isShellKind) {
|
|
@@ -617,7 +594,7 @@ function deliverFromRuntimeBackends(context, windowId, subId, subKey, filters, i
|
|
|
617
594
|
return;
|
|
618
595
|
}
|
|
619
596
|
if (!pool?.isAvailable() || isShellKind) return;
|
|
620
|
-
const relayUrls = pool.selectRelayTier(filters);
|
|
597
|
+
const relayUrls = relayHint ? [relayHint] : pool.selectRelayTier(filters);
|
|
621
598
|
let eoseSent = false;
|
|
622
599
|
const eoseFallbackTimer = setTimeout(() => {
|
|
623
600
|
if (!eoseSent) {
|
|
@@ -837,39 +814,28 @@ function createIdentityHandler(context) {
|
|
|
837
814
|
};
|
|
838
815
|
}
|
|
839
816
|
|
|
840
|
-
// src/
|
|
841
|
-
function
|
|
817
|
+
// src/inc-handler.ts
|
|
818
|
+
function createIncRuntime(hooks, sessionRegistry) {
|
|
842
819
|
const state = {
|
|
843
820
|
subscriptions: /* @__PURE__ */ new Map(),
|
|
844
821
|
channels: /* @__PURE__ */ new Map(),
|
|
845
|
-
channelsByWindow: /* @__PURE__ */ new Map()
|
|
846
|
-
domainByWindow: /* @__PURE__ */ new Map()
|
|
822
|
+
channelsByWindow: /* @__PURE__ */ new Map()
|
|
847
823
|
};
|
|
848
824
|
return {
|
|
849
825
|
handleMessage(windowId, msg) {
|
|
850
|
-
|
|
826
|
+
handleIncMessage(state, hooks, sessionRegistry, windowId, msg);
|
|
851
827
|
},
|
|
852
828
|
destroyWindow(windowId) {
|
|
853
829
|
removeWindowChannels(state, hooks, windowId);
|
|
854
830
|
removeWindowSubscriptions(state, windowId);
|
|
855
|
-
state.domainByWindow.delete(windowId);
|
|
856
831
|
},
|
|
857
832
|
clear() {
|
|
858
833
|
state.subscriptions.clear();
|
|
859
834
|
state.channels.clear();
|
|
860
835
|
state.channelsByWindow.clear();
|
|
861
|
-
state.domainByWindow.clear();
|
|
862
836
|
}
|
|
863
837
|
};
|
|
864
838
|
}
|
|
865
|
-
function domainOf(type) {
|
|
866
|
-
const dot = type.indexOf(".");
|
|
867
|
-
const d = dot === -1 ? type : type.slice(0, dot);
|
|
868
|
-
return d === "inc" ? "inc" : "ifc";
|
|
869
|
-
}
|
|
870
|
-
function prefixFor(state, windowId, fallback) {
|
|
871
|
-
return state.domainByWindow.get(windowId) ?? fallback;
|
|
872
|
-
}
|
|
873
839
|
function addChannel(state, channelId, peerA, peerB) {
|
|
874
840
|
state.channels.set(channelId, { channelId, peerA, peerB });
|
|
875
841
|
for (const windowId of [peerA, peerB]) {
|
|
@@ -905,60 +871,55 @@ function resolveTarget(sessionRegistry, target) {
|
|
|
905
871
|
const byPubkey = entries.find((entry) => entry.pubkey === target);
|
|
906
872
|
return byPubkey?.windowId ?? null;
|
|
907
873
|
}
|
|
908
|
-
function
|
|
874
|
+
function handleIncMessage(state, hooks, sessionRegistry, windowId, msg) {
|
|
909
875
|
const m = msg;
|
|
910
876
|
const dotIdx = msg.type.indexOf(".");
|
|
911
877
|
const action = msg.type.slice(dotIdx + 1);
|
|
912
|
-
const incomingDomain = domainOf(msg.type);
|
|
913
|
-
if (!state.domainByWindow.has(windowId)) {
|
|
914
|
-
state.domainByWindow.set(windowId, incomingDomain);
|
|
915
|
-
}
|
|
916
878
|
switch (action) {
|
|
917
879
|
case "emit":
|
|
918
|
-
handleEmit(state, hooks, windowId, m
|
|
880
|
+
handleEmit(state, hooks, windowId, m);
|
|
919
881
|
return;
|
|
920
882
|
case "subscribe":
|
|
921
|
-
handleSubscribe(state, hooks, windowId, m
|
|
883
|
+
handleSubscribe(state, hooks, windowId, m);
|
|
922
884
|
return;
|
|
923
885
|
case "unsubscribe":
|
|
924
886
|
handleUnsubscribe(state, windowId, m);
|
|
925
887
|
return;
|
|
926
888
|
case "channel.open":
|
|
927
|
-
handleChannelOpen(state, hooks, sessionRegistry, windowId, m
|
|
889
|
+
handleChannelOpen(state, hooks, sessionRegistry, windowId, m);
|
|
928
890
|
return;
|
|
929
891
|
case "channel.emit":
|
|
930
|
-
handleChannelEmit(state, hooks, windowId, m
|
|
892
|
+
handleChannelEmit(state, hooks, windowId, m);
|
|
931
893
|
return;
|
|
932
894
|
case "channel.broadcast":
|
|
933
|
-
handleChannelBroadcast(state, hooks, windowId, m
|
|
895
|
+
handleChannelBroadcast(state, hooks, windowId, m);
|
|
934
896
|
return;
|
|
935
897
|
case "channel.list":
|
|
936
|
-
handleChannelList(state, hooks, windowId, m
|
|
898
|
+
handleChannelList(state, hooks, windowId, m);
|
|
937
899
|
return;
|
|
938
900
|
case "channel.close":
|
|
939
|
-
handleChannelClose(state, hooks, windowId, m
|
|
901
|
+
handleChannelClose(state, hooks, windowId, m);
|
|
940
902
|
return;
|
|
941
903
|
default:
|
|
942
904
|
return;
|
|
943
905
|
}
|
|
944
906
|
}
|
|
945
|
-
function handleEmit(state, hooks, windowId, m
|
|
907
|
+
function handleEmit(state, hooks, windowId, m) {
|
|
946
908
|
const topic = m.topic ?? "";
|
|
947
909
|
if (!topic) return;
|
|
948
910
|
const subscribers = state.subscriptions.get(topic);
|
|
949
911
|
if (!subscribers) return;
|
|
950
912
|
for (const subscriberWindowId of subscribers) {
|
|
951
913
|
if (subscriberWindowId !== windowId) {
|
|
952
|
-
|
|
953
|
-
hooks.sendToNapplet(subscriberWindowId, { type: `${prefix}.event`, topic, payload: m.payload, sender: windowId });
|
|
914
|
+
hooks.sendToNapplet(subscriberWindowId, { type: "inc.event", topic, payload: m.payload, sender: windowId });
|
|
954
915
|
}
|
|
955
916
|
}
|
|
956
917
|
}
|
|
957
|
-
function handleSubscribe(state, hooks, windowId, m
|
|
918
|
+
function handleSubscribe(state, hooks, windowId, m) {
|
|
958
919
|
const id = m.id ?? "";
|
|
959
920
|
const topic = m.topic ?? "";
|
|
960
921
|
if (!topic) {
|
|
961
|
-
hooks.sendToNapplet(windowId, { type:
|
|
922
|
+
hooks.sendToNapplet(windowId, { type: "inc.subscribe.result", id, error: "missing topic" });
|
|
962
923
|
return;
|
|
963
924
|
}
|
|
964
925
|
let subscriptions = state.subscriptions.get(topic);
|
|
@@ -967,7 +928,7 @@ function handleSubscribe(state, hooks, windowId, m, incomingDomain) {
|
|
|
967
928
|
state.subscriptions.set(topic, subscriptions);
|
|
968
929
|
}
|
|
969
930
|
subscriptions.add(windowId);
|
|
970
|
-
hooks.sendToNapplet(windowId, { type:
|
|
931
|
+
hooks.sendToNapplet(windowId, { type: "inc.subscribe.result", id });
|
|
971
932
|
}
|
|
972
933
|
function handleUnsubscribe(state, windowId, m) {
|
|
973
934
|
const topic = m.topic ?? "";
|
|
@@ -977,36 +938,34 @@ function handleUnsubscribe(state, windowId, m) {
|
|
|
977
938
|
subscriptions.delete(windowId);
|
|
978
939
|
if (subscriptions.size === 0) state.subscriptions.delete(topic);
|
|
979
940
|
}
|
|
980
|
-
function handleChannelOpen(state, hooks, sessionRegistry, windowId, m
|
|
941
|
+
function handleChannelOpen(state, hooks, sessionRegistry, windowId, m) {
|
|
981
942
|
const id = m.id ?? "";
|
|
982
943
|
const peerWindow = resolveTarget(sessionRegistry, m.target ?? "");
|
|
983
944
|
if (!peerWindow) {
|
|
984
|
-
hooks.sendToNapplet(windowId, { type:
|
|
945
|
+
hooks.sendToNapplet(windowId, { type: "inc.channel.open.result", id, error: "target not found" });
|
|
985
946
|
return;
|
|
986
947
|
}
|
|
987
948
|
const channelId = hooks.crypto.randomUUID().replace(/-/g, "").slice(0, 32);
|
|
988
949
|
addChannel(state, channelId, windowId, peerWindow);
|
|
989
|
-
hooks.sendToNapplet(windowId, { type:
|
|
950
|
+
hooks.sendToNapplet(windowId, { type: "inc.channel.open.result", id, channelId, peer: peerWindow });
|
|
990
951
|
}
|
|
991
|
-
function handleChannelEmit(state, hooks, windowId, m
|
|
952
|
+
function handleChannelEmit(state, hooks, windowId, m) {
|
|
992
953
|
const peer = peerOf(state, m.channelId ?? "", windowId);
|
|
993
954
|
if (peer) {
|
|
994
|
-
|
|
995
|
-
hooks.sendToNapplet(peer, { type: `${prefix}.channel.event`, channelId: m.channelId ?? "", sender: windowId, payload: m.payload });
|
|
955
|
+
hooks.sendToNapplet(peer, { type: "inc.channel.event", channelId: m.channelId ?? "", sender: windowId, payload: m.payload });
|
|
996
956
|
}
|
|
997
957
|
}
|
|
998
|
-
function handleChannelBroadcast(state, hooks, windowId, m
|
|
958
|
+
function handleChannelBroadcast(state, hooks, windowId, m) {
|
|
999
959
|
const channels = state.channelsByWindow.get(windowId);
|
|
1000
960
|
if (!channels) return;
|
|
1001
961
|
for (const channelId of channels) {
|
|
1002
962
|
const peer = peerOf(state, channelId, windowId);
|
|
1003
963
|
if (peer) {
|
|
1004
|
-
|
|
1005
|
-
hooks.sendToNapplet(peer, { type: `${prefix}.channel.event`, channelId, sender: windowId, payload: m.payload });
|
|
964
|
+
hooks.sendToNapplet(peer, { type: "inc.channel.event", channelId, sender: windowId, payload: m.payload });
|
|
1006
965
|
}
|
|
1007
966
|
}
|
|
1008
967
|
}
|
|
1009
|
-
function handleChannelList(state, hooks, windowId, m
|
|
968
|
+
function handleChannelList(state, hooks, windowId, m) {
|
|
1010
969
|
const channels = [];
|
|
1011
970
|
const set = state.channelsByWindow.get(windowId);
|
|
1012
971
|
if (set) {
|
|
@@ -1015,15 +974,14 @@ function handleChannelList(state, hooks, windowId, m, incomingDomain) {
|
|
|
1015
974
|
if (peer) channels.push({ id: channelId, peer });
|
|
1016
975
|
}
|
|
1017
976
|
}
|
|
1018
|
-
hooks.sendToNapplet(windowId, { type:
|
|
977
|
+
hooks.sendToNapplet(windowId, { type: "inc.channel.list.result", id: m.id ?? "", channels });
|
|
1019
978
|
}
|
|
1020
|
-
function handleChannelClose(state, hooks, windowId, m
|
|
979
|
+
function handleChannelClose(state, hooks, windowId, m) {
|
|
1021
980
|
const channelId = m.channelId ?? "";
|
|
1022
981
|
const peer = peerOf(state, channelId, windowId);
|
|
1023
982
|
if (!peer) return;
|
|
1024
|
-
hooks.sendToNapplet(windowId, { type:
|
|
1025
|
-
|
|
1026
|
-
hooks.sendToNapplet(peer, { type: `${peerPrefix}.channel.closed`, channelId });
|
|
983
|
+
hooks.sendToNapplet(windowId, { type: "inc.channel.closed", channelId });
|
|
984
|
+
hooks.sendToNapplet(peer, { type: "inc.channel.closed", channelId });
|
|
1027
985
|
removeChannel(state, channelId);
|
|
1028
986
|
}
|
|
1029
987
|
function removeWindowSubscriptions(state, windowId) {
|
|
@@ -1038,9 +996,7 @@ function removeWindowChannels(state, hooks, windowId) {
|
|
|
1038
996
|
for (const channelId of Array.from(channelIds)) {
|
|
1039
997
|
const peer = peerOf(state, channelId, windowId);
|
|
1040
998
|
if (peer) {
|
|
1041
|
-
|
|
1042
|
-
const peerPrefix = prefixFor(state, peer, destroyeeDomain);
|
|
1043
|
-
hooks.sendToNapplet(peer, { type: `${peerPrefix}.channel.closed`, channelId });
|
|
999
|
+
hooks.sendToNapplet(peer, { type: "inc.channel.closed", channelId });
|
|
1044
1000
|
}
|
|
1045
1001
|
removeChannel(state, channelId);
|
|
1046
1002
|
}
|
|
@@ -1072,26 +1028,26 @@ function byteLength(str) {
|
|
|
1072
1028
|
}
|
|
1073
1029
|
return bytes;
|
|
1074
1030
|
}
|
|
1075
|
-
function
|
|
1031
|
+
function handleStorageNap(windowId, msg, sendToNapplet, sessionRegistry, aclState, statePersistence) {
|
|
1076
1032
|
const m = msg;
|
|
1077
1033
|
const id = m.id ?? "";
|
|
1078
1034
|
const action = msg.type.split(".")[1];
|
|
1079
1035
|
function sendResult(payload) {
|
|
1080
1036
|
sendToNapplet(windowId, { type: `${msg.type}.result`, id, ...payload });
|
|
1081
1037
|
}
|
|
1082
|
-
function
|
|
1038
|
+
function sendErrorNap(error) {
|
|
1083
1039
|
sendToNapplet(windowId, { type: `${msg.type}.result`, id, error });
|
|
1084
1040
|
}
|
|
1085
1041
|
const entry = sessionRegistry.getEntryByWindowId(windowId);
|
|
1086
1042
|
if (!entry) {
|
|
1087
|
-
|
|
1043
|
+
sendErrorNap("not registered");
|
|
1088
1044
|
return;
|
|
1089
1045
|
}
|
|
1090
1046
|
const { dTag, aggregateHash, pubkey } = entry;
|
|
1091
1047
|
const prefix = `napplet-state:${dTag}:${aggregateHash}:`;
|
|
1092
1048
|
const legacyPrefix = pubkey ? `napplet-state:${pubkey}:${dTag}:${aggregateHash}:` : "";
|
|
1093
1049
|
if (m.scope !== void 0 && m.scope !== "shared" && m.scope !== "instance") {
|
|
1094
|
-
|
|
1050
|
+
sendErrorNap(`invalid scope: ${String(m.scope)} (expected "shared" or "instance")`);
|
|
1095
1051
|
return;
|
|
1096
1052
|
}
|
|
1097
1053
|
const scope = m.scope === "instance" ? "instance" : "shared";
|
|
@@ -1102,7 +1058,7 @@ function handleStorageNub(windowId, msg, sendToNapplet, sessionRegistry, aclStat
|
|
|
1102
1058
|
case "get": {
|
|
1103
1059
|
const key = m.key;
|
|
1104
1060
|
if (!key) {
|
|
1105
|
-
|
|
1061
|
+
sendErrorNap("missing key");
|
|
1106
1062
|
return;
|
|
1107
1063
|
}
|
|
1108
1064
|
if (isInstance) {
|
|
@@ -1124,7 +1080,7 @@ function handleStorageNub(windowId, msg, sendToNapplet, sessionRegistry, aclStat
|
|
|
1124
1080
|
const key = m.key;
|
|
1125
1081
|
const value = m.value ?? "";
|
|
1126
1082
|
if (!key) {
|
|
1127
|
-
|
|
1083
|
+
sendErrorNap("missing key");
|
|
1128
1084
|
return;
|
|
1129
1085
|
}
|
|
1130
1086
|
const quota = aclState.getStateQuota(pubkey ?? "", dTag, aggregateHash);
|
|
@@ -1132,7 +1088,7 @@ function handleStorageNub(windowId, msg, sendToNapplet, sessionRegistry, aclStat
|
|
|
1132
1088
|
const newWriteBytes = byteLength(sk + value);
|
|
1133
1089
|
const existingBytes = statePersistence.calculateBytes(prefix, key);
|
|
1134
1090
|
if (existingBytes + newWriteBytes > quota) {
|
|
1135
|
-
|
|
1091
|
+
sendErrorNap(`quota exceeded: napplet state limit is ${quota} bytes`);
|
|
1136
1092
|
return;
|
|
1137
1093
|
}
|
|
1138
1094
|
const success = statePersistence.set(sk, value);
|
|
@@ -1142,7 +1098,7 @@ function handleStorageNub(windowId, msg, sendToNapplet, sessionRegistry, aclStat
|
|
|
1142
1098
|
case "remove": {
|
|
1143
1099
|
const key = m.key;
|
|
1144
1100
|
if (!key) {
|
|
1145
|
-
|
|
1101
|
+
sendErrorNap("missing key");
|
|
1146
1102
|
return;
|
|
1147
1103
|
}
|
|
1148
1104
|
statePersistence.remove(keyFor(key));
|
|
@@ -1151,7 +1107,7 @@ function handleStorageNub(windowId, msg, sendToNapplet, sessionRegistry, aclStat
|
|
|
1151
1107
|
break;
|
|
1152
1108
|
}
|
|
1153
1109
|
case "clear": {
|
|
1154
|
-
|
|
1110
|
+
sendErrorNap("storage.clear is not in @napplet/nap/storage; action not supported");
|
|
1155
1111
|
break;
|
|
1156
1112
|
}
|
|
1157
1113
|
case "keys": {
|
|
@@ -1181,7 +1137,7 @@ function handleStorageNub(windowId, msg, sendToNapplet, sessionRegistry, aclStat
|
|
|
1181
1137
|
break;
|
|
1182
1138
|
}
|
|
1183
1139
|
default:
|
|
1184
|
-
|
|
1140
|
+
sendErrorNap(`unknown storage action: ${action}`);
|
|
1185
1141
|
break;
|
|
1186
1142
|
}
|
|
1187
1143
|
}
|
|
@@ -1213,7 +1169,7 @@ function createRuntimeDomainHandlers(context) {
|
|
|
1213
1169
|
}
|
|
1214
1170
|
function handleStorageMessage(context, windowId, msg) {
|
|
1215
1171
|
const { aclState, hooks, sessionRegistry } = context;
|
|
1216
|
-
|
|
1172
|
+
handleStorageNap(windowId, msg, hooks.sendToNapplet, sessionRegistry, aclState, hooks.statePersistence);
|
|
1217
1173
|
}
|
|
1218
1174
|
function handleMediaMessage(context, windowId, msg) {
|
|
1219
1175
|
const { hooks, serviceRegistry } = context;
|
|
@@ -1331,31 +1287,30 @@ function createRegisteredServices(serviceRegistry) {
|
|
|
1331
1287
|
}
|
|
1332
1288
|
return registeredServices;
|
|
1333
1289
|
}
|
|
1334
|
-
function
|
|
1290
|
+
function createNapEnvelopeDispatcher(handlers) {
|
|
1335
1291
|
let currentWindowId = null;
|
|
1336
|
-
const
|
|
1292
|
+
const napDispatch = createDispatch();
|
|
1337
1293
|
const adapt = (handler) => (msg) => {
|
|
1338
1294
|
if (currentWindowId !== null) handler(currentWindowId, msg);
|
|
1339
1295
|
};
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
|
|
1346
|
-
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
nubDispatch.registerNap("intent", adapt(handlers.intent));
|
|
1296
|
+
napDispatch.registerNap("relay", adapt(handlers.relay));
|
|
1297
|
+
napDispatch.registerNap("identity", adapt(handlers.identity));
|
|
1298
|
+
napDispatch.registerNap("keys", adapt(handlers.keys));
|
|
1299
|
+
napDispatch.registerNap("media", adapt(handlers.media));
|
|
1300
|
+
napDispatch.registerNap("notify", adapt(handlers.notify));
|
|
1301
|
+
napDispatch.registerNap("storage", adapt(handlers.storage));
|
|
1302
|
+
napDispatch.registerNap("inc", adapt(handlers.inc));
|
|
1303
|
+
napDispatch.registerNap("theme", adapt(handlers.theme));
|
|
1304
|
+
napDispatch.registerNap("config", adapt(handlers.config));
|
|
1305
|
+
napDispatch.registerNap("resource", adapt(handlers.resource));
|
|
1306
|
+
napDispatch.registerNap("cvm", adapt(handlers.cvm));
|
|
1307
|
+
napDispatch.registerNap("outbox", adapt(handlers.outbox));
|
|
1308
|
+
napDispatch.registerNap("upload", adapt(handlers.upload));
|
|
1309
|
+
napDispatch.registerNap("intent", adapt(handlers.intent));
|
|
1355
1310
|
return (windowId, envelope) => {
|
|
1356
1311
|
currentWindowId = windowId;
|
|
1357
1312
|
try {
|
|
1358
|
-
|
|
1313
|
+
napDispatch.dispatch(envelope);
|
|
1359
1314
|
} finally {
|
|
1360
1315
|
currentWindowId = null;
|
|
1361
1316
|
}
|
|
@@ -1421,15 +1376,15 @@ function createFirewallGate(config) {
|
|
|
1421
1376
|
return "dispatch";
|
|
1422
1377
|
};
|
|
1423
1378
|
}
|
|
1424
|
-
function createMessageHandler(hooks,
|
|
1379
|
+
function createMessageHandler(hooks, enforceNap, dispatchNapEnvelope, firewallGate) {
|
|
1425
1380
|
return (windowId, msg) => {
|
|
1426
1381
|
if (typeof msg !== "object" || msg === null || !("type" in msg)) return;
|
|
1427
1382
|
const envelope = msg;
|
|
1428
1383
|
const dotIdx = envelope.type.indexOf(".");
|
|
1429
1384
|
if (dotIdx === -1) return;
|
|
1430
|
-
const caps =
|
|
1385
|
+
const caps = resolveCapabilitiesNap(envelope);
|
|
1431
1386
|
if (caps.senderCap) {
|
|
1432
|
-
const result =
|
|
1387
|
+
const result = enforceNap(windowId, caps.senderCap, envelope);
|
|
1433
1388
|
if (!result.allowed) {
|
|
1434
1389
|
const id = envelope.id ?? "";
|
|
1435
1390
|
const isStorageEnvelope = envelope.type.startsWith("storage.");
|
|
@@ -1441,7 +1396,7 @@ function createMessageHandler(hooks, enforceNub, dispatchNubEnvelope, firewallGa
|
|
|
1441
1396
|
}
|
|
1442
1397
|
const verdict = firewallGate(windowId, envelope, caps.senderCap);
|
|
1443
1398
|
if (verdict === "drop") return;
|
|
1444
|
-
|
|
1399
|
+
dispatchNapEnvelope(windowId, envelope);
|
|
1445
1400
|
};
|
|
1446
1401
|
}
|
|
1447
1402
|
function createInjectedEvent(hooks, topic, payload) {
|
|
@@ -1462,7 +1417,7 @@ function createRuntimeInstance(context) {
|
|
|
1462
1417
|
firewallState,
|
|
1463
1418
|
eventBuffer,
|
|
1464
1419
|
hooks,
|
|
1465
|
-
|
|
1420
|
+
incRuntime,
|
|
1466
1421
|
manifestCache,
|
|
1467
1422
|
registeredServices,
|
|
1468
1423
|
replayDetector,
|
|
@@ -1483,7 +1438,7 @@ function createRuntimeInstance(context) {
|
|
|
1483
1438
|
firewallState.persist();
|
|
1484
1439
|
replayDetector.clear();
|
|
1485
1440
|
subscriptions.clear();
|
|
1486
|
-
|
|
1441
|
+
incRuntime.clear();
|
|
1487
1442
|
eventBuffer.clear();
|
|
1488
1443
|
registeredServices.clear();
|
|
1489
1444
|
undeclaredServiceConsents.clear();
|
|
@@ -1510,7 +1465,7 @@ function createRuntimeInstance(context) {
|
|
|
1510
1465
|
hooks.relayPool?.untrackSubscription(key);
|
|
1511
1466
|
}
|
|
1512
1467
|
}
|
|
1513
|
-
|
|
1468
|
+
incRuntime.destroyWindow(windowId);
|
|
1514
1469
|
notifyServiceWindowDestroyed(windowId, serviceRegistry);
|
|
1515
1470
|
},
|
|
1516
1471
|
get sessionRegistry() {
|
|
@@ -1561,11 +1516,11 @@ function createRuntime(hooks) {
|
|
|
1561
1516
|
},
|
|
1562
1517
|
onAclCheck: hooks.onAclCheck
|
|
1563
1518
|
});
|
|
1564
|
-
const
|
|
1519
|
+
const enforceNap = createNapEnforceGate({
|
|
1565
1520
|
checkAcl: (pubkey, dTag, aggregateHash, capability) => aclState.check(pubkey, dTag, aggregateHash, capability),
|
|
1566
1521
|
resolveIdentityByWindowId: (windowId) => {
|
|
1567
1522
|
const entry = sessionRegistry.getEntryByWindowId(windowId);
|
|
1568
|
-
return entry ? { dTag: entry.dTag, aggregateHash: entry.aggregateHash
|
|
1523
|
+
return entry ? { dTag: entry.dTag, aggregateHash: entry.aggregateHash } : void 0;
|
|
1569
1524
|
},
|
|
1570
1525
|
onAclCheck: hooks.onAclCheck
|
|
1571
1526
|
});
|
|
@@ -1580,15 +1535,15 @@ function createRuntime(hooks) {
|
|
|
1580
1535
|
aclState.load();
|
|
1581
1536
|
firewallState.load();
|
|
1582
1537
|
manifestCache.load();
|
|
1583
|
-
const
|
|
1538
|
+
const incRuntime = createIncRuntime(hooks, sessionRegistry);
|
|
1584
1539
|
const domainHandlers = createRuntimeDomainHandlers({ hooks, serviceRegistry, sessionRegistry, aclState });
|
|
1585
|
-
const
|
|
1540
|
+
const dispatchNapEnvelope = createNapEnvelopeDispatcher({
|
|
1586
1541
|
relay: createRelayHandler({ hooks, serviceRegistry, subscriptions, eventBuffer, replayDetector }),
|
|
1587
1542
|
identity: createIdentityHandler({ hooks, serviceRegistry }),
|
|
1588
|
-
|
|
1543
|
+
inc: incRuntime.handleMessage,
|
|
1589
1544
|
...domainHandlers
|
|
1590
1545
|
});
|
|
1591
|
-
const handleMessage = createMessageHandler(hooks,
|
|
1546
|
+
const handleMessage = createMessageHandler(hooks, enforceNap, dispatchNapEnvelope, firewallGate);
|
|
1592
1547
|
return createRuntimeInstance({
|
|
1593
1548
|
hooks,
|
|
1594
1549
|
serviceRegistry,
|
|
@@ -1596,7 +1551,7 @@ function createRuntime(hooks) {
|
|
|
1596
1551
|
replayDetector,
|
|
1597
1552
|
subscriptions,
|
|
1598
1553
|
eventBuffer,
|
|
1599
|
-
|
|
1554
|
+
incRuntime,
|
|
1600
1555
|
sessionRegistry,
|
|
1601
1556
|
aclState,
|
|
1602
1557
|
firewallState,
|
|
@@ -1607,9 +1562,9 @@ function createRuntime(hooks) {
|
|
|
1607
1562
|
}
|
|
1608
1563
|
|
|
1609
1564
|
// src/index.ts
|
|
1610
|
-
import { ALL_CAPABILITIES
|
|
1565
|
+
import { ALL_CAPABILITIES } from "@kehto/acl/capabilities";
|
|
1611
1566
|
export {
|
|
1612
|
-
|
|
1567
|
+
ALL_CAPABILITIES,
|
|
1613
1568
|
RING_BUFFER_SIZE,
|
|
1614
1569
|
cleanupNappState,
|
|
1615
1570
|
createAclState,
|
|
@@ -1617,17 +1572,17 @@ export {
|
|
|
1617
1572
|
createEventBuffer,
|
|
1618
1573
|
createFirewallState,
|
|
1619
1574
|
createManifestCache,
|
|
1575
|
+
createNapEnforceGate,
|
|
1620
1576
|
createNappKeyRegistry,
|
|
1621
|
-
createNubEnforceGate,
|
|
1622
1577
|
createReplayDetector,
|
|
1623
1578
|
createRuntime,
|
|
1624
1579
|
createSessionRegistry,
|
|
1625
1580
|
formatDenialReason,
|
|
1626
|
-
|
|
1581
|
+
handleStorageNap,
|
|
1627
1582
|
matchesAnyFilter,
|
|
1628
1583
|
matchesFilter,
|
|
1629
1584
|
notifyServiceWindowDestroyed,
|
|
1630
|
-
|
|
1585
|
+
resolveCapabilitiesNap,
|
|
1631
1586
|
routeServiceMessage
|
|
1632
1587
|
};
|
|
1633
1588
|
//# sourceMappingURL=index.js.map
|