@kehto/runtime 0.12.0 → 0.14.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 +103 -136
- package/dist/index.js.map +1 -1
- package/package.json +8 -8
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
|
}
|
|
@@ -1208,12 +1164,18 @@ function createRuntimeDomainHandlers(context) {
|
|
|
1208
1164
|
cvm: (windowId, msg) => handleServiceOnlyMessage(context, "cvm", windowId, msg),
|
|
1209
1165
|
outbox: (windowId, msg) => handleServiceOnlyMessage(context, "outbox", windowId, msg),
|
|
1210
1166
|
upload: (windowId, msg) => handleServiceOnlyMessage(context, "upload", windowId, msg),
|
|
1211
|
-
intent: (windowId, msg) => handleServiceOnlyMessage(context, "intent", windowId, msg)
|
|
1167
|
+
intent: (windowId, msg) => handleServiceOnlyMessage(context, "intent", windowId, msg),
|
|
1168
|
+
link: (windowId, msg) => handleServiceOnlyMessage(context, "link", windowId, msg),
|
|
1169
|
+
common: (windowId, msg) => handleServiceOnlyMessage(context, "common", windowId, msg),
|
|
1170
|
+
lists: (windowId, msg) => handleServiceOnlyMessage(context, "lists", windowId, msg),
|
|
1171
|
+
serial: (windowId, msg) => handleServiceOnlyMessage(context, "serial", windowId, msg),
|
|
1172
|
+
ble: (windowId, msg) => handleServiceOnlyMessage(context, "ble", windowId, msg),
|
|
1173
|
+
webrtc: (windowId, msg) => handleServiceOnlyMessage(context, "webrtc", windowId, msg)
|
|
1212
1174
|
};
|
|
1213
1175
|
}
|
|
1214
1176
|
function handleStorageMessage(context, windowId, msg) {
|
|
1215
1177
|
const { aclState, hooks, sessionRegistry } = context;
|
|
1216
|
-
|
|
1178
|
+
handleStorageNap(windowId, msg, hooks.sendToNapplet, sessionRegistry, aclState, hooks.statePersistence);
|
|
1217
1179
|
}
|
|
1218
1180
|
function handleMediaMessage(context, windowId, msg) {
|
|
1219
1181
|
const { hooks, serviceRegistry } = context;
|
|
@@ -1331,31 +1293,36 @@ function createRegisteredServices(serviceRegistry) {
|
|
|
1331
1293
|
}
|
|
1332
1294
|
return registeredServices;
|
|
1333
1295
|
}
|
|
1334
|
-
function
|
|
1296
|
+
function createNapEnvelopeDispatcher(handlers) {
|
|
1335
1297
|
let currentWindowId = null;
|
|
1336
|
-
const
|
|
1298
|
+
const napDispatch = createDispatch();
|
|
1337
1299
|
const adapt = (handler) => (msg) => {
|
|
1338
1300
|
if (currentWindowId !== null) handler(currentWindowId, msg);
|
|
1339
1301
|
};
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
|
|
1346
|
-
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
|
|
1302
|
+
napDispatch.registerNap("relay", adapt(handlers.relay));
|
|
1303
|
+
napDispatch.registerNap("identity", adapt(handlers.identity));
|
|
1304
|
+
napDispatch.registerNap("keys", adapt(handlers.keys));
|
|
1305
|
+
napDispatch.registerNap("media", adapt(handlers.media));
|
|
1306
|
+
napDispatch.registerNap("notify", adapt(handlers.notify));
|
|
1307
|
+
napDispatch.registerNap("storage", adapt(handlers.storage));
|
|
1308
|
+
napDispatch.registerNap("inc", adapt(handlers.inc));
|
|
1309
|
+
napDispatch.registerNap("theme", adapt(handlers.theme));
|
|
1310
|
+
napDispatch.registerNap("config", adapt(handlers.config));
|
|
1311
|
+
napDispatch.registerNap("resource", adapt(handlers.resource));
|
|
1312
|
+
napDispatch.registerNap("cvm", adapt(handlers.cvm));
|
|
1313
|
+
napDispatch.registerNap("outbox", adapt(handlers.outbox));
|
|
1314
|
+
napDispatch.registerNap("upload", adapt(handlers.upload));
|
|
1315
|
+
napDispatch.registerNap("intent", adapt(handlers.intent));
|
|
1316
|
+
napDispatch.registerNap("link", adapt(handlers.link));
|
|
1317
|
+
napDispatch.registerNap("common", adapt(handlers.common));
|
|
1318
|
+
napDispatch.registerNap("lists", adapt(handlers.lists));
|
|
1319
|
+
napDispatch.registerNap("serial", adapt(handlers.serial));
|
|
1320
|
+
napDispatch.registerNap("ble", adapt(handlers.ble));
|
|
1321
|
+
napDispatch.registerNap("webrtc", adapt(handlers.webrtc));
|
|
1355
1322
|
return (windowId, envelope) => {
|
|
1356
1323
|
currentWindowId = windowId;
|
|
1357
1324
|
try {
|
|
1358
|
-
|
|
1325
|
+
napDispatch.dispatch(envelope);
|
|
1359
1326
|
} finally {
|
|
1360
1327
|
currentWindowId = null;
|
|
1361
1328
|
}
|
|
@@ -1421,15 +1388,15 @@ function createFirewallGate(config) {
|
|
|
1421
1388
|
return "dispatch";
|
|
1422
1389
|
};
|
|
1423
1390
|
}
|
|
1424
|
-
function createMessageHandler(hooks,
|
|
1391
|
+
function createMessageHandler(hooks, enforceNap, dispatchNapEnvelope, firewallGate) {
|
|
1425
1392
|
return (windowId, msg) => {
|
|
1426
1393
|
if (typeof msg !== "object" || msg === null || !("type" in msg)) return;
|
|
1427
1394
|
const envelope = msg;
|
|
1428
1395
|
const dotIdx = envelope.type.indexOf(".");
|
|
1429
1396
|
if (dotIdx === -1) return;
|
|
1430
|
-
const caps =
|
|
1397
|
+
const caps = resolveCapabilitiesNap(envelope);
|
|
1431
1398
|
if (caps.senderCap) {
|
|
1432
|
-
const result =
|
|
1399
|
+
const result = enforceNap(windowId, caps.senderCap, envelope);
|
|
1433
1400
|
if (!result.allowed) {
|
|
1434
1401
|
const id = envelope.id ?? "";
|
|
1435
1402
|
const isStorageEnvelope = envelope.type.startsWith("storage.");
|
|
@@ -1441,7 +1408,7 @@ function createMessageHandler(hooks, enforceNub, dispatchNubEnvelope, firewallGa
|
|
|
1441
1408
|
}
|
|
1442
1409
|
const verdict = firewallGate(windowId, envelope, caps.senderCap);
|
|
1443
1410
|
if (verdict === "drop") return;
|
|
1444
|
-
|
|
1411
|
+
dispatchNapEnvelope(windowId, envelope);
|
|
1445
1412
|
};
|
|
1446
1413
|
}
|
|
1447
1414
|
function createInjectedEvent(hooks, topic, payload) {
|
|
@@ -1462,7 +1429,7 @@ function createRuntimeInstance(context) {
|
|
|
1462
1429
|
firewallState,
|
|
1463
1430
|
eventBuffer,
|
|
1464
1431
|
hooks,
|
|
1465
|
-
|
|
1432
|
+
incRuntime,
|
|
1466
1433
|
manifestCache,
|
|
1467
1434
|
registeredServices,
|
|
1468
1435
|
replayDetector,
|
|
@@ -1483,7 +1450,7 @@ function createRuntimeInstance(context) {
|
|
|
1483
1450
|
firewallState.persist();
|
|
1484
1451
|
replayDetector.clear();
|
|
1485
1452
|
subscriptions.clear();
|
|
1486
|
-
|
|
1453
|
+
incRuntime.clear();
|
|
1487
1454
|
eventBuffer.clear();
|
|
1488
1455
|
registeredServices.clear();
|
|
1489
1456
|
undeclaredServiceConsents.clear();
|
|
@@ -1510,7 +1477,7 @@ function createRuntimeInstance(context) {
|
|
|
1510
1477
|
hooks.relayPool?.untrackSubscription(key);
|
|
1511
1478
|
}
|
|
1512
1479
|
}
|
|
1513
|
-
|
|
1480
|
+
incRuntime.destroyWindow(windowId);
|
|
1514
1481
|
notifyServiceWindowDestroyed(windowId, serviceRegistry);
|
|
1515
1482
|
},
|
|
1516
1483
|
get sessionRegistry() {
|
|
@@ -1561,11 +1528,11 @@ function createRuntime(hooks) {
|
|
|
1561
1528
|
},
|
|
1562
1529
|
onAclCheck: hooks.onAclCheck
|
|
1563
1530
|
});
|
|
1564
|
-
const
|
|
1531
|
+
const enforceNap = createNapEnforceGate({
|
|
1565
1532
|
checkAcl: (pubkey, dTag, aggregateHash, capability) => aclState.check(pubkey, dTag, aggregateHash, capability),
|
|
1566
1533
|
resolveIdentityByWindowId: (windowId) => {
|
|
1567
1534
|
const entry = sessionRegistry.getEntryByWindowId(windowId);
|
|
1568
|
-
return entry ? { dTag: entry.dTag, aggregateHash: entry.aggregateHash
|
|
1535
|
+
return entry ? { dTag: entry.dTag, aggregateHash: entry.aggregateHash } : void 0;
|
|
1569
1536
|
},
|
|
1570
1537
|
onAclCheck: hooks.onAclCheck
|
|
1571
1538
|
});
|
|
@@ -1580,15 +1547,15 @@ function createRuntime(hooks) {
|
|
|
1580
1547
|
aclState.load();
|
|
1581
1548
|
firewallState.load();
|
|
1582
1549
|
manifestCache.load();
|
|
1583
|
-
const
|
|
1550
|
+
const incRuntime = createIncRuntime(hooks, sessionRegistry);
|
|
1584
1551
|
const domainHandlers = createRuntimeDomainHandlers({ hooks, serviceRegistry, sessionRegistry, aclState });
|
|
1585
|
-
const
|
|
1552
|
+
const dispatchNapEnvelope = createNapEnvelopeDispatcher({
|
|
1586
1553
|
relay: createRelayHandler({ hooks, serviceRegistry, subscriptions, eventBuffer, replayDetector }),
|
|
1587
1554
|
identity: createIdentityHandler({ hooks, serviceRegistry }),
|
|
1588
|
-
|
|
1555
|
+
inc: incRuntime.handleMessage,
|
|
1589
1556
|
...domainHandlers
|
|
1590
1557
|
});
|
|
1591
|
-
const handleMessage = createMessageHandler(hooks,
|
|
1558
|
+
const handleMessage = createMessageHandler(hooks, enforceNap, dispatchNapEnvelope, firewallGate);
|
|
1592
1559
|
return createRuntimeInstance({
|
|
1593
1560
|
hooks,
|
|
1594
1561
|
serviceRegistry,
|
|
@@ -1596,7 +1563,7 @@ function createRuntime(hooks) {
|
|
|
1596
1563
|
replayDetector,
|
|
1597
1564
|
subscriptions,
|
|
1598
1565
|
eventBuffer,
|
|
1599
|
-
|
|
1566
|
+
incRuntime,
|
|
1600
1567
|
sessionRegistry,
|
|
1601
1568
|
aclState,
|
|
1602
1569
|
firewallState,
|
|
@@ -1607,9 +1574,9 @@ function createRuntime(hooks) {
|
|
|
1607
1574
|
}
|
|
1608
1575
|
|
|
1609
1576
|
// src/index.ts
|
|
1610
|
-
import { ALL_CAPABILITIES
|
|
1577
|
+
import { ALL_CAPABILITIES } from "@kehto/acl/capabilities";
|
|
1611
1578
|
export {
|
|
1612
|
-
|
|
1579
|
+
ALL_CAPABILITIES,
|
|
1613
1580
|
RING_BUFFER_SIZE,
|
|
1614
1581
|
cleanupNappState,
|
|
1615
1582
|
createAclState,
|
|
@@ -1617,17 +1584,17 @@ export {
|
|
|
1617
1584
|
createEventBuffer,
|
|
1618
1585
|
createFirewallState,
|
|
1619
1586
|
createManifestCache,
|
|
1587
|
+
createNapEnforceGate,
|
|
1620
1588
|
createNappKeyRegistry,
|
|
1621
|
-
createNubEnforceGate,
|
|
1622
1589
|
createReplayDetector,
|
|
1623
1590
|
createRuntime,
|
|
1624
1591
|
createSessionRegistry,
|
|
1625
1592
|
formatDenialReason,
|
|
1626
|
-
|
|
1593
|
+
handleStorageNap,
|
|
1627
1594
|
matchesAnyFilter,
|
|
1628
1595
|
matchesFilter,
|
|
1629
1596
|
notifyServiceWindowDestroyed,
|
|
1630
|
-
|
|
1597
|
+
resolveCapabilitiesNap,
|
|
1631
1598
|
routeServiceMessage
|
|
1632
1599
|
};
|
|
1633
1600
|
//# sourceMappingURL=index.js.map
|