@tinycloud/cli 0.6.0-beta.8 → 0.6.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 +101 -21
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1402,6 +1402,15 @@ function registerAuthCommand(program2) {
|
|
|
1402
1402
|
handleError(error);
|
|
1403
1403
|
}
|
|
1404
1404
|
});
|
|
1405
|
+
auth.command("rotate").description("Rotate the active profile session key").option("--paste", "Use manual paste mode instead of browser callback").action(async (options, cmd) => {
|
|
1406
|
+
try {
|
|
1407
|
+
const globalOpts = cmd.optsWithGlobals();
|
|
1408
|
+
const ctx = await ProfileManager.resolveContext(globalOpts);
|
|
1409
|
+
await rotateAuthKey(ctx.profile, ctx.host, { paste: options.paste });
|
|
1410
|
+
} catch (error) {
|
|
1411
|
+
handleError(error);
|
|
1412
|
+
}
|
|
1413
|
+
});
|
|
1405
1414
|
auth.command("status").description("Show current authentication state").action(async (_options, cmd) => {
|
|
1406
1415
|
try {
|
|
1407
1416
|
const globalOpts = cmd.optsWithGlobals();
|
|
@@ -2127,16 +2136,74 @@ function inferDelegationExpiry(data) {
|
|
|
2127
2136
|
}
|
|
2128
2137
|
return new Date(Date.now() + 60 * 60 * 1e3);
|
|
2129
2138
|
}
|
|
2130
|
-
async function
|
|
2139
|
+
async function rotateAuthKey(profileName, host, options = {}) {
|
|
2140
|
+
const profile = await ProfileManager.getProfile(profileName);
|
|
2141
|
+
const posture = resolveProfilePosture(profile);
|
|
2142
|
+
const oldDid = profile.sessionDid ?? profile.did;
|
|
2143
|
+
if (posture === "delegate-session") {
|
|
2144
|
+
throw new CLIError(
|
|
2145
|
+
"ROTATE_DELEGATE_SESSION_UNSUPPORTED",
|
|
2146
|
+
`Profile "${profileName}" is a delegated session. Request or import a new owner delegation instead of rotating it locally.`,
|
|
2147
|
+
ExitCode.PERMISSION_DENIED
|
|
2148
|
+
);
|
|
2149
|
+
}
|
|
2150
|
+
if (profile.authMethod === "local" || posture === "local-owner-key") {
|
|
2151
|
+
if (!profile.privateKey) {
|
|
2152
|
+
throw new CLIError(
|
|
2153
|
+
"LOCAL_OWNER_KEY_REQUIRED",
|
|
2154
|
+
`Profile "${profileName}" does not have a local owner private key. Run \`tc auth login --method local\` first.`,
|
|
2155
|
+
ExitCode.AUTH_REQUIRED
|
|
2156
|
+
);
|
|
2157
|
+
}
|
|
2158
|
+
await ProfileManager.clearSession(profileName);
|
|
2159
|
+
const result2 = await handleLocalAuth(profileName, host, {
|
|
2160
|
+
emitOutput: false,
|
|
2161
|
+
forceSessionKey: true
|
|
2162
|
+
});
|
|
2163
|
+
outputRotationResult(result2.profile, profileName, oldDid, "local");
|
|
2164
|
+
return;
|
|
2165
|
+
}
|
|
2166
|
+
const { jwk, did } = await withSpinner("Generating session key...", async () => {
|
|
2167
|
+
return generateKey();
|
|
2168
|
+
});
|
|
2169
|
+
await ProfileManager.setKey(profileName, jwk);
|
|
2170
|
+
await ProfileManager.clearSession(profileName);
|
|
2171
|
+
await ProfileManager.setProfile(profileName, {
|
|
2172
|
+
...profile,
|
|
2173
|
+
host,
|
|
2174
|
+
did,
|
|
2175
|
+
sessionDid: did,
|
|
2176
|
+
posture: profile.posture ?? "owner-openkey",
|
|
2177
|
+
operatorType: profile.operatorType ?? "human",
|
|
2178
|
+
authMethod: "openkey"
|
|
2179
|
+
});
|
|
2180
|
+
const result = await refreshOpenKeySession(profileName, host, {
|
|
2181
|
+
paste: options.paste
|
|
2182
|
+
});
|
|
2183
|
+
outputRotationResult(result.profile, profileName, oldDid, "openkey");
|
|
2184
|
+
}
|
|
2185
|
+
function outputRotationResult(profile, profileName, oldDid, authMethod) {
|
|
2186
|
+
outputJson({
|
|
2187
|
+
rotated: true,
|
|
2188
|
+
profile: profileName,
|
|
2189
|
+
oldDid,
|
|
2190
|
+
did: profile.did,
|
|
2191
|
+
sessionDid: profile.sessionDid ?? null,
|
|
2192
|
+
authMethod,
|
|
2193
|
+
spaceId: profile.spaceId ?? null
|
|
2194
|
+
});
|
|
2195
|
+
}
|
|
2196
|
+
async function handleLocalAuth(profileName, host, options = {}) {
|
|
2131
2197
|
const profile = await ProfileManager.getProfile(profileName).catch(() => null);
|
|
2198
|
+
const posture = profile ? resolveProfilePosture(profile) : null;
|
|
2132
2199
|
let privateKey;
|
|
2133
2200
|
let address;
|
|
2134
2201
|
let did;
|
|
2135
2202
|
let sessionDid = profile?.sessionDid;
|
|
2136
|
-
if (profile?.authMethod === "local"
|
|
2203
|
+
if ((profile?.authMethod === "local" || posture === "local-owner-key") && profile.privateKey) {
|
|
2137
2204
|
privateKey = profile.privateKey;
|
|
2138
|
-
address = profile.address;
|
|
2139
|
-
did = profile.did;
|
|
2205
|
+
address = profile.address ?? await deriveAddress(privateKey);
|
|
2206
|
+
did = profile.did.startsWith("did:pkh:") ? profile.did : addressToDID(address, profile.chainId ?? DEFAULT_CHAIN_ID);
|
|
2140
2207
|
if (isInteractive()) {
|
|
2141
2208
|
process.stderr.write(theme.muted("Using existing local key") + "\n");
|
|
2142
2209
|
process.stderr.write(formatField("Address", address) + "\n");
|
|
@@ -2155,7 +2222,7 @@ async function handleLocalAuth(profileName, host) {
|
|
|
2155
2222
|
}
|
|
2156
2223
|
}
|
|
2157
2224
|
const hasKey = await ProfileManager.getKey(profileName);
|
|
2158
|
-
if (!hasKey) {
|
|
2225
|
+
if (options.forceSessionKey || !hasKey) {
|
|
2159
2226
|
const { jwk, did: generatedSessionDid } = await withSpinner("Generating session key...", async () => {
|
|
2160
2227
|
return generateKey();
|
|
2161
2228
|
});
|
|
@@ -2180,7 +2247,7 @@ async function handleLocalAuth(profileName, host) {
|
|
|
2180
2247
|
signature: sessionResult.signature
|
|
2181
2248
|
});
|
|
2182
2249
|
sessionDid = sessionResult.verificationMethod;
|
|
2183
|
-
|
|
2250
|
+
const updatedProfile = {
|
|
2184
2251
|
...profile,
|
|
2185
2252
|
name: profileName,
|
|
2186
2253
|
host,
|
|
@@ -2196,16 +2263,20 @@ async function handleLocalAuth(profileName, host) {
|
|
|
2196
2263
|
authMethod: "local",
|
|
2197
2264
|
privateKey,
|
|
2198
2265
|
address
|
|
2199
|
-
}
|
|
2200
|
-
|
|
2201
|
-
|
|
2202
|
-
|
|
2203
|
-
|
|
2204
|
-
|
|
2205
|
-
|
|
2206
|
-
|
|
2207
|
-
|
|
2208
|
-
|
|
2266
|
+
};
|
|
2267
|
+
await ProfileManager.setProfile(profileName, updatedProfile);
|
|
2268
|
+
if (options.emitOutput ?? true) {
|
|
2269
|
+
outputJson({
|
|
2270
|
+
authenticated: true,
|
|
2271
|
+
profile: profileName,
|
|
2272
|
+
did,
|
|
2273
|
+
sessionDid,
|
|
2274
|
+
address,
|
|
2275
|
+
spaceId: sessionResult.spaceId,
|
|
2276
|
+
authMethod: "local"
|
|
2277
|
+
});
|
|
2278
|
+
}
|
|
2279
|
+
return { profile: updatedProfile, sessionResult };
|
|
2209
2280
|
}
|
|
2210
2281
|
async function handleOpenKeyAuth(profileName, host, paste) {
|
|
2211
2282
|
const { profile, delegationData } = await refreshOpenKeySession(profileName, host, { paste });
|
|
@@ -2978,7 +3049,7 @@ _tc_completions() {
|
|
|
2978
3049
|
commands="init auth kv space delegation share node profile completion"
|
|
2979
3050
|
|
|
2980
3051
|
case "\${COMP_WORDS[1]}" in
|
|
2981
|
-
auth) subcommands="login logout status whoami" ;;
|
|
3052
|
+
auth) subcommands="login logout rotate status whoami" ;;
|
|
2982
3053
|
kv) subcommands="get put delete list head" ;;
|
|
2983
3054
|
space) subcommands="list create info switch" ;;
|
|
2984
3055
|
delegation) subcommands="create list info revoke" ;;
|
|
@@ -3028,7 +3099,7 @@ _tc() {
|
|
|
3028
3099
|
;;
|
|
3029
3100
|
args)
|
|
3030
3101
|
case $words[1] in
|
|
3031
|
-
auth) _values 'subcommand' login logout status whoami ;;
|
|
3102
|
+
auth) _values 'subcommand' login logout rotate status whoami ;;
|
|
3032
3103
|
kv) _values 'subcommand' get put delete list head ;;
|
|
3033
3104
|
space) _values 'subcommand' list create info switch ;;
|
|
3034
3105
|
delegation) _values 'subcommand' create list info revoke ;;
|
|
@@ -3063,7 +3134,7 @@ complete -c tc -n "not __fish_seen_subcommand_from $commands" -a profile -d "Pro
|
|
|
3063
3134
|
complete -c tc -n "not __fish_seen_subcommand_from $commands" -a completion -d "Generate shell completions"
|
|
3064
3135
|
|
|
3065
3136
|
# Subcommands
|
|
3066
|
-
complete -c tc -n "__fish_seen_subcommand_from auth" -a "login logout status whoami"
|
|
3137
|
+
complete -c tc -n "__fish_seen_subcommand_from auth" -a "login logout rotate status whoami"
|
|
3067
3138
|
complete -c tc -n "__fish_seen_subcommand_from kv" -a "get put delete list head"
|
|
3068
3139
|
complete -c tc -n "__fish_seen_subcommand_from space" -a "list create info switch"
|
|
3069
3140
|
complete -c tc -n "__fish_seen_subcommand_from delegation" -a "create list info revoke"
|
|
@@ -3262,6 +3333,12 @@ import {
|
|
|
3262
3333
|
resolveSecretPath
|
|
3263
3334
|
} from "@tinycloud/node-sdk";
|
|
3264
3335
|
var SECRETS_SPACE = "secrets";
|
|
3336
|
+
var SECRET_KV_ABILITIES = {
|
|
3337
|
+
get: "tinycloud.kv/get",
|
|
3338
|
+
put: "tinycloud.kv/put",
|
|
3339
|
+
del: "tinycloud.kv/del",
|
|
3340
|
+
list: "tinycloud.kv/list"
|
|
3341
|
+
};
|
|
3265
3342
|
async function readStdin4() {
|
|
3266
3343
|
const chunks = [];
|
|
3267
3344
|
for await (const chunk of process.stdin) {
|
|
@@ -3347,20 +3424,23 @@ function parseDate(value) {
|
|
|
3347
3424
|
const date = new Date(value);
|
|
3348
3425
|
return Number.isNaN(date.getTime()) ? null : date;
|
|
3349
3426
|
}
|
|
3427
|
+
function secretKvAbility(action) {
|
|
3428
|
+
return SECRET_KV_ABILITIES[action];
|
|
3429
|
+
}
|
|
3350
3430
|
function secretPermissionEntries(params) {
|
|
3351
3431
|
const path = params.action === "list" ? resolveSecretListPrefix(params.options) : resolveSecretPath(params.name ?? "", params.options).permissionPaths.vault;
|
|
3352
3432
|
const permissions = [{
|
|
3353
3433
|
service: "tinycloud.kv",
|
|
3354
3434
|
space: SECRETS_SPACE,
|
|
3355
3435
|
path,
|
|
3356
|
-
actions: [params.action],
|
|
3436
|
+
actions: [secretKvAbility(params.action)],
|
|
3357
3437
|
skipPrefix: true
|
|
3358
3438
|
}];
|
|
3359
3439
|
if (params.action === "get") {
|
|
3360
3440
|
permissions.push({
|
|
3361
3441
|
service: "tinycloud.encryption",
|
|
3362
3442
|
path: params.node.getDefaultEncryptionNetworkId(),
|
|
3363
|
-
actions: ["decrypt"],
|
|
3443
|
+
actions: ["tinycloud.encryption/decrypt"],
|
|
3364
3444
|
skipPrefix: true
|
|
3365
3445
|
});
|
|
3366
3446
|
}
|