@tinycloud/cli 1.1.0-beta.11 → 1.1.0-beta.12
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 +43 -10
- package/dist/legacy-entry.js.map +1 -1
- package/package.json +1 -1
- package/skills/tc-cli/AUTH.md +1 -0
- package/skills/tc-cli/REFERENCE.md +1 -1
package/dist/legacy-entry.js
CHANGED
|
@@ -15117,6 +15117,34 @@ async function commitLogin(profileName, snapshot, commit) {
|
|
|
15117
15117
|
});
|
|
15118
15118
|
}
|
|
15119
15119
|
|
|
15120
|
+
// src/auth/owner-key.ts
|
|
15121
|
+
init_theme();
|
|
15122
|
+
function openKeyPrimaryFlag(delegation) {
|
|
15123
|
+
return typeof delegation.primary === "boolean" ? delegation.primary : void 0;
|
|
15124
|
+
}
|
|
15125
|
+
function withOwnerKeyPrimary(profile, primary) {
|
|
15126
|
+
const { ownerKeyPrimary: _previous, ...rest } = profile;
|
|
15127
|
+
return primary === void 0 ? rest : { ...rest, ownerKeyPrimary: primary };
|
|
15128
|
+
}
|
|
15129
|
+
function nonPrimaryKeyWarning(ownerDid) {
|
|
15130
|
+
const address = ownerDid.split(":")[4] ?? ownerDid;
|
|
15131
|
+
return `${theme.warn("Warning:")} you signed in with OpenKey key ${address} (${ownerDid}), which is not your account's primary OpenKey key. This key is a separate owner with its own spaces and data, so this profile does not see the data stored under your primary key.
|
|
15132
|
+
To use your primary key, log in again and choose the primary key in OpenKey, for example into a new profile: tc init --name <profile>
|
|
15133
|
+
`;
|
|
15134
|
+
}
|
|
15135
|
+
function warnIfNotPrimaryKey(ownerDid, primary) {
|
|
15136
|
+
if (primary !== false || ownerDid === void 0) return;
|
|
15137
|
+
process.stderr.write(nonPrimaryKeyWarning(ownerDid));
|
|
15138
|
+
}
|
|
15139
|
+
function ownerLoginPermissions(owner) {
|
|
15140
|
+
const space = ownerSpaceId("default", owner);
|
|
15141
|
+
return [
|
|
15142
|
+
{ service: "tinycloud.kv", space, path: "", actions: ["tinycloud.kv/put", "tinycloud.kv/get", "tinycloud.kv/del", "tinycloud.kv/list", "tinycloud.kv/metadata"] },
|
|
15143
|
+
{ service: "tinycloud.sql", space, path: "", actions: ["tinycloud.sql/read", "tinycloud.sql/write", "tinycloud.sql/admin"] },
|
|
15144
|
+
{ service: "tinycloud.capabilities", space, path: "", actions: ["tinycloud.capabilities/read"] }
|
|
15145
|
+
];
|
|
15146
|
+
}
|
|
15147
|
+
|
|
15120
15148
|
// src/auth/device-auth.ts
|
|
15121
15149
|
var DEVICE_DELEGATION_MAX_SECONDS = 30 * 24 * 60 * 60;
|
|
15122
15150
|
var DEVICE_APPROVAL_WINDOW_MAX_SECONDS = 60 * 60;
|
|
@@ -15321,7 +15349,8 @@ async function verifyApproval(input) {
|
|
|
15321
15349
|
spaceId: delegation.spaceId,
|
|
15322
15350
|
expiresAt: session.expiresAt,
|
|
15323
15351
|
approved: permissionsFromTuples(signed),
|
|
15324
|
-
declined: declinedPermissions(input.requested, session.permissions, ownerDid)
|
|
15352
|
+
declined: declinedPermissions(input.requested, session.permissions, ownerDid),
|
|
15353
|
+
...openKeyPrimaryFlag(delegation) === void 0 ? {} : { primary: openKeyPrimaryFlag(delegation) }
|
|
15325
15354
|
};
|
|
15326
15355
|
}
|
|
15327
15356
|
function writeApprovalPrompt(prompt) {
|
|
@@ -15498,7 +15527,7 @@ async function loginWithDeviceAuthorization(input) {
|
|
|
15498
15527
|
openkeyHost: input.openkeyHost ?? resolveDeviceApiHost(existing),
|
|
15499
15528
|
expectedOwner
|
|
15500
15529
|
});
|
|
15501
|
-
const profile = {
|
|
15530
|
+
const profile = withOwnerKeyPrimary({
|
|
15502
15531
|
...existing,
|
|
15503
15532
|
name: input.profileName,
|
|
15504
15533
|
host: input.persistHost === true || !existing?.host ? input.nodeOrigin : existing.host,
|
|
@@ -15512,7 +15541,7 @@ async function loginWithDeviceAuthorization(input) {
|
|
|
15512
15541
|
posture: "owner-openkey",
|
|
15513
15542
|
operatorType: existing?.operatorType ?? "human",
|
|
15514
15543
|
authMethod: "openkey"
|
|
15515
|
-
};
|
|
15544
|
+
}, result.primary);
|
|
15516
15545
|
await commitLogin(input.profileName, snapshot, {
|
|
15517
15546
|
key,
|
|
15518
15547
|
session: result.session,
|
|
@@ -15520,6 +15549,7 @@ async function loginWithDeviceAuthorization(input) {
|
|
|
15520
15549
|
// The signed permissions, with their caveats; `approved` is the action summary.
|
|
15521
15550
|
approved: { scope: result.session.permissions, ownerDid: result.ownerDid, replaceSession: input.replaceSession === true }
|
|
15522
15551
|
});
|
|
15552
|
+
warnIfNotPrimaryKey(result.ownerDid, result.primary);
|
|
15523
15553
|
return { profile, result };
|
|
15524
15554
|
}
|
|
15525
15555
|
|
|
@@ -15557,7 +15587,7 @@ async function promptAuthMethod() {
|
|
|
15557
15587
|
}
|
|
15558
15588
|
function registerAuthCommand(program) {
|
|
15559
15589
|
const auth = program.command("auth").description("Authentication management");
|
|
15560
|
-
auth.command("login").description("Authenticate with TinyCloud").option("--device", "Approve on another device (e.g. a phone) through OpenKey device authorization; requires a KV-scoped --manifest (SQL and secret decrypt need browser or --paste login)").option("--paste", "Use manual paste mode instead of browser callback").option("--no-popup", "Print the OpenKey URL without opening a browser").option("--method <method>", "Authentication method: local or openkey").option("--manifest <fileOrBase64>", `Request only this manifest's permissions (one space, plus raw encryption network entries such as a secrets decrypt grant); ${SHARE_PUBLISHING_MANIFEST_REF} covers \`tc share publish\``).option("--expiry <duration>", "OpenKey session lifetime, e.g. 1h or 7d (device login: at most 30d, default 30d)").option("--owner <did>", "
|
|
15590
|
+
auth.command("login").description("Authenticate with TinyCloud").option("--device", "Approve on another device (e.g. a phone) through OpenKey device authorization; requires a KV-scoped --manifest (SQL and secret decrypt need browser or --paste login)").option("--paste", "Use manual paste mode instead of browser callback").option("--no-popup", "Print the OpenKey URL without opening a browser").option("--method <method>", "Authentication method: local or openkey").option("--manifest <fileOrBase64>", `Request only this manifest's permissions (one space, plus raw encryption network entries such as a secrets decrypt grant); ${SHARE_PUBLISHING_MANIFEST_REF} covers \`tc share publish\``).option("--expiry <duration>", "OpenKey session lifetime, e.g. 1h or 7d (device login: at most 30d, default 30d)").option("--owner <did>", "Sign in as this owner (did:pkh:eip155:CHAIN:ADDRESS): OpenKey preselects that key, e.g. one that is not the account's primary key, and an approval by any other identity is refused. With --manifest, also names the secrets owner for a manifest's `secrets` on a profile with no recorded owner").option("--replace-session", "Scoped or device login: replace this profile's live session even though the new scope would narrow, change or shorten it (prefer a new profile)").action(async (options, cmd) => {
|
|
15561
15591
|
try {
|
|
15562
15592
|
if (options.device && options.paste) {
|
|
15563
15593
|
throw new CLIError("INVALID_ARGUMENT", "--device and --paste are mutually exclusive.", ExitCode.USAGE_ERROR);
|
|
@@ -15566,9 +15596,6 @@ function registerAuthCommand(program) {
|
|
|
15566
15596
|
if (scoped && options.method === "local") {
|
|
15567
15597
|
throw new CLIError("INVALID_ARGUMENT", "--device, --manifest, --expiry and --owner require OpenKey login.", ExitCode.USAGE_ERROR);
|
|
15568
15598
|
}
|
|
15569
|
-
if (options.owner && !options.manifest) {
|
|
15570
|
-
throw new CLIError("INVALID_ARGUMENT", "--owner requires --manifest so the signed identity is verified.", ExitCode.USAGE_ERROR);
|
|
15571
|
-
}
|
|
15572
15599
|
if (options.device && !options.manifest) {
|
|
15573
15600
|
throw new CLIError(
|
|
15574
15601
|
"MANIFEST_REQUIRED",
|
|
@@ -15691,6 +15718,7 @@ function registerAuthCommand(program) {
|
|
|
15691
15718
|
did: profile?.did ?? null,
|
|
15692
15719
|
sessionDid: profile?.sessionDid ?? null,
|
|
15693
15720
|
ownerDid: profile?.ownerDid ?? null,
|
|
15721
|
+
ownerKeyPrimary: profile?.ownerKeyPrimary ?? null,
|
|
15694
15722
|
spaceId: profile?.spaceId ?? null,
|
|
15695
15723
|
host: ctx.host,
|
|
15696
15724
|
profile: ctx.profile,
|
|
@@ -15711,6 +15739,7 @@ function registerAuthCommand(program) {
|
|
|
15711
15739
|
process.stdout.write(formatField("DID", profile?.did ?? null) + "\n");
|
|
15712
15740
|
process.stdout.write(formatField("Session DID", profile?.sessionDid ?? null) + "\n");
|
|
15713
15741
|
process.stdout.write(formatField("Owner DID", profile?.ownerDid ?? null) + "\n");
|
|
15742
|
+
process.stdout.write(formatField("Primary Key", profile?.ownerKeyPrimary ?? "unknown") + "\n");
|
|
15714
15743
|
process.stdout.write(formatField("Address", profile?.address ?? null) + "\n");
|
|
15715
15744
|
process.stdout.write(formatField("Space ID", profile?.spaceId ?? null) + "\n");
|
|
15716
15745
|
process.stdout.write(formatField("Has Key", hasKey !== null) + "\n");
|
|
@@ -16783,7 +16812,9 @@ async function refreshOpenKeySession(profileName, host, options = {}) {
|
|
|
16783
16812
|
jwk: key,
|
|
16784
16813
|
host,
|
|
16785
16814
|
openkeyHost: resolveOpenKeyHost(profile),
|
|
16786
|
-
|
|
16815
|
+
// A plain login with --owner names that owner's space, so OpenKey
|
|
16816
|
+
// preselects its key; the signed owner is verified below.
|
|
16817
|
+
permissions: permissions ?? (options.expectedOwner === void 0 ? void 0 : ownerLoginPermissions(expectedOwner)),
|
|
16787
16818
|
expiry: openKeyExpiry,
|
|
16788
16819
|
...permissions ? { reason: "Allow this TinyCloud CLI profile to use the permissions in the requested manifest." } : {}
|
|
16789
16820
|
});
|
|
@@ -16809,7 +16840,8 @@ async function refreshOpenKeySession(profileName, host, options = {}) {
|
|
|
16809
16840
|
sanitizedSession = Object.fromEntries(Object.entries(withoutTrustFields(merged)).filter(([name]) => name !== "siwe" && name !== "signature"));
|
|
16810
16841
|
}
|
|
16811
16842
|
}
|
|
16812
|
-
const
|
|
16843
|
+
const ownerKeyPrimary = verifiedOwner === void 0 ? void 0 : openKeyPrimaryFlag(delegationData);
|
|
16844
|
+
const updatedProfile = withOwnerKeyPrimary({
|
|
16813
16845
|
...profile,
|
|
16814
16846
|
host: options.persistHost === true || !profile.host ? host : profile.host,
|
|
16815
16847
|
sessionDid: profile.sessionDid ?? profile.did,
|
|
@@ -16818,13 +16850,14 @@ async function refreshOpenKeySession(profileName, host, options = {}) {
|
|
|
16818
16850
|
authMethod: "openkey",
|
|
16819
16851
|
...typeof sanitizedSession.spaceId === "string" ? { spaceId: sanitizedSession.spaceId } : {},
|
|
16820
16852
|
...verifiedOwner === void 0 ? {} : { ownerDid: verifiedOwner }
|
|
16821
|
-
};
|
|
16853
|
+
}, ownerKeyPrimary);
|
|
16822
16854
|
await commitLogin(profileName, snapshot, {
|
|
16823
16855
|
key,
|
|
16824
16856
|
session: sanitizedSession,
|
|
16825
16857
|
profile: updatedProfile,
|
|
16826
16858
|
...permissions && verifiedOwner ? { approved: { scope: sanitizedSession.permissions, ownerDid: verifiedOwner, replaceSession: options.replaceSession === true } } : {}
|
|
16827
16859
|
});
|
|
16860
|
+
warnIfNotPrimaryKey(verifiedOwner, ownerKeyPrimary);
|
|
16828
16861
|
return { profile: updatedProfile, delegationData: sanitizedSession, declined, legacyNested };
|
|
16829
16862
|
}
|
|
16830
16863
|
|