passwd-sso-cli 0.4.66 → 0.4.67

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.
@@ -10,7 +10,7 @@ import { spawn } from "node:child_process";
10
10
  import { mkdirSync, lstatSync, chmodSync, unlinkSync } from "node:fs";
11
11
  import { join } from "node:path";
12
12
  import { z } from "zod";
13
- import { apiRequest, startBackgroundRefresh } from "../lib/api-client.js";
13
+ import { apiRequest, assertLoggedIn, startBackgroundRefresh } from "../lib/api-client.js";
14
14
  import { decryptData, hexEncode } from "../lib/crypto.js";
15
15
  import { buildPersonalEntryAAD, VAULT_TYPE } from "../lib/crypto-aad.js";
16
16
  import { getEncryptionKey, getUserId, getSecretKeyBytes, setEncryptionKey } from "../lib/vault-state.js";
@@ -153,7 +153,16 @@ export function handleConnection(socket) {
153
153
  };
154
154
  }
155
155
  else {
156
- response = await handleDecryptRequest(parsed.data);
156
+ try {
157
+ response = await handleDecryptRequest(parsed.data);
158
+ }
159
+ catch (err) {
160
+ // Request-layer failures (server down, revoked login) — not parse errors
161
+ response = {
162
+ ok: false,
163
+ error: `Request failed: ${err instanceof Error ? err.message : "unknown error"}`,
164
+ };
165
+ }
157
166
  }
158
167
  }
159
168
  catch (err) {
@@ -187,6 +196,8 @@ export async function decryptAgentCommand(opts) {
187
196
  "Run in an interactive terminal.\n");
188
197
  process.exit(1);
189
198
  }
199
+ // Fail fast before prompting — the passphrase is useless without a login
200
+ assertLoggedIn();
190
201
  // In --eval mode, stdout is captured by the shell — write prompt to stderr
191
202
  const passphrase = await readPassphrase("Master passphrase: ", { useStderr: opts.eval });
192
203
  if (!passphrase) {
@@ -12,7 +12,7 @@
12
12
  * substitution returns instead of blocking.
13
13
  */
14
14
  import { spawn } from "node:child_process";
15
- import { apiRequest } from "../lib/api-client.js";
15
+ import { apiRequest, assertLoggedIn } from "../lib/api-client.js";
16
16
  import { decryptData, hexEncode } from "../lib/crypto.js";
17
17
  import { buildPersonalEntryAAD, VAULT_TYPE } from "../lib/crypto-aad.js";
18
18
  import { getEncryptionKey, getUserId, getSecretKeyBytes, setEncryptionKey, isUnlocked, } from "../lib/vault-state.js";
@@ -100,6 +100,8 @@ export async function agentCommand(opts) {
100
100
  // Unlock the vault in this (parent / foreground) process.
101
101
  if (!(await autoUnlockIfNeeded())) {
102
102
  if (opts.eval && process.stdin.isTTY) {
103
+ // Fail fast before prompting — the passphrase is useless without a login
104
+ assertLoggedIn();
103
105
  // Prompt on stderr so stdout stays clean for `eval $(...)` capture.
104
106
  const passphrase = await readPassphrase("Master passphrase: ", { useStderr: true });
105
107
  if (!passphrase || !(await unlockWithPassphrase(passphrase))) {
@@ -3,7 +3,7 @@
3
3
  *
4
4
  * Derives the encryption key and stores it in process memory.
5
5
  */
6
- import { apiRequest } from "../lib/api-client.js";
6
+ import { apiRequest, assertLoggedIn } from "../lib/api-client.js";
7
7
  import { hexDecode, deriveWrappingKey, unwrapSecretKey, deriveEncryptionKey, verifyKey, } from "../lib/crypto.js";
8
8
  import { setEncryptionKey, setSecretKeyBytes, isUnlocked } from "../lib/vault-state.js";
9
9
  import * as output from "../lib/output.js";
@@ -100,6 +100,8 @@ export async function unlockCommand() {
100
100
  output.info("Vault is already unlocked.");
101
101
  return;
102
102
  }
103
+ // Fail fast before prompting — the passphrase is useless without a login
104
+ assertLoggedIn();
103
105
  const passphrase = await readPassphrase("Master passphrase: ");
104
106
  if (!passphrase) {
105
107
  output.error("Passphrase is required.");
package/dist/index.js CHANGED
@@ -175,7 +175,14 @@ program
175
175
  process.exit(1);
176
176
  }
177
177
  });
178
- program.parse();
178
+ try {
179
+ await program.parseAsync();
180
+ }
181
+ catch (err) {
182
+ // Render action-handler errors as a clean one-liner — never a stack trace
183
+ output.error(err instanceof Error ? err.message : String(err));
184
+ process.exit(1);
185
+ }
179
186
  // ─── Interactive REPL Mode ──────────────────────────────────────
180
187
  async function interactiveMode() {
181
188
  output.info("Vault unlocked. Type a command or `help` for options. `lock` to exit.");
@@ -8,6 +8,7 @@ export declare function setInsecure(enabled: boolean): void;
8
8
  export declare function getToken(): string | null;
9
9
  export declare function setTokenCache(token: string, expiresAt?: string, refreshToken?: string, clientId?: string): void;
10
10
  export declare function clearTokenCache(): void;
11
+ export declare function assertLoggedIn(): void;
11
12
  export interface ApiResponse<T = unknown> {
12
13
  ok: boolean;
13
14
  status: number;
@@ -47,6 +47,11 @@ export function clearTokenCache() {
47
47
  cachedRefreshToken = null;
48
48
  cachedClientId = null;
49
49
  }
50
+ export function assertLoggedIn() {
51
+ if (!getToken()) {
52
+ throw new Error("Not logged in. Run `passwd-sso login` first.");
53
+ }
54
+ }
50
55
  function getBaseUrl() {
51
56
  const config = loadConfig();
52
57
  if (!config.serverUrl) {
@@ -83,10 +88,8 @@ async function refreshToken() {
83
88
  }
84
89
  }
85
90
  export async function apiRequest(path, options = {}) {
91
+ assertLoggedIn();
86
92
  let token = getToken();
87
- if (!token) {
88
- throw new Error("Not logged in. Run `passwd-sso login` first.");
89
- }
90
93
  if (isTokenExpiringSoon()) {
91
94
  const refreshed = await refreshToken();
92
95
  if (refreshed) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "passwd-sso-cli",
3
- "version": "0.4.66",
3
+ "version": "0.4.67",
4
4
  "description": "CLI for passwd-sso password manager",
5
5
  "type": "module",
6
6
  "license": "MIT",