@tinycloud/cli 1.2.2-beta.0 → 1.2.2-beta.2

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.
@@ -17797,6 +17797,7 @@ __export(sdk_exports, {
17797
17797
  storedSessionVerifiesLocally: () => storedSessionVerifiesLocally
17798
17798
  });
17799
17799
  import { TinyCloudNode, signedCompactUcanExpiry } from "@tinycloud/node-sdk";
17800
+ import { ownerSessionLacksProof } from "@tinycloud/operations/profile";
17800
17801
  function jwkHasPrivateParameter(jwk) {
17801
17802
  if (!jwk || typeof jwk !== "object") return false;
17802
17803
  const d = jwk.d;
@@ -17828,11 +17829,15 @@ function signedLifetimePassed(delegation) {
17828
17829
  return expiry !== void 0 && expiry.getTime() <= Date.now();
17829
17830
  }
17830
17831
  async function restoreProfileSession(node, profileName2, profile, sessionData) {
17832
+ const posture = profile === null ? void 0 : resolveProfilePosture(profile);
17833
+ if (ownerSessionLacksProof(sessionData, profile)) {
17834
+ throw sessionExpiredError(profileName2, posture);
17835
+ }
17831
17836
  try {
17832
17837
  await node.restoreSession(sessionData);
17833
17838
  } catch (error) {
17834
17839
  if (typeof error === "object" && error !== null && "code" in error && error.code === "AUTH_EXPIRED") {
17835
- throw sessionExpiredError(profileName2, profile === null ? void 0 : resolveProfilePosture(profile));
17840
+ throw sessionExpiredError(profileName2, posture);
17836
17841
  }
17837
17842
  throw error;
17838
17843
  }
@@ -20670,7 +20675,7 @@ async function localKeySignIn(options) {
20670
20675
  init_errors();
20671
20676
  init_constants();
20672
20677
  import { NodeWasmBindings, signedCompactUcanExpiry as signedCompactUcanExpiry2 } from "@tinycloud/node-sdk";
20673
- import { isLocalOwnerProfile as isLocalOwnerProfile2 } from "@tinycloud/operations/profile";
20678
+ import { isLocalOwnerProfile as isLocalOwnerProfile2, ownerSessionLacksProof as ownerSessionLacksProof2 } from "@tinycloud/operations/profile";
20674
20679
 
20675
20680
  // src/lib/duration.ts
20676
20681
  function parseDuration(input) {
@@ -20772,6 +20777,17 @@ function sessionExpiresAt(session) {
20772
20777
  if (typeof value === "string") return new Date(value).toISOString();
20773
20778
  return null;
20774
20779
  }
20780
+ function storedSessionState(session, profile) {
20781
+ if (session === null) return { state: "missing", expiresAt: null };
20782
+ if (ownerSessionLacksProof2(session, profile)) return { state: "unverified", expiresAt: null };
20783
+ const siweExpiry = typeof session.siwe === "string" ? session.siwe.match(/^Expiration Time:\s*(.+)$/m)?.[1] : void 0;
20784
+ const expiresAt = siweExpiry !== void 0 && Number.isFinite(Date.parse(siweExpiry)) ? new Date(siweExpiry).toISOString() : sessionExpiresAt(session);
20785
+ if (expiresAt === null) return { state: "unknown-expiry", expiresAt };
20786
+ return { state: Date.parse(expiresAt) <= Date.now() ? "expired" : "present", expiresAt };
20787
+ }
20788
+ function sessionStateIsUsable(state2) {
20789
+ return state2 === "present" || state2 === "unknown-expiry";
20790
+ }
20775
20791
  function ownerSpaceId(space, ownerDid) {
20776
20792
  return space.startsWith("tinycloud:") ? space : `tinycloud:${ownerDid.slice("did:".length)}:${space}`;
20777
20793
  }
@@ -21485,15 +21501,6 @@ async function acquireDeviceDelegation(input) {
21485
21501
  }
21486
21502
  throw new CLIError("DEVICE_AUTH_EXPIRED", "OpenKey device authorization expired before approval. Run the command again.", ExitCode.AUTH_REQUIRED);
21487
21503
  }
21488
- function mergePrivateJwkIntoSession(session, key) {
21489
- const sessionJwk = session.jwk;
21490
- if (!sessionJwk || typeof sessionJwk !== "object") return session;
21491
- const sessionJwkRecord = sessionJwk;
21492
- if (typeof sessionJwkRecord.d === "string" && sessionJwkRecord.d.length > 0) return session;
21493
- const privateParameter = key.d;
21494
- if (typeof privateParameter !== "string" || privateParameter.length === 0) return session;
21495
- return { ...session, jwk: { ...sessionJwkRecord, d: privateParameter } };
21496
- }
21497
21504
  async function loginWithDeviceAuthorization(input) {
21498
21505
  const snapshot = await readProfileSnapshot(input.profileName);
21499
21506
  const existing = snapshot.profile;
@@ -22244,10 +22251,12 @@ function registerAuthCommand(program, options) {
22244
22251
  }
22245
22252
  const posture = profile ? resolveProfilePosture(profile) : null;
22246
22253
  const operatorType = profile ? resolveProfileOperatorType(profile) : null;
22247
- const authenticated = session !== null;
22254
+ const { state: sessionState, expiresAt } = storedSessionState(session, profile);
22255
+ const authenticated = sessionStateIsUsable(sessionState);
22248
22256
  if (shouldOutputJson()) {
22249
22257
  outputJson({
22250
22258
  authenticated,
22259
+ session: { state: sessionState, expiresAt },
22251
22260
  did: profile?.did ?? null,
22252
22261
  sessionDid: profile?.sessionDid ?? null,
22253
22262
  ownerDid: profile?.ownerDid ?? null,
@@ -22265,6 +22274,7 @@ function registerAuthCommand(program, options) {
22265
22274
  process.stdout.write(theme.heading("Authentication Status") + "\n");
22266
22275
  process.stdout.write(formatField("Profile", ctx.profile) + "\n");
22267
22276
  process.stdout.write(formatField("Authenticated", authenticated) + "\n");
22277
+ process.stdout.write(formatField("Session", describeSession(sessionState, expiresAt)) + "\n");
22268
22278
  process.stdout.write(formatField("Auth Method", profile?.authMethod ?? null) + "\n");
22269
22279
  process.stdout.write(formatField("Posture", posture) + "\n");
22270
22280
  process.stdout.write(formatField("Operator", operatorType) + "\n");
@@ -22276,6 +22286,11 @@ function registerAuthCommand(program, options) {
22276
22286
  process.stdout.write(formatField("Address", profile?.address ?? null) + "\n");
22277
22287
  process.stdout.write(formatField("Space ID", profile?.spaceId ?? null) + "\n");
22278
22288
  process.stdout.write(formatField("Has Key", hasKey !== null) + "\n");
22289
+ if (sessionState === "expired" || sessionState === "unverified") {
22290
+ process.stdout.write(`
22291
+ ${signInAgainHint(ctx.profile, posture ?? void 0)}
22292
+ `);
22293
+ }
22279
22294
  }
22280
22295
  } catch (error) {
22281
22296
  return handleError(error);
@@ -22723,8 +22738,9 @@ function registerAuthCommand(program, options) {
22723
22738
  const ctx = await ProfileManager.resolveContext(globalOpts, { storedSession: "unused" });
22724
22739
  const profile = await ProfileManager.getProfile(ctx.profile);
22725
22740
  const session = await ProfileManager.getSession(ctx.profile);
22726
- const authenticated = session !== null;
22727
22741
  const posture = resolveProfilePosture(profile);
22742
+ const { state: sessionState, expiresAt } = storedSessionState(session, profile);
22743
+ const authenticated = sessionStateIsUsable(sessionState);
22728
22744
  const operatorType = resolveProfileOperatorType(profile);
22729
22745
  if (shouldOutputJson()) {
22730
22746
  outputJson({
@@ -22735,6 +22751,7 @@ function registerAuthCommand(program, options) {
22735
22751
  spaceId: profile.spaceId ?? null,
22736
22752
  host: profile.host,
22737
22753
  authenticated,
22754
+ session: { state: sessionState, expiresAt },
22738
22755
  authMethod: profile.authMethod ?? null,
22739
22756
  posture,
22740
22757
  operatorType,
@@ -22753,12 +22770,27 @@ function registerAuthCommand(program, options) {
22753
22770
  process.stdout.write(formatField("Space ID", profile.spaceId ?? null) + "\n");
22754
22771
  process.stdout.write(formatField("Host", profile.host) + "\n");
22755
22772
  process.stdout.write(formatField("Authenticated", authenticated) + "\n");
22773
+ process.stdout.write(formatField("Session", describeSession(sessionState, expiresAt)) + "\n");
22756
22774
  }
22757
22775
  } catch (error) {
22758
22776
  return handleError(error);
22759
22777
  }
22760
22778
  });
22761
22779
  }
22780
+ function describeSession(state2, expiresAt) {
22781
+ switch (state2) {
22782
+ case "missing":
22783
+ return "none";
22784
+ case "expired":
22785
+ return `expired ${expiresAt}`;
22786
+ case "present":
22787
+ return `active until ${expiresAt}`;
22788
+ case "unknown-expiry":
22789
+ return "active (no recorded expiry)";
22790
+ case "unverified":
22791
+ return "not usable (no signed OpenKey proof)";
22792
+ }
22793
+ }
22762
22794
  async function emitPermissionRequestArtifact(artifact, emitOption) {
22763
22795
  if (typeof emitOption === "string" && emitOption.length > 0) {
22764
22796
  await mkdir3(dirname3(emitOption), { recursive: true });
@@ -23501,15 +23533,13 @@ async function refreshOpenKeySession(profileName2, host, options = {}) {
23501
23533
  verifiedOwner = sanitizedSession.ownerDid;
23502
23534
  declined = declinedPermissions(permissions, sanitizedSession.permissions, verifiedOwner);
23503
23535
  } else {
23504
- const carriesProof = typeof delegationData.siwe === "string" && typeof delegationData.signature === "string";
23505
- const merged = mergePrivateJwkIntoSession(delegationData, key);
23506
- if (carriesProof || expiry !== void 0 || expectedOwner !== void 0) {
23507
- const signed = verifySignedSession(delegationData, key, sessionDid, { expectedOwner, expiry });
23508
- verifiedOwner = signed.ownerDid;
23509
- sanitizedSession = withVerifiedAuthority(merged, signed);
23510
- } else {
23511
- sanitizedSession = Object.fromEntries(Object.entries(withoutTrustFields(merged)).filter(([name]) => name !== "siwe" && name !== "signature"));
23536
+ const signed = verifySignedSession(delegationData, key, sessionDid, { expectedOwner, expiry });
23537
+ const spaceId = String(delegationData.spaceId);
23538
+ if (normalizePkhIdentifier(ownerSpaceId(spaceId.split(":").at(-1) ?? "", signed.ownerDid)) !== normalizePkhIdentifier(spaceId)) {
23539
+ throw new CLIError("OPENKEY_SCOPE_MISMATCH", "The approved session is for a space the signing account doesn't own. No session was saved.", ExitCode.PERMISSION_DENIED);
23512
23540
  }
23541
+ verifiedOwner = signed.ownerDid;
23542
+ sanitizedSession = withVerifiedAuthority({ ...delegationData, jwk: key }, signed);
23513
23543
  }
23514
23544
  const ownerKeyPrimary = verifiedOwner === void 0 ? void 0 : openKeyPrimaryFlag(delegationData);
23515
23545
  const updatedProfile = withOwnerKeyPrimary({
@@ -23687,7 +23717,6 @@ function registerContextCommand(program) {
23687
23717
  const profile = await ProfileManager.getProfile(ctx.profile);
23688
23718
  const session = await ProfileManager.getSession(ctx.profile);
23689
23719
  const spaceId = await resolveSpaceUri(options.space, ctx.profile) ?? (typeof session?.spaceId === "string" ? session.spaceId : profile.spaceId ?? null);
23690
- const expiresAt = sessionExpiresAt(session);
23691
23720
  let root = cmd;
23692
23721
  while (root.parent) root = root.parent;
23693
23722
  outputJson({
@@ -23699,8 +23728,7 @@ function registerContextCommand(program) {
23699
23728
  host: ctx.host,
23700
23729
  spaceId,
23701
23730
  session: {
23702
- state: session === null ? "missing" : expiresAt === null ? "unknown-expiry" : Date.parse(expiresAt) <= Date.now() ? "expired" : "present",
23703
- expiresAt,
23731
+ ...storedSessionState(session, profile),
23704
23732
  evidence: "local-metadata"
23705
23733
  },
23706
23734
  access: "not-tested"
@@ -36486,6 +36514,7 @@ init_permissions();
36486
36514
  import {
36487
36515
  NodeWasmBindings as NodeWasmBindings2
36488
36516
  } from "@tinycloud/node-sdk";
36517
+ import { ownerSessionLacksProof as ownerSessionLacksProof3 } from "@tinycloud/operations/profile";
36489
36518
  var wasmBindings = null;
36490
36519
  function registerStatusCommand(program) {
36491
36520
  program.command("status").description("Show local TinyCloud profile, session, delegation, and permission state").action(async (_options, cmd) => {
@@ -36552,7 +36581,7 @@ async function inspectProfile(params) {
36552
36581
  ]);
36553
36582
  const hasPrivateKey = typeof profile?.privateKey === "string" && profile.privateKey.length > 0;
36554
36583
  const localKeyAuthenticated = profile?.authMethod === "local" && hasPrivateKey;
36555
- const sessionAuthenticated = session !== null && sessionExpired !== true;
36584
+ const sessionAuthenticated = session !== null && sessionExpired !== true && !ownerSessionLacksProof3(session, profile);
36556
36585
  const authenticated = localKeyAuthenticated || sessionAuthenticated;
36557
36586
  const status = resolveStatus({
36558
36587
  exists: profile !== null,