passwd-sso-cli 0.4.57 → 0.4.59

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.
@@ -16,6 +16,7 @@ import { buildPersonalEntryAAD, VAULT_TYPE } from "../lib/crypto-aad.js";
16
16
  import { getEncryptionKey, getUserId, getSecretKeyBytes, setEncryptionKey } from "../lib/vault-state.js";
17
17
  import { readPassphrase, unlockWithPassphrase } from "./unlock.js";
18
18
  import * as output from "../lib/output.js";
19
+ import { AGENT_CHILD_TIMEOUT_MS } from "../lib/time.js";
19
20
  // ─── Input Validation Schema ───────────────────────────────────
20
21
  export const DecryptRequestSchema = z.object({
21
22
  entryId: z.string().regex(/^[a-zA-Z0-9_-]{1,100}$/),
@@ -249,7 +250,7 @@ async function forkDaemon(socketPath) {
249
250
  process.stderr.write("Error: Agent child did not respond within 10s.\n");
250
251
  child.kill();
251
252
  process.exit(1);
252
- }, 10_000);
253
+ }, AGENT_CHILD_TIMEOUT_MS);
253
254
  }
254
255
  /**
255
256
  * Internal: runs as the daemon child process (forked by --eval).
@@ -23,6 +23,8 @@ import { authorizeSign } from "../lib/ssh-sign-authorizer.js";
23
23
  import { confirmSign } from "../lib/ssh-confirm.js";
24
24
  import { decryptAgentCommand } from "./agent-decrypt.js";
25
25
  import * as output from "../lib/output.js";
26
+ import { AGENT_CHILD_TIMEOUT_MS, VAULT_LOCK_POLL_INTERVAL_MS } from "../lib/time.js";
27
+ import { CLI_API_PATH } from "../lib/api-paths.js";
26
28
  /** Env flag marking the forked daemon child process. */
27
29
  const SSH_DAEMON_ENV = "_PSSO_SSH_DAEMON";
28
30
  /**
@@ -52,7 +54,7 @@ async function loadSshKeys() {
52
54
  process.exit(1);
53
55
  }
54
56
  const userId = getUserId();
55
- const res = await apiRequest("/api/passwords?type=SSH_KEY&include=blob");
57
+ const res = await apiRequest(`${CLI_API_PATH.PASSWORDS}?type=SSH_KEY&include=blob`);
56
58
  if (!res.ok) {
57
59
  output.error(`Failed to fetch SSH keys: HTTP ${res.status}`);
58
60
  process.exit(1);
@@ -133,7 +135,7 @@ export async function agentCommand(opts) {
133
135
  clearInterval(checkLock);
134
136
  process.exit(0);
135
137
  }
136
- }, 5000);
138
+ }, VAULT_LOCK_POLL_INTERVAL_MS);
137
139
  // Wait forever (signal handlers in ssh-agent-socket.ts handle cleanup)
138
140
  await new Promise(() => {
139
141
  // Never resolves — process exits via signal handlers
@@ -184,7 +186,7 @@ async function forkDaemon() {
184
186
  process.stderr.write("Error: Agent child did not respond within 10s.\n");
185
187
  child.kill();
186
188
  process.exit(1);
187
- }, 10_000);
189
+ }, AGENT_CHILD_TIMEOUT_MS);
188
190
  }
189
191
  /**
190
192
  * Internal daemon child: receives the vault secret via IPC, derives the
@@ -11,6 +11,7 @@
11
11
  * --json outputs all decrypted fields as JSON (ignores --field).
12
12
  */
13
13
  import { createConnection } from "node:net";
14
+ import { AGENT_CHILD_TIMEOUT_MS } from "../lib/time.js";
14
15
  export async function decryptCommand(id, options) {
15
16
  const socketPath = process.env.PSSO_AGENT_SOCK;
16
17
  if (!socketPath) {
@@ -95,7 +96,7 @@ export async function decryptCommand(id, options) {
95
96
  process.exitCode = 1;
96
97
  finish(err);
97
98
  });
98
- socket.setTimeout(10_000);
99
+ socket.setTimeout(AGENT_CHILD_TIMEOUT_MS);
99
100
  socket.on("timeout", () => {
100
101
  process.stderr.write("Error: Agent request timed out\n");
101
102
  process.exitCode = 1;
@@ -9,6 +9,7 @@ import { decryptData } from "../lib/crypto.js";
9
9
  import { buildPersonalEntryAAD, VAULT_TYPE } from "../lib/crypto-aad.js";
10
10
  import { writeSecretFile } from "../lib/secure-file.js";
11
11
  import * as output from "../lib/output.js";
12
+ import { CLI_API_PATH } from "../lib/api-paths.js";
12
13
  function escapeCSV(value) {
13
14
  if (value.includes(",") || value.includes('"') || value.includes("\n")) {
14
15
  return `"${value.replace(/"/g, '""')}"`;
@@ -26,7 +27,7 @@ export async function exportCommand(options) {
26
27
  output.error("Format must be 'json' or 'csv'.");
27
28
  return;
28
29
  }
29
- const res = await apiRequest("/api/passwords?include=blob");
30
+ const res = await apiRequest(`${CLI_API_PATH.PASSWORDS}?include=blob`);
30
31
  if (!res.ok) {
31
32
  output.error(`Failed to fetch entries: ${res.status}`);
32
33
  return;
@@ -6,6 +6,7 @@ import { getEncryptionKey, getUserId } from "../lib/vault-state.js";
6
6
  import { decryptData } from "../lib/crypto.js";
7
7
  import { buildPersonalEntryAAD, VAULT_TYPE } from "../lib/crypto-aad.js";
8
8
  import * as output from "../lib/output.js";
9
+ import { CLI_API_PATH } from "../lib/api-paths.js";
9
10
  export async function listCommand(options) {
10
11
  const key = getEncryptionKey();
11
12
  if (!key) {
@@ -13,7 +14,7 @@ export async function listCommand(options) {
13
14
  return;
14
15
  }
15
16
  const userId = getUserId();
16
- const res = await apiRequest("/api/passwords");
17
+ const res = await apiRequest(CLI_API_PATH.PASSWORDS);
17
18
  if (!res.ok) {
18
19
  output.error(`Failed to fetch entries: ${res.status}`);
19
20
  return;
@@ -8,6 +8,7 @@ import { buildPersonalEntryAAD, VAULT_TYPE } from "../lib/crypto-aad.js";
8
8
  import { generateTOTPCode } from "../lib/totp.js";
9
9
  import { copyToClipboard } from "../lib/clipboard.js";
10
10
  import * as output from "../lib/output.js";
11
+ import { MS_PER_SECOND } from "../lib/time.js";
11
12
  export async function totpCommand(id, options) {
12
13
  const key = getEncryptionKey();
13
14
  if (!key) {
@@ -37,7 +38,7 @@ export async function totpCommand(id, options) {
37
38
  period: blob.totp.period,
38
39
  });
39
40
  const period = blob.totp.period ?? 30;
40
- const remaining = period - (Math.floor(Date.now() / 1000) % period);
41
+ const remaining = period - (Math.floor(Date.now() / MS_PER_SECOND) % period);
41
42
  if (options.json) {
42
43
  output.json({ code, remaining, period });
43
44
  return;
@@ -0,0 +1,3 @@
1
+ export declare const CLI_API_PATH: {
2
+ readonly PASSWORDS: "/api/passwords";
3
+ };
@@ -0,0 +1,4 @@
1
+ export const CLI_API_PATH = {
2
+ PASSWORDS: "/api/passwords",
3
+ };
4
+ //# sourceMappingURL=api-paths.js.map
@@ -6,7 +6,8 @@
6
6
  */
7
7
  import { createHash } from "node:crypto";
8
8
  import { execSync } from "node:child_process";
9
- const CLEAR_TIMEOUT_MS = 30_000;
9
+ import { MS_PER_SECOND } from "./time.js";
10
+ const CLEAR_TIMEOUT_MS = 30 * MS_PER_SECOND;
10
11
  let clearTimer = null;
11
12
  let copiedHash = null;
12
13
  function hashContent(content) {
@@ -7,6 +7,7 @@
7
7
  const PBKDF2_ITERATIONS = 600_000;
8
8
  const AES_KEY_LENGTH = 256;
9
9
  const IV_LENGTH = 12;
10
+ const GCM_TAG_LENGTH = 16;
10
11
  const HKDF_ENC_INFO = "passwd-sso-enc-v1";
11
12
  const HKDF_AUTH_INFO = "passwd-sso-auth-v1";
12
13
  const VERIFICATION_PLAINTEXT = "passwd-sso-vault-verification-v1";
@@ -109,8 +110,8 @@ export async function encryptData(plaintext, key, aad) {
109
110
  params.additionalData = toArrayBuffer(aad);
110
111
  const encrypted = await crypto.subtle.encrypt(params, key, textEncode(plaintext));
111
112
  const encryptedBytes = new Uint8Array(encrypted);
112
- const ciphertext = encryptedBytes.slice(0, encryptedBytes.length - 16);
113
- const authTag = encryptedBytes.slice(encryptedBytes.length - 16);
113
+ const ciphertext = encryptedBytes.slice(0, encryptedBytes.length - GCM_TAG_LENGTH);
114
+ const authTag = encryptedBytes.slice(encryptedBytes.length - GCM_TAG_LENGTH);
114
115
  return {
115
116
  ciphertext: hexEncode(ciphertext),
116
117
  iv: hexEncode(iv),
package/dist/lib/oauth.js CHANGED
@@ -7,10 +7,15 @@
7
7
  import { randomBytes, createHash, timingSafeEqual } from "node:crypto";
8
8
  import { createServer, } from "node:http";
9
9
  import { spawn } from "node:child_process";
10
- const CALLBACK_TIMEOUT_MS = 120_000; // 2 minutes
10
+ import { MS_PER_MINUTE, MS_PER_SECOND, SEC_PER_HOUR } from "./time.js";
11
+ const CALLBACK_TIMEOUT_MS = 2 * MS_PER_MINUTE;
11
12
  const CLI_CLIENT_NAME = "passwd-sso-cli";
12
13
  const CLI_SCOPES = "credentials:list credentials:use vault:status vault:unlock-data passwords:read passwords:write ssh:sign";
14
+ const OAUTH_DEFAULT_EXPIRES_IN_SEC = SEC_PER_HOUR;
13
15
  const MCP_TOKEN_ENDPOINT = "/api/mcp/token";
16
+ const MCP_REGISTER_ENDPOINT = "/api/mcp/register";
17
+ const MCP_REVOKE_ENDPOINT = "/api/mcp/revoke";
18
+ const MCP_AUTHORIZE_ENDPOINT = "/api/mcp/authorize";
14
19
  // ─── PKCE helpers ─────────────────────────────────────────────────────────────
15
20
  export function generateCodeVerifier() {
16
21
  return randomBytes(32).toString("base64url");
@@ -117,7 +122,7 @@ export async function startCallbackServer(expectedState) {
117
122
  return new Promise((res, rej) => {
118
123
  const timer = setTimeout(() => {
119
124
  server.close();
120
- rej(new Error(`Timed out waiting for OAuth callback after ${CALLBACK_TIMEOUT_MS / 1000}s`));
125
+ rej(new Error(`Timed out waiting for OAuth callback after ${CALLBACK_TIMEOUT_MS / MS_PER_SECOND}s`));
121
126
  }, CALLBACK_TIMEOUT_MS);
122
127
  callbackPromise
123
128
  .then((result) => { clearTimeout(timer); server.close(); res(result); })
@@ -129,7 +134,7 @@ export async function startCallbackServer(expectedState) {
129
134
  // ─── DCR client registration ──────────────────────────────────────────────────
130
135
  /** Register a new public OAuth client via Dynamic Client Registration (RFC 7591). */
131
136
  export async function registerClient(serverUrl, redirectUri) {
132
- const response = await fetch(`${serverUrl}/api/mcp/register`, {
137
+ const response = await fetch(`${serverUrl}${MCP_REGISTER_ENDPOINT}`, {
133
138
  method: "POST",
134
139
  headers: { "Content-Type": "application/json" },
135
140
  body: JSON.stringify({
@@ -172,7 +177,7 @@ function parseTokenResponse(data) {
172
177
  return {
173
178
  accessToken,
174
179
  refreshToken,
175
- expiresIn: typeof expiresIn === "number" ? expiresIn : 3600,
180
+ expiresIn: typeof expiresIn === "number" ? expiresIn : OAUTH_DEFAULT_EXPIRES_IN_SEC,
176
181
  scope: typeof scope === "string" ? scope : CLI_SCOPES,
177
182
  };
178
183
  }
@@ -220,7 +225,7 @@ export async function revokeTokenRequest(serverUrl, token, clientId, tokenTypeHi
220
225
  if (tokenTypeHint)
221
226
  params.token_type_hint = tokenTypeHint;
222
227
  try {
223
- await fetch(`${serverUrl}/api/mcp/revoke`, {
228
+ await fetch(`${serverUrl}${MCP_REVOKE_ENDPOINT}`, {
224
229
  method: "POST",
225
230
  headers: { "Content-Type": "application/x-www-form-urlencoded" },
226
231
  body: new URLSearchParams(params).toString(),
@@ -298,7 +303,7 @@ export async function runOAuthFlow(serverUrl) {
298
303
  const { port, waitForCallback } = await startCallbackServer(state);
299
304
  const redirectUri = `http://127.0.0.1:${port}/callback`;
300
305
  const { clientId } = await registerClient(serverUrl, redirectUri);
301
- const authUrl = new URL(`${serverUrl}/api/mcp/authorize`);
306
+ const authUrl = new URL(`${serverUrl}${MCP_AUTHORIZE_ENDPOINT}`);
302
307
  authUrl.searchParams.set("response_type", "code");
303
308
  authUrl.searchParams.set("client_id", clientId);
304
309
  authUrl.searchParams.set("redirect_uri", redirectUri);
@@ -6,3 +6,13 @@ export declare const MS_PER_MINUTE: number;
6
6
  export declare const MS_PER_HOUR: number;
7
7
  /** Milliseconds per day. */
8
8
  export declare const MS_PER_DAY: number;
9
+ /** Seconds per minute. */
10
+ export declare const SEC_PER_MINUTE = 60;
11
+ /** Seconds per hour. */
12
+ export declare const SEC_PER_HOUR: number;
13
+ /** Seconds per day. */
14
+ export declare const SEC_PER_DAY: number;
15
+ /** Timeout for agent child process acknowledgement (agent-decrypt, agent, decrypt). */
16
+ export declare const AGENT_CHILD_TIMEOUT_MS: number;
17
+ /** Polling interval for vault lock check in agent foreground mode. */
18
+ export declare const VAULT_LOCK_POLL_INTERVAL_MS: number;
package/dist/lib/time.js CHANGED
@@ -6,4 +6,14 @@ export const MS_PER_MINUTE = 60 * MS_PER_SECOND;
6
6
  export const MS_PER_HOUR = 60 * MS_PER_MINUTE;
7
7
  /** Milliseconds per day. */
8
8
  export const MS_PER_DAY = 24 * MS_PER_HOUR;
9
+ /** Seconds per minute. */
10
+ export const SEC_PER_MINUTE = 60;
11
+ /** Seconds per hour. */
12
+ export const SEC_PER_HOUR = 60 * SEC_PER_MINUTE;
13
+ /** Seconds per day. */
14
+ export const SEC_PER_DAY = 24 * SEC_PER_HOUR;
15
+ /** Timeout for agent child process acknowledgement (agent-decrypt, agent, decrypt). */
16
+ export const AGENT_CHILD_TIMEOUT_MS = 10 * MS_PER_SECOND;
17
+ /** Polling interval for vault lock check in agent foreground mode. */
18
+ export const VAULT_LOCK_POLL_INTERVAL_MS = 5 * MS_PER_SECOND;
9
19
  //# sourceMappingURL=time.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "passwd-sso-cli",
3
- "version": "0.4.57",
3
+ "version": "0.4.59",
4
4
  "description": "CLI for passwd-sso password manager",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -51,6 +51,7 @@
51
51
  "vitest": "^4.1.8"
52
52
  },
53
53
  "overrides": {
54
- "postcss": ">=8.5.10"
54
+ "postcss": ">=8.5.10",
55
+ "esbuild": ">=0.28.1"
55
56
  }
56
57
  }