buckyos 0.7.127 → 0.7.128
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/cli/dist/cli.mjs +116 -31
- package/cli/dist/cli.mjs.map +1 -1
- package/cli/launcher.mjs +0 -0
- package/cli/modules/pikg.ts +5 -0
- package/cli/modules/pikg_protocol.ts +40 -0
- package/cli/runtime/host_deno.ts +16 -31
- package/cli/runtime/host_node.ts +15 -30
- package/cli/runtime/path_policy.ts +49 -0
- package/cli/version.ts +1 -1
- package/dist/app-frame.cjs +2 -0
- package/dist/app-frame.cjs.map +1 -0
- package/dist/app-frame.d.ts +82 -0
- package/dist/app-frame.d.ts.map +1 -0
- package/dist/app-frame.mjs +189 -0
- package/dist/app-frame.mjs.map +1 -0
- package/dist/browser.cjs +1 -1
- package/dist/browser.mjs +2 -2
- package/dist/content.cjs +2 -0
- package/dist/content.cjs.map +1 -0
- package/dist/content.d.ts +148 -0
- package/dist/content.d.ts.map +1 -0
- package/dist/content.mjs +361 -0
- package/dist/content.mjs.map +1 -0
- package/dist/content_mime.d.ts +4 -0
- package/dist/content_mime.d.ts.map +1 -0
- package/dist/index.cjs +1 -1
- package/dist/index.mjs +2 -2
- package/dist/{ndm_proxy-1b07ecf3.mjs → ndm_proxy-3caceb0a.mjs} +6 -2
- package/dist/{ndm_proxy-1b07ecf3.mjs.map → ndm_proxy-3caceb0a.mjs.map} +1 -1
- package/dist/{ndm_proxy-7b71deb4.js → ndm_proxy-d37a0204.js} +2 -2
- package/dist/{ndm_proxy-7b71deb4.js.map → ndm_proxy-d37a0204.js.map} +1 -1
- package/dist/nfsp.cjs +2 -0
- package/dist/nfsp.cjs.map +1 -0
- package/dist/nfsp.d.ts +484 -0
- package/dist/nfsp.d.ts.map +1 -0
- package/dist/nfsp.mjs +466 -0
- package/dist/nfsp.mjs.map +1 -0
- package/dist/node.cjs +1 -1
- package/dist/node.mjs +2 -2
- package/dist/runtime.d.ts.map +1 -1
- package/package.json +18 -2
package/cli/dist/cli.mjs
CHANGED
|
@@ -4594,6 +4594,7 @@ function validateAppDocShape(appDoc) {
|
|
|
4594
4594
|
"sdk_version",
|
|
4595
4595
|
"req_capbilities",
|
|
4596
4596
|
"permissions",
|
|
4597
|
+
"content_handlers",
|
|
4597
4598
|
"selector_type",
|
|
4598
4599
|
"service_config_tips"
|
|
4599
4600
|
],
|
|
@@ -4660,6 +4661,9 @@ function validateAppDocShape(appDoc) {
|
|
|
4660
4661
|
throw invalid("appdoc", "APPDOC.permissions must be an array");
|
|
4661
4662
|
}
|
|
4662
4663
|
validatePermissions(appDoc.permissions ?? [], "APPDOC.permissions");
|
|
4664
|
+
if (appDoc.content_handlers !== void 0 && !Array.isArray(appDoc.content_handlers)) {
|
|
4665
|
+
throw invalid("appdoc", "APPDOC.content_handlers must be an array");
|
|
4666
|
+
}
|
|
4663
4667
|
validateServiceConfigTips(appDoc.service_config_tips, "APPDOC.service_config_tips");
|
|
4664
4668
|
const pkgList = expectObject$3(appDoc.pkg_list, "APPDOC.pkg_list");
|
|
4665
4669
|
if (Object.keys(pkgList).length === 0) {
|
|
@@ -4865,7 +4869,60 @@ function invalid(stage, message, entry) {
|
|
|
4865
4869
|
function stableJsonDigest(value) {
|
|
4866
4870
|
return sha256Bytes(new TextEncoder().encode(ndn.toCanonicalJsonString(value)));
|
|
4867
4871
|
}
|
|
4868
|
-
|
|
4872
|
+
function validateContentHandlers(value, permissions) {
|
|
4873
|
+
if (!Array.isArray(value))
|
|
4874
|
+
throw invalid("appdoc", "content_handlers must be an array");
|
|
4875
|
+
const ids = /* @__PURE__ */ new Set();
|
|
4876
|
+
for (const raw of value) {
|
|
4877
|
+
const h = expectObject$3(raw, "content handler");
|
|
4878
|
+
const id = expectNonEmptyString(h.handler_id, "handler_id");
|
|
4879
|
+
if (!/^[a-zA-Z0-9_-]+$/.test(id) || ids.has(id))
|
|
4880
|
+
throw invalid("appdoc", "invalid or duplicate handler_id");
|
|
4881
|
+
ids.add(id);
|
|
4882
|
+
if (!Number.isSafeInteger(h.version) || Number(h.version) < 1)
|
|
4883
|
+
throw invalid("appdoc", "invalid handler version");
|
|
4884
|
+
if (!Array.isArray(h.selectors) || !h.selectors.length)
|
|
4885
|
+
throw invalid("appdoc", "missing selectors");
|
|
4886
|
+
for (const rawSelector of h.selectors) {
|
|
4887
|
+
const s = expectObject$3(rawSelector, "selector");
|
|
4888
|
+
if (!["mime", "objType", "schema", "ext"].some((k) => k in s))
|
|
4889
|
+
throw invalid("appdoc", "empty selector");
|
|
4890
|
+
for (const key of ["mime", "objType", "schema"]) {
|
|
4891
|
+
const v = s[key];
|
|
4892
|
+
if (v !== void 0 && !(typeof v === "string" && v.length) && !(Array.isArray(v) && v.length && v.every((i) => typeof i === "string" && i.length)))
|
|
4893
|
+
throw invalid("appdoc", "invalid selector field");
|
|
4894
|
+
}
|
|
4895
|
+
if (s.maxSize !== void 0 && (!Number.isSafeInteger(s.maxSize) || Number(s.maxSize) < 0))
|
|
4896
|
+
throw invalid("appdoc", "invalid maxSize");
|
|
4897
|
+
}
|
|
4898
|
+
const intents = expectObject$3(h.intents, "intents");
|
|
4899
|
+
if (Object.keys(intents).length !== 1 || !intents.open)
|
|
4900
|
+
throw invalid("appdoc", "only open intent is supported");
|
|
4901
|
+
const open2 = expectObject$3(intents.open, "open");
|
|
4902
|
+
const entry = expectObject$3(open2.entry, "entry");
|
|
4903
|
+
const path = expectNonEmptyString(entry.path, "entry.path");
|
|
4904
|
+
let decoded;
|
|
4905
|
+
try {
|
|
4906
|
+
decoded = decodeURIComponent(path);
|
|
4907
|
+
} catch {
|
|
4908
|
+
throw invalid("appdoc", "invalid entry path");
|
|
4909
|
+
}
|
|
4910
|
+
if (entry.type !== "web" || !decoded.startsWith("/") || decoded.startsWith("//") || decoded.includes("..") || decoded.includes("\\") || decoded.includes("://") || decoded.includes("#") || /[\r\n]/.test(decoded))
|
|
4911
|
+
throw invalid("appdoc", "unsafe Web entry");
|
|
4912
|
+
if (open2.priority !== void 0 && (!Number.isSafeInteger(open2.priority) || Number(open2.priority) < 0 || Number(open2.priority) > 80))
|
|
4913
|
+
throw invalid("appdoc", "priority must be 0..80");
|
|
4914
|
+
if (open2.window !== void 0 && open2.window !== "new" && open2.window !== "reuse")
|
|
4915
|
+
throw invalid("appdoc", "invalid window policy");
|
|
4916
|
+
if (open2.multiSource !== void 0 && typeof open2.multiSource !== "boolean")
|
|
4917
|
+
throw invalid("appdoc", "invalid multiSource");
|
|
4918
|
+
if (open2.modes !== void 0 && (!Array.isArray(open2.modes) || !open2.modes.length || open2.modes.some((m) => m !== "view" && m !== "edit")))
|
|
4919
|
+
throw invalid("appdoc", "invalid modes");
|
|
4920
|
+
if (h.permissions !== void 0 && (!Array.isArray(h.permissions) || h.permissions.some((scope) => !permissions.some((p) => p && typeof p === "object" && p.scope_path === scope))))
|
|
4921
|
+
throw invalid("appdoc", "handler permissions exceed App permissions");
|
|
4922
|
+
}
|
|
4923
|
+
return value;
|
|
4924
|
+
}
|
|
4925
|
+
const PACKAGE_VERSION = "0.7.128";
|
|
4869
4926
|
const TOOL_VERSION = PACKAGE_VERSION;
|
|
4870
4927
|
const SDK_VERSION = PACKAGE_VERSION;
|
|
4871
4928
|
const PROTOCOL_VERSION = "1";
|
|
@@ -5428,6 +5485,7 @@ async function buildCommand(ctx, input, docker, now) {
|
|
|
5428
5485
|
pkg_list: pkgList,
|
|
5429
5486
|
show_name: appMeta.show_name,
|
|
5430
5487
|
...appMeta.permissions.length ? { permissions: appMeta.permissions } : {},
|
|
5488
|
+
...appMeta.content_handlers?.length ? { content_handlers: appMeta.content_handlers } : {},
|
|
5431
5489
|
selector_type: appMeta.selector_type,
|
|
5432
5490
|
service_config_tips: appMeta.service_config_tips
|
|
5433
5491
|
};
|
|
@@ -5591,6 +5649,7 @@ function parseAppMeta(value) {
|
|
|
5591
5649
|
"show_name",
|
|
5592
5650
|
"categories",
|
|
5593
5651
|
"permissions",
|
|
5652
|
+
"content_handlers",
|
|
5594
5653
|
"selector_type",
|
|
5595
5654
|
"service_config_tips"
|
|
5596
5655
|
],
|
|
@@ -5632,6 +5691,7 @@ function parseAppMeta(value) {
|
|
|
5632
5691
|
show_name: developmentString(value.show_name, "app.json.show_name"),
|
|
5633
5692
|
categories,
|
|
5634
5693
|
permissions,
|
|
5694
|
+
...value.content_handlers === void 0 ? {} : { content_handlers: developmentValidation(() => validateContentHandlers(value.content_handlers, permissions)) },
|
|
5635
5695
|
selector_type: developmentString(value.selector_type, "app.json.selector_type"),
|
|
5636
5696
|
service_config_tips: serviceConfig
|
|
5637
5697
|
};
|
|
@@ -9606,6 +9666,47 @@ async function runCli(host2, argv) {
|
|
|
9606
9666
|
installHost(host2);
|
|
9607
9667
|
return await new BuckyOSToolApplication().run(argv);
|
|
9608
9668
|
}
|
|
9669
|
+
async function assertPathAccess(policy2, path, realPath, candidate, operation, resolveLinks = true) {
|
|
9670
|
+
const roots = operation === "read" ? policy2.readPaths : policy2.writePaths;
|
|
9671
|
+
const absolute = path.resolve(candidate);
|
|
9672
|
+
const physicalRoots = [];
|
|
9673
|
+
for (const root of roots) {
|
|
9674
|
+
try {
|
|
9675
|
+
physicalRoots.push(await realPath(path.resolve(root)));
|
|
9676
|
+
} catch (error) {
|
|
9677
|
+
if (!isHostError(error, "NotFound") && !isHostError(error, "PermissionDenied"))
|
|
9678
|
+
throw error;
|
|
9679
|
+
}
|
|
9680
|
+
}
|
|
9681
|
+
if (!insideAny(absolute, roots, path) && !insideAny(absolute, physicalRoots, path)) {
|
|
9682
|
+
throw new HostError(
|
|
9683
|
+
"PermissionDenied",
|
|
9684
|
+
`${operation} access is outside ${policy2.name}: ${absolute}`,
|
|
9685
|
+
absolute
|
|
9686
|
+
);
|
|
9687
|
+
}
|
|
9688
|
+
if (!resolveLinks)
|
|
9689
|
+
return;
|
|
9690
|
+
try {
|
|
9691
|
+
const physical = await realPath(absolute);
|
|
9692
|
+
if (!insideAny(physical, physicalRoots, path)) {
|
|
9693
|
+
throw new HostError(
|
|
9694
|
+
"PermissionDenied",
|
|
9695
|
+
`${operation} access escapes ${policy2.name}: ${absolute}`,
|
|
9696
|
+
absolute
|
|
9697
|
+
);
|
|
9698
|
+
}
|
|
9699
|
+
} catch (error) {
|
|
9700
|
+
if (!isHostError(error, "NotFound"))
|
|
9701
|
+
throw error;
|
|
9702
|
+
}
|
|
9703
|
+
}
|
|
9704
|
+
function insideAny(candidate, roots, path) {
|
|
9705
|
+
return roots.some((root) => {
|
|
9706
|
+
const relative2 = path.relative(path.resolve(root), candidate);
|
|
9707
|
+
return relative2 === "" || relative2 !== ".." && !relative2.startsWith(`..${path.sep}`) && !path.isAbsolute(relative2);
|
|
9708
|
+
});
|
|
9709
|
+
}
|
|
9609
9710
|
class NodeHost {
|
|
9610
9711
|
constructor(policy2) {
|
|
9611
9712
|
this.kind = "node";
|
|
@@ -9916,30 +10017,20 @@ class NodeHost {
|
|
|
9916
10017
|
}
|
|
9917
10018
|
}
|
|
9918
10019
|
async assertPath(candidate, operation, resolveLinks = true) {
|
|
9919
|
-
|
|
9920
|
-
|
|
9921
|
-
|
|
9922
|
-
|
|
9923
|
-
|
|
9924
|
-
|
|
9925
|
-
|
|
9926
|
-
|
|
9927
|
-
|
|
9928
|
-
|
|
9929
|
-
|
|
9930
|
-
|
|
9931
|
-
|
|
9932
|
-
|
|
9933
|
-
throw new HostError(
|
|
9934
|
-
"PermissionDenied",
|
|
9935
|
-
`${operation} access escapes ${this.policy.name}: ${absolute}`,
|
|
9936
|
-
absolute
|
|
9937
|
-
);
|
|
9938
|
-
}
|
|
9939
|
-
} catch (error) {
|
|
9940
|
-
if (error.code !== "ENOENT")
|
|
9941
|
-
throw error;
|
|
9942
|
-
}
|
|
10020
|
+
await assertPathAccess(
|
|
10021
|
+
this.policy,
|
|
10022
|
+
nodePath,
|
|
10023
|
+
async (path) => {
|
|
10024
|
+
try {
|
|
10025
|
+
return await realpath(path);
|
|
10026
|
+
} catch (error) {
|
|
10027
|
+
throw translateNodeError(error, path);
|
|
10028
|
+
}
|
|
10029
|
+
},
|
|
10030
|
+
candidate,
|
|
10031
|
+
operation,
|
|
10032
|
+
resolveLinks
|
|
10033
|
+
);
|
|
9943
10034
|
}
|
|
9944
10035
|
}
|
|
9945
10036
|
async function* fixedChunks(source) {
|
|
@@ -10007,12 +10098,6 @@ function fileInfo(value) {
|
|
|
10007
10098
|
ino: value.ino ?? null
|
|
10008
10099
|
};
|
|
10009
10100
|
}
|
|
10010
|
-
function insideAny(candidate, roots) {
|
|
10011
|
-
return roots.some((root) => {
|
|
10012
|
-
const relative2 = nodePath.relative(nodePath.resolve(root), candidate);
|
|
10013
|
-
return relative2 === "" || relative2 !== ".." && !relative2.startsWith(`..${nodePath.sep}`) && !nodePath.isAbsolute(relative2);
|
|
10014
|
-
});
|
|
10015
|
-
}
|
|
10016
10101
|
async function capture(command, args) {
|
|
10017
10102
|
return await new Promise((resolve2, reject) => {
|
|
10018
10103
|
const child = spawn(command, args, { stdio: ["ignore", "pipe", "pipe"], shell: false });
|