@tinycloud/cli 0.9.0-beta.8 → 0.9.0-beta.9
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/dist/index.js.map +1 -1
- package/dist/legacy-entry.js +124 -20
- package/dist/legacy-entry.js.map +1 -1
- package/package.json +3 -3
package/dist/legacy-entry.js
CHANGED
|
@@ -29979,9 +29979,52 @@ function buildAuthUrl(did, options = {}) {
|
|
|
29979
29979
|
if (options.expiry !== void 0) {
|
|
29980
29980
|
params.set("expiry", String(options.expiry));
|
|
29981
29981
|
}
|
|
29982
|
+
params.set("protocolVersion", "1");
|
|
29982
29983
|
const base4 = options.openkeyHost ?? DEFAULT_OPENKEY_HOST;
|
|
29983
29984
|
return `${base4}/delegate?${params.toString()}`;
|
|
29984
29985
|
}
|
|
29986
|
+
function validateDelegationCallbackPayload(value) {
|
|
29987
|
+
if (!value || typeof value !== "object") return "expected an object";
|
|
29988
|
+
const v = value;
|
|
29989
|
+
if (!v.delegationHeader || typeof v.delegationHeader !== "object") {
|
|
29990
|
+
return "delegationHeader must be an object";
|
|
29991
|
+
}
|
|
29992
|
+
const auth = v.delegationHeader.Authorization;
|
|
29993
|
+
if (typeof auth !== "string" || !auth) {
|
|
29994
|
+
return "delegationHeader.Authorization must be a non-empty string";
|
|
29995
|
+
}
|
|
29996
|
+
if (typeof v.delegationCid !== "string" || !v.delegationCid) {
|
|
29997
|
+
return "delegationCid must be a non-empty string";
|
|
29998
|
+
}
|
|
29999
|
+
if (typeof v.spaceId !== "string" || !v.spaceId) {
|
|
30000
|
+
return "spaceId must be a non-empty string";
|
|
30001
|
+
}
|
|
30002
|
+
if (v.permissions !== void 0) {
|
|
30003
|
+
if (!Array.isArray(v.permissions)) {
|
|
30004
|
+
return "permissions, when present, must be an array";
|
|
30005
|
+
}
|
|
30006
|
+
for (let i = 0; i < v.permissions.length; i++) {
|
|
30007
|
+
const entry = v.permissions[i];
|
|
30008
|
+
if (!entry || typeof entry !== "object") {
|
|
30009
|
+
return `permissions[${i}] must be an object`;
|
|
30010
|
+
}
|
|
30011
|
+
const e = entry;
|
|
30012
|
+
if (typeof e.service !== "string" || !e.service) {
|
|
30013
|
+
return `permissions[${i}].service must be a non-empty string`;
|
|
30014
|
+
}
|
|
30015
|
+
if (typeof e.space !== "string") {
|
|
30016
|
+
return `permissions[${i}].space must be a string`;
|
|
30017
|
+
}
|
|
30018
|
+
if (typeof e.path !== "string") {
|
|
30019
|
+
return `permissions[${i}].path must be a string`;
|
|
30020
|
+
}
|
|
30021
|
+
if (!Array.isArray(e.actions) || e.actions.some((a) => typeof a !== "string" || !a)) {
|
|
30022
|
+
return `permissions[${i}].actions must be a non-empty string[]`;
|
|
30023
|
+
}
|
|
30024
|
+
}
|
|
30025
|
+
}
|
|
30026
|
+
return null;
|
|
30027
|
+
}
|
|
29985
30028
|
function shouldOpenBrowser(options) {
|
|
29986
30029
|
if (options.noPopup) return false;
|
|
29987
30030
|
const env = process.env.TC_AUTH_NO_POPUP ?? process.env.TC_NO_POPUP;
|
|
@@ -30008,12 +30051,18 @@ async function callbackFlow(did, options = {}) {
|
|
|
30008
30051
|
}
|
|
30009
30052
|
function parsePasteInput(input) {
|
|
30010
30053
|
const trimmed = input.trim();
|
|
30054
|
+
let parsed;
|
|
30011
30055
|
try {
|
|
30012
|
-
|
|
30056
|
+
parsed = JSON.parse(trimmed);
|
|
30013
30057
|
} catch {
|
|
30014
30058
|
const decoded = Buffer.from(trimmed, "base64").toString("utf-8");
|
|
30015
|
-
|
|
30059
|
+
parsed = JSON.parse(decoded);
|
|
30060
|
+
}
|
|
30061
|
+
const invalid = validateDelegationCallbackPayload(parsed);
|
|
30062
|
+
if (invalid) {
|
|
30063
|
+
throw new Error(`Invalid delegation code: ${invalid}`);
|
|
30016
30064
|
}
|
|
30065
|
+
return parsed;
|
|
30017
30066
|
}
|
|
30018
30067
|
const server = createServer((req, res) => {
|
|
30019
30068
|
if (req.method === "POST" && req.url === "/callback") {
|
|
@@ -30024,6 +30073,13 @@ async function callbackFlow(did, options = {}) {
|
|
|
30024
30073
|
req.on("end", () => {
|
|
30025
30074
|
try {
|
|
30026
30075
|
const data = JSON.parse(body);
|
|
30076
|
+
const invalid = validateDelegationCallbackPayload(data);
|
|
30077
|
+
if (invalid) {
|
|
30078
|
+
res.writeHead(400, { "Content-Type": "application/json" });
|
|
30079
|
+
res.end(JSON.stringify({ error: invalid }));
|
|
30080
|
+
settle({ error: new Error(`Invalid delegation payload: ${invalid}`) });
|
|
30081
|
+
return;
|
|
30082
|
+
}
|
|
30027
30083
|
res.writeHead(200, {
|
|
30028
30084
|
"Content-Type": "application/json",
|
|
30029
30085
|
"Access-Control-Allow-Origin": "*"
|
|
@@ -30110,18 +30166,24 @@ Open this URL in a browser to authenticate:
|
|
|
30110
30166
|
return new Promise((resolve4, reject) => {
|
|
30111
30167
|
rl.question("Paste delegation code: ", (input) => {
|
|
30112
30168
|
rl.close();
|
|
30169
|
+
let parsed;
|
|
30113
30170
|
try {
|
|
30114
|
-
|
|
30115
|
-
resolve4(data);
|
|
30171
|
+
parsed = JSON.parse(input.trim());
|
|
30116
30172
|
} catch {
|
|
30117
30173
|
try {
|
|
30118
30174
|
const decoded = Buffer.from(input.trim(), "base64").toString("utf-8");
|
|
30119
|
-
|
|
30120
|
-
resolve4(data);
|
|
30175
|
+
parsed = JSON.parse(decoded);
|
|
30121
30176
|
} catch {
|
|
30122
30177
|
reject(new Error("Invalid delegation code. Expected JSON or base64-encoded JSON."));
|
|
30178
|
+
return;
|
|
30123
30179
|
}
|
|
30124
30180
|
}
|
|
30181
|
+
const invalid = validateDelegationCallbackPayload(parsed);
|
|
30182
|
+
if (invalid) {
|
|
30183
|
+
reject(new Error(`Invalid delegation code: ${invalid}`));
|
|
30184
|
+
return;
|
|
30185
|
+
}
|
|
30186
|
+
resolve4(parsed);
|
|
30125
30187
|
});
|
|
30126
30188
|
});
|
|
30127
30189
|
}
|
|
@@ -30376,6 +30438,7 @@ function registerAuthCommand(program) {
|
|
|
30376
30438
|
const delegationCids2 = [];
|
|
30377
30439
|
let expiry2;
|
|
30378
30440
|
const openkeyHost = resolveOpenKeyHost(profile);
|
|
30441
|
+
const openkeyEffective = [];
|
|
30379
30442
|
for (const group of groupPermissionsBySpace(requested)) {
|
|
30380
30443
|
const delegationData = await startAuthFlow(profile.did, {
|
|
30381
30444
|
jwk: key,
|
|
@@ -30390,13 +30453,15 @@ function registerAuthCommand(program) {
|
|
|
30390
30453
|
noPopup: options.popup === false
|
|
30391
30454
|
});
|
|
30392
30455
|
const delegation = portableFromOpenKeyDelegation(delegationData, group, ctx.host);
|
|
30393
|
-
const
|
|
30456
|
+
const effective = permissionsFromDelegation(delegation);
|
|
30457
|
+
openkeyEffective.push(...effective);
|
|
30458
|
+
const stored = storedAdditionalDelegation(delegation, effective);
|
|
30394
30459
|
await appendAdditionalDelegation(ctx.profile, stored);
|
|
30395
30460
|
await node.useRuntimeDelegation(delegation);
|
|
30396
30461
|
delegationCids2.push(delegation.cid);
|
|
30397
30462
|
expiry2 = delegation.expiry.toISOString();
|
|
30398
30463
|
await appendGrantHistory(ctx.profile, {
|
|
30399
|
-
addedCaps:
|
|
30464
|
+
addedCaps: effective,
|
|
30400
30465
|
source: options.manifest ? "manifest" : "cli",
|
|
30401
30466
|
delegationCid: delegation.cid,
|
|
30402
30467
|
expiry: expiry2
|
|
@@ -30404,7 +30469,7 @@ function registerAuthCommand(program) {
|
|
|
30404
30469
|
}
|
|
30405
30470
|
outputJson({
|
|
30406
30471
|
changed: delegationCids2.length > 0,
|
|
30407
|
-
added:
|
|
30472
|
+
added: openkeyEffective,
|
|
30408
30473
|
delegationCid: delegationCids2[0],
|
|
30409
30474
|
delegationCids: delegationCids2,
|
|
30410
30475
|
expiry: expiry2
|
|
@@ -30429,8 +30494,10 @@ function registerAuthCommand(program) {
|
|
|
30429
30494
|
await persistCurrentLocalSession(ctx.profile, profile, node.restorableSession);
|
|
30430
30495
|
const delegationCids = [];
|
|
30431
30496
|
let expiry;
|
|
30497
|
+
const localEffective = [];
|
|
30432
30498
|
for (const delegation of delegations) {
|
|
30433
30499
|
const covering = permissionsFromDelegation(delegation);
|
|
30500
|
+
localEffective.push(...covering);
|
|
30434
30501
|
const stored = storedAdditionalDelegation(delegation, covering);
|
|
30435
30502
|
await appendAdditionalDelegation(ctx.profile, stored);
|
|
30436
30503
|
delegationCids.push(delegation.cid);
|
|
@@ -30448,7 +30515,7 @@ function registerAuthCommand(program) {
|
|
|
30448
30515
|
}
|
|
30449
30516
|
outputJson({
|
|
30450
30517
|
changed: true,
|
|
30451
|
-
added:
|
|
30518
|
+
added: localEffective,
|
|
30452
30519
|
delegationCid: delegationCids[0],
|
|
30453
30520
|
delegationCids,
|
|
30454
30521
|
expiry
|
|
@@ -30907,13 +30974,14 @@ async function ensureDelegationAuthority(params) {
|
|
|
30907
30974
|
expiry: params.expiryOption
|
|
30908
30975
|
});
|
|
30909
30976
|
const delegation = portableFromOpenKeyDelegation(delegationData, group, params.ctx.host);
|
|
30977
|
+
const effective = permissionsFromDelegation(delegation);
|
|
30910
30978
|
await appendAdditionalDelegation(
|
|
30911
30979
|
params.ctx.profile,
|
|
30912
|
-
storedAdditionalDelegation(delegation,
|
|
30980
|
+
storedAdditionalDelegation(delegation, effective)
|
|
30913
30981
|
);
|
|
30914
30982
|
await params.node.useRuntimeDelegation(delegation);
|
|
30915
30983
|
await appendGrantHistory(params.ctx.profile, {
|
|
30916
|
-
addedCaps:
|
|
30984
|
+
addedCaps: effective,
|
|
30917
30985
|
source: "cli",
|
|
30918
30986
|
delegationCid: delegation.cid,
|
|
30919
30987
|
expiry: delegation.expiry.toISOString()
|
|
@@ -31045,7 +31113,7 @@ function groupPermissionsBySpace(permissions) {
|
|
|
31045
31113
|
rawEntries.push(permission);
|
|
31046
31114
|
continue;
|
|
31047
31115
|
}
|
|
31048
|
-
const key = normalizeSpaceForCompare(permission.space);
|
|
31116
|
+
const key = normalizeSpaceForCompare(permission.space ?? "");
|
|
31049
31117
|
const group = groups.get(key) ?? [];
|
|
31050
31118
|
group.push(permission);
|
|
31051
31119
|
groups.set(key, group);
|
|
@@ -31078,7 +31146,7 @@ function portableFromOpenKeyDelegation(data, permissions, host) {
|
|
|
31078
31146
|
const primary = permissions.find((permission) => !isRawPermission(permission)) ?? permissions[0];
|
|
31079
31147
|
const returnedSpace = String(data.spaceId ?? primary.space ?? "encryption");
|
|
31080
31148
|
const expectedSpaces = new Set(
|
|
31081
|
-
permissions.filter((permission) => !isRawPermission(permission)).map((permission) => normalizeSpaceForCompare(permission.space))
|
|
31149
|
+
permissions.filter((permission) => !isRawPermission(permission)).map((permission) => normalizeSpaceForCompare(permission.space ?? ""))
|
|
31082
31150
|
);
|
|
31083
31151
|
const matchesExpectedSpace = expectedSpaces.size === 1 && returnedSpaceMatchesExpected(returnedSpace, Array.from(expectedSpaces)[0]);
|
|
31084
31152
|
if (expectedSpaces.size > 0 && !matchesExpectedSpace) {
|
|
@@ -31089,18 +31157,54 @@ function portableFromOpenKeyDelegation(data, permissions, host) {
|
|
|
31089
31157
|
);
|
|
31090
31158
|
}
|
|
31091
31159
|
const expiry = inferDelegationExpiry(data);
|
|
31160
|
+
const requestedPairs = new Set(
|
|
31161
|
+
permissions.flatMap(
|
|
31162
|
+
(p) => isRawPermission(p) ? p.actions.map((a) => `${p.service}|${p.space ?? ""}|${p.path}|${a}`) : p.actions.map((a) => `${p.service}|${normalizeSpaceForCompare(p.space ?? "")}|${p.path}|${a}`)
|
|
31163
|
+
)
|
|
31164
|
+
);
|
|
31165
|
+
const returnedPermissions = Array.isArray(data.permissions) ? data.permissions : null;
|
|
31166
|
+
const resources = (returnedPermissions ?? permissions).map((permission) => {
|
|
31167
|
+
const service = permission.service.startsWith("tinycloud.") ? permission.service.slice("tinycloud.".length) : permission.service;
|
|
31168
|
+
const rawService = permission.service.startsWith("tinycloud.") ? permission.service : `tinycloud.${service}`;
|
|
31169
|
+
const permSpace = permission.space ?? "";
|
|
31170
|
+
if (returnedPermissions) {
|
|
31171
|
+
const rawSpace = isRawPermission({
|
|
31172
|
+
service: rawService,
|
|
31173
|
+
space: permSpace,
|
|
31174
|
+
path: permission.path,
|
|
31175
|
+
actions: []
|
|
31176
|
+
}) ? permSpace : normalizeSpaceForCompare(permSpace);
|
|
31177
|
+
for (const action of permission.actions) {
|
|
31178
|
+
const key = `${rawService}|${rawSpace}|${permission.path}|${action}`;
|
|
31179
|
+
if (!requestedPairs.has(key)) {
|
|
31180
|
+
throw new CLIError(
|
|
31181
|
+
"OPENKEY_GRANT_BROADENED",
|
|
31182
|
+
`OpenKey returned grant ${rawService}/${action} on ${permSpace}/${permission.path} that was not requested.`,
|
|
31183
|
+
ExitCode.PERMISSION_DENIED
|
|
31184
|
+
);
|
|
31185
|
+
}
|
|
31186
|
+
}
|
|
31187
|
+
}
|
|
31188
|
+
const resolvedSpace = isRawPermission({
|
|
31189
|
+
service: rawService,
|
|
31190
|
+
space: permSpace,
|
|
31191
|
+
path: permission.path,
|
|
31192
|
+
actions: []
|
|
31193
|
+
}) ? permSpace : returnedSpace;
|
|
31194
|
+
return {
|
|
31195
|
+
service,
|
|
31196
|
+
space: resolvedSpace,
|
|
31197
|
+
path: permission.path,
|
|
31198
|
+
actions: [...permission.actions]
|
|
31199
|
+
};
|
|
31200
|
+
});
|
|
31092
31201
|
return {
|
|
31093
31202
|
cid: String(data.delegationCid),
|
|
31094
31203
|
delegationHeader: data.delegationHeader,
|
|
31095
31204
|
spaceId: returnedSpace,
|
|
31096
31205
|
path: primary.path,
|
|
31097
31206
|
actions: primary.actions,
|
|
31098
|
-
resources
|
|
31099
|
-
service: permission.service.startsWith("tinycloud.") ? permission.service.slice("tinycloud.".length) : permission.service,
|
|
31100
|
-
space: isRawPermission(permission) ? permission.space : returnedSpace,
|
|
31101
|
-
path: permission.path,
|
|
31102
|
-
actions: [...permission.actions]
|
|
31103
|
-
})),
|
|
31207
|
+
resources,
|
|
31104
31208
|
expiry,
|
|
31105
31209
|
delegateDID: String(data.verificationMethod),
|
|
31106
31210
|
ownerAddress: String(data.address ?? ""),
|