@knowzai/core 0.1.0
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/LICENSE +21 -0
- package/dist/.tsbuildinfo +1 -0
- package/dist/auth.d.ts +55 -0
- package/dist/auth.d.ts.map +1 -0
- package/dist/auth.js +107 -0
- package/dist/auth.js.map +1 -0
- package/dist/config.d.ts +169 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +178 -0
- package/dist/config.js.map +1 -0
- package/dist/credential-store.d.ts +34 -0
- package/dist/credential-store.d.ts.map +1 -0
- package/dist/credential-store.js +224 -0
- package/dist/credential-store.js.map +1 -0
- package/dist/errors.d.ts +30 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +53 -0
- package/dist/errors.js.map +1 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +8 -0
- package/dist/index.js.map +1 -0
- package/dist/logger.d.ts +26 -0
- package/dist/logger.d.ts.map +1 -0
- package/dist/logger.js +63 -0
- package/dist/logger.js.map +1 -0
- package/dist/redactor.d.ts +13 -0
- package/dist/redactor.d.ts.map +1 -0
- package/dist/redactor.js +60 -0
- package/dist/redactor.js.map +1 -0
- package/dist/settings.d.ts +19 -0
- package/dist/settings.d.ts.map +1 -0
- package/dist/settings.js +65 -0
- package/dist/settings.js.map +1 -0
- package/package.json +37 -0
package/dist/config.js
ADDED
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Config system: `~/.knowz/config.json` with multi-profile support, Zod
|
|
3
|
+
* validation, and the resolution precedence flag > env > profile > default.
|
|
4
|
+
* Secrets are NEVER stored here (credential store owns those — N3).
|
|
5
|
+
*
|
|
6
|
+
* For test isolation set `KNOWZ_CONFIG_DIR` to redirect the config directory.
|
|
7
|
+
*/
|
|
8
|
+
import { homedir } from 'node:os';
|
|
9
|
+
import { join } from 'node:path';
|
|
10
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync, renameSync } from 'node:fs';
|
|
11
|
+
import { z } from 'zod';
|
|
12
|
+
import { KnowzError, ExitCode } from './errors.js';
|
|
13
|
+
// ---------------------------------------------------------------------------
|
|
14
|
+
// Built-in environment defaults
|
|
15
|
+
// ---------------------------------------------------------------------------
|
|
16
|
+
export const BUILTIN_API_URLS = {
|
|
17
|
+
dev: 'https://api.dev.knowz.io',
|
|
18
|
+
prod: 'https://api.knowz.io',
|
|
19
|
+
};
|
|
20
|
+
export const DEFAULT_PROFILE = 'dev';
|
|
21
|
+
export const DEFAULT_API_URL = BUILTIN_API_URLS[DEFAULT_PROFILE];
|
|
22
|
+
// ---------------------------------------------------------------------------
|
|
23
|
+
// Schema
|
|
24
|
+
// ---------------------------------------------------------------------------
|
|
25
|
+
export const ProfileConfigSchema = z
|
|
26
|
+
.object({
|
|
27
|
+
apiUrl: z.string().url(),
|
|
28
|
+
defaultVaultId: z.string().optional(),
|
|
29
|
+
email: z.string().optional(),
|
|
30
|
+
tenantId: z.string().optional(),
|
|
31
|
+
label: z.string().optional(),
|
|
32
|
+
/** When set, local storage uses this Postgres+pgvector DSN (see `knowz pg up`). */
|
|
33
|
+
pgDsn: z.string().optional(),
|
|
34
|
+
})
|
|
35
|
+
.strict();
|
|
36
|
+
/** Global (not per-profile) UI preferences. */
|
|
37
|
+
export const UiConfigSchema = z
|
|
38
|
+
.object({
|
|
39
|
+
/** Interactive frontend: 'menu' (inquirer) or 'tui' (Ink, when available). */
|
|
40
|
+
frontend: z.enum(['menu', 'tui']).optional(),
|
|
41
|
+
})
|
|
42
|
+
.strict();
|
|
43
|
+
/**
|
|
44
|
+
* Portable platform provider presets. Kept in lockstep with the CLI's
|
|
45
|
+
* `PLATFORM_PROVIDERS` (deploy/portable/runtime-contract.json). Duplicated here
|
|
46
|
+
* because `@knowzai/core` is a leaf package the CLI depends on — it cannot import
|
|
47
|
+
* the CLI's platform-runtime module.
|
|
48
|
+
*/
|
|
49
|
+
export const PLATFORM_PROVIDER_PRESETS = ['offline', 'azure', 'gcp', 'knowz-cloud', 'openai-compatible'];
|
|
50
|
+
/** Global (not per-profile) portable-platform deployment preferences. */
|
|
51
|
+
export const PlatformConfigSchema = z
|
|
52
|
+
.object({
|
|
53
|
+
/** Provider preset reused on the next `knowz up` (never a secret). */
|
|
54
|
+
defaultProvider: z.enum(PLATFORM_PROVIDER_PRESETS).optional(),
|
|
55
|
+
})
|
|
56
|
+
.strict();
|
|
57
|
+
export const KnowzConfigSchema = z
|
|
58
|
+
.object({
|
|
59
|
+
activeProfile: z.string().min(1),
|
|
60
|
+
profiles: z.record(z.string(), ProfileConfigSchema),
|
|
61
|
+
/** Global UI preferences (optional; absent in existing configs). */
|
|
62
|
+
ui: UiConfigSchema.optional(),
|
|
63
|
+
/** Global portable-platform preferences (optional; absent in existing configs). */
|
|
64
|
+
platform: PlatformConfigSchema.optional(),
|
|
65
|
+
})
|
|
66
|
+
.strict();
|
|
67
|
+
// ---------------------------------------------------------------------------
|
|
68
|
+
// Paths
|
|
69
|
+
// ---------------------------------------------------------------------------
|
|
70
|
+
export function configDir() {
|
|
71
|
+
return process.env.KNOWZ_CONFIG_DIR ?? join(homedir(), '.knowz');
|
|
72
|
+
}
|
|
73
|
+
export function configPath() {
|
|
74
|
+
return join(configDir(), 'config.json');
|
|
75
|
+
}
|
|
76
|
+
// ---------------------------------------------------------------------------
|
|
77
|
+
// Defaults
|
|
78
|
+
// ---------------------------------------------------------------------------
|
|
79
|
+
export function defaultConfig() {
|
|
80
|
+
return {
|
|
81
|
+
activeProfile: DEFAULT_PROFILE,
|
|
82
|
+
profiles: {
|
|
83
|
+
dev: { apiUrl: BUILTIN_API_URLS.dev },
|
|
84
|
+
prod: { apiUrl: BUILTIN_API_URLS.prod },
|
|
85
|
+
},
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
// ---------------------------------------------------------------------------
|
|
89
|
+
// Load / Save
|
|
90
|
+
// ---------------------------------------------------------------------------
|
|
91
|
+
/** Read + validate config. Missing file → built-in defaults. Invalid → KnowzError(Usage). */
|
|
92
|
+
export function loadConfig() {
|
|
93
|
+
const path = configPath();
|
|
94
|
+
if (!existsSync(path))
|
|
95
|
+
return defaultConfig();
|
|
96
|
+
let raw;
|
|
97
|
+
try {
|
|
98
|
+
raw = readFileSync(path, 'utf8');
|
|
99
|
+
}
|
|
100
|
+
catch (e) {
|
|
101
|
+
throw new KnowzError(`Unable to read config at ${path}`, ExitCode.Usage, { cause: e });
|
|
102
|
+
}
|
|
103
|
+
let parsed;
|
|
104
|
+
try {
|
|
105
|
+
parsed = JSON.parse(raw);
|
|
106
|
+
}
|
|
107
|
+
catch (e) {
|
|
108
|
+
throw new KnowzError(`Config at ${path} is not valid JSON`, ExitCode.Usage, { cause: e });
|
|
109
|
+
}
|
|
110
|
+
const result = KnowzConfigSchema.safeParse(parsed);
|
|
111
|
+
if (!result.success) {
|
|
112
|
+
const first = result.error.issues[0];
|
|
113
|
+
const where = first ? `'${first.path.join('.') || '(root)'}': ${first.message}` : 'unknown';
|
|
114
|
+
throw new KnowzError(`Invalid config at ${path} — ${where}`, ExitCode.Usage);
|
|
115
|
+
}
|
|
116
|
+
return result.data;
|
|
117
|
+
}
|
|
118
|
+
/** Atomic write with file mode 0600 / dir mode 0700. */
|
|
119
|
+
export function saveConfig(cfg) {
|
|
120
|
+
const validated = KnowzConfigSchema.parse(cfg);
|
|
121
|
+
const dir = configDir();
|
|
122
|
+
mkdirSync(dir, { recursive: true, mode: 0o700 });
|
|
123
|
+
const path = configPath();
|
|
124
|
+
const tmp = `${path}.${process.pid}.tmp`;
|
|
125
|
+
writeFileSync(tmp, `${JSON.stringify(validated, null, 2)}\n`, { mode: 0o600 });
|
|
126
|
+
renameSync(tmp, path);
|
|
127
|
+
}
|
|
128
|
+
// ---------------------------------------------------------------------------
|
|
129
|
+
// Resolution (flag > env > profile > default)
|
|
130
|
+
// ---------------------------------------------------------------------------
|
|
131
|
+
export function resolveProfileName(opts = {}, cfg) {
|
|
132
|
+
return opts.profileFlag ?? process.env.KNOWZ_PROFILE ?? cfg?.activeProfile ?? DEFAULT_PROFILE;
|
|
133
|
+
}
|
|
134
|
+
export function resolveProfile(opts = {}, cfg = loadConfig()) {
|
|
135
|
+
const name = resolveProfileName(opts, cfg);
|
|
136
|
+
const profile = cfg.profiles[name] ??
|
|
137
|
+
{ apiUrl: BUILTIN_API_URLS[name] ?? DEFAULT_API_URL };
|
|
138
|
+
return { name, profile };
|
|
139
|
+
}
|
|
140
|
+
export function resolveApiUrl(opts = {}, cfg = loadConfig()) {
|
|
141
|
+
if (opts.apiUrlFlag)
|
|
142
|
+
return opts.apiUrlFlag;
|
|
143
|
+
if (process.env.KNOWZ_API_URL)
|
|
144
|
+
return process.env.KNOWZ_API_URL;
|
|
145
|
+
const { profile } = resolveProfile({ profileFlag: opts.profileFlag }, cfg);
|
|
146
|
+
return profile.apiUrl ?? DEFAULT_API_URL;
|
|
147
|
+
}
|
|
148
|
+
// ---------------------------------------------------------------------------
|
|
149
|
+
// UI preferences (global, not per-profile)
|
|
150
|
+
// ---------------------------------------------------------------------------
|
|
151
|
+
/** The configured interactive frontend ('menu' | 'tui'), or undefined. */
|
|
152
|
+
export function getUiFrontend(cfg) {
|
|
153
|
+
return cfg.ui?.frontend;
|
|
154
|
+
}
|
|
155
|
+
/** Set the interactive frontend preference. Throws on an unknown value. */
|
|
156
|
+
export function setUiFrontend(cfg, frontend) {
|
|
157
|
+
const f = frontend.toLowerCase();
|
|
158
|
+
if (f !== 'menu' && f !== 'tui') {
|
|
159
|
+
throw new KnowzError(`Unknown UI frontend '${frontend}' (use 'menu' or 'tui').`, ExitCode.Usage);
|
|
160
|
+
}
|
|
161
|
+
cfg.ui = { ...(cfg.ui ?? {}), frontend: f };
|
|
162
|
+
}
|
|
163
|
+
// ---------------------------------------------------------------------------
|
|
164
|
+
// Portable-platform preferences (global, not per-profile)
|
|
165
|
+
// ---------------------------------------------------------------------------
|
|
166
|
+
/** The persisted default portable-platform provider preset, or undefined. */
|
|
167
|
+
export function getPlatformDefaultProvider(cfg) {
|
|
168
|
+
return cfg.platform?.defaultProvider;
|
|
169
|
+
}
|
|
170
|
+
/** Persist the default provider preset for future `knowz up` reruns. Throws on an unknown preset. */
|
|
171
|
+
export function setPlatformDefaultProvider(cfg, provider) {
|
|
172
|
+
const p = provider.toLowerCase();
|
|
173
|
+
if (!PLATFORM_PROVIDER_PRESETS.includes(p)) {
|
|
174
|
+
throw new KnowzError(`Unknown platform provider '${provider}' (use ${PLATFORM_PROVIDER_PRESETS.join(', ')}).`, ExitCode.Usage);
|
|
175
|
+
}
|
|
176
|
+
cfg.platform = { ...(cfg.platform ?? {}), defaultProvider: p };
|
|
177
|
+
}
|
|
178
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Credential store: OS keychain (preferred) with a mandatory AES-256-GCM
|
|
3
|
+
* encrypted-file fallback for headless/CI environments (Discovery D1 — keyring
|
|
4
|
+
* throws AccessDenied with no Secret Service). Secrets are NEVER plaintext.
|
|
5
|
+
*
|
|
6
|
+
* Security requirements S-N3-1..3:
|
|
7
|
+
* - file perms 0600, dir 0700
|
|
8
|
+
* - 96-bit random GCM nonce per write, auth tag verified on read (tamper -> throw)
|
|
9
|
+
* - wrapping key derived via scrypt (N=2^15) from a passphrase, else a
|
|
10
|
+
* machine-bound key. Machine-bound mode is OBFUSCATION, not protection.
|
|
11
|
+
*
|
|
12
|
+
* NOTE (deviation from S-N3-2): the KDF is Node's built-in scrypt rather than
|
|
13
|
+
* Argon2id — chosen to avoid an extra native dependency. scrypt is memory-hard
|
|
14
|
+
* and FIPS-adjacent; flagged for security re-review at Gate #3.
|
|
15
|
+
*/
|
|
16
|
+
export type KeyBackend = 'keychain' | 'encrypted-file';
|
|
17
|
+
export type FileKeyMode = 'passphrase' | 'machine-bound';
|
|
18
|
+
export interface CredentialStore {
|
|
19
|
+
backend(): KeyBackend;
|
|
20
|
+
fileKeyMode(): FileKeyMode | null;
|
|
21
|
+
setSecret(profile: string, secret: string): Promise<void>;
|
|
22
|
+
getSecret(profile: string): Promise<string | undefined>;
|
|
23
|
+
deleteSecret(profile: string): Promise<void>;
|
|
24
|
+
deleteAll(): Promise<void>;
|
|
25
|
+
listProfiles(): Promise<string[]>;
|
|
26
|
+
}
|
|
27
|
+
export interface OpenStoreOptions {
|
|
28
|
+
passphrase?: string;
|
|
29
|
+
/** Force the encrypted-file backend (skip keychain probe) — used in tests. */
|
|
30
|
+
forceFile?: boolean;
|
|
31
|
+
}
|
|
32
|
+
/** Probe the OS keychain; fall back to the encrypted file when unavailable. */
|
|
33
|
+
export declare function openCredentialStore(opts?: OpenStoreOptions): Promise<CredentialStore>;
|
|
34
|
+
//# sourceMappingURL=credential-store.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"credential-store.d.ts","sourceRoot":"","sources":["../src/credential-store.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAgBH,MAAM,MAAM,UAAU,GAAG,UAAU,GAAG,gBAAgB,CAAC;AACvD,MAAM,MAAM,WAAW,GAAG,YAAY,GAAG,eAAe,CAAC;AAEzD,MAAM,WAAW,eAAe;IAC9B,OAAO,IAAI,UAAU,CAAC;IACtB,WAAW,IAAI,WAAW,GAAG,IAAI,CAAC;IAClC,SAAS,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC1D,SAAS,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAAC;IACxD,YAAY,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC7C,SAAS,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IAC3B,YAAY,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;CACnC;AAuMD,MAAM,WAAW,gBAAgB;IAC/B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,8EAA8E;IAC9E,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB;AAED,+EAA+E;AAC/E,wBAAsB,mBAAmB,CAAC,IAAI,GAAE,gBAAqB,GAAG,OAAO,CAAC,eAAe,CAAC,CAqB/F"}
|
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Credential store: OS keychain (preferred) with a mandatory AES-256-GCM
|
|
3
|
+
* encrypted-file fallback for headless/CI environments (Discovery D1 — keyring
|
|
4
|
+
* throws AccessDenied with no Secret Service). Secrets are NEVER plaintext.
|
|
5
|
+
*
|
|
6
|
+
* Security requirements S-N3-1..3:
|
|
7
|
+
* - file perms 0600, dir 0700
|
|
8
|
+
* - 96-bit random GCM nonce per write, auth tag verified on read (tamper -> throw)
|
|
9
|
+
* - wrapping key derived via scrypt (N=2^15) from a passphrase, else a
|
|
10
|
+
* machine-bound key. Machine-bound mode is OBFUSCATION, not protection.
|
|
11
|
+
*
|
|
12
|
+
* NOTE (deviation from S-N3-2): the KDF is Node's built-in scrypt rather than
|
|
13
|
+
* Argon2id — chosen to avoid an extra native dependency. scrypt is memory-hard
|
|
14
|
+
* and FIPS-adjacent; flagged for security re-review at Gate #3.
|
|
15
|
+
*/
|
|
16
|
+
import { hostname } from 'node:os';
|
|
17
|
+
import { join } from 'node:path';
|
|
18
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync, renameSync, rmSync, } from 'node:fs';
|
|
19
|
+
import { randomBytes, createCipheriv, createDecipheriv, scryptSync } from 'node:crypto';
|
|
20
|
+
import { configDir } from './config.js';
|
|
21
|
+
import { KnowzError, ExitCode } from './errors.js';
|
|
22
|
+
const SERVICE = 'knowz-cli';
|
|
23
|
+
const SCRYPT = { N: 1 << 15, r: 8, p: 1, maxmem: 96 * 1024 * 1024 };
|
|
24
|
+
const encFile = () => join(configDir(), 'credentials.enc');
|
|
25
|
+
const indexFile = () => join(configDir(), 'credential-index.json');
|
|
26
|
+
const installSaltFile = () => join(configDir(), '.install-salt');
|
|
27
|
+
function ensureDir() {
|
|
28
|
+
mkdirSync(configDir(), { recursive: true, mode: 0o700 });
|
|
29
|
+
}
|
|
30
|
+
function writeFile0600(path, data) {
|
|
31
|
+
ensureDir();
|
|
32
|
+
const tmp = `${path}.${process.pid}.tmp`;
|
|
33
|
+
writeFileSync(tmp, data, { mode: 0o600 });
|
|
34
|
+
renameSync(tmp, path);
|
|
35
|
+
}
|
|
36
|
+
// --------------------------------------------------------------------------
|
|
37
|
+
// Profile index (so keychain — which can't enumerate — supports deleteAll/list)
|
|
38
|
+
// --------------------------------------------------------------------------
|
|
39
|
+
function readIndex() {
|
|
40
|
+
if (!existsSync(indexFile()))
|
|
41
|
+
return [];
|
|
42
|
+
try {
|
|
43
|
+
const v = JSON.parse(readFileSync(indexFile(), 'utf8'));
|
|
44
|
+
return Array.isArray(v) ? v.filter((x) => typeof x === 'string') : [];
|
|
45
|
+
}
|
|
46
|
+
catch {
|
|
47
|
+
return [];
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
function writeIndex(profiles) {
|
|
51
|
+
writeFile0600(indexFile(), JSON.stringify([...new Set(profiles)]));
|
|
52
|
+
}
|
|
53
|
+
function addToIndex(p) {
|
|
54
|
+
writeIndex([...readIndex(), p]);
|
|
55
|
+
}
|
|
56
|
+
function removeFromIndex(p) {
|
|
57
|
+
writeIndex(readIndex().filter((x) => x !== p));
|
|
58
|
+
}
|
|
59
|
+
function installSalt() {
|
|
60
|
+
if (existsSync(installSaltFile()))
|
|
61
|
+
return Buffer.from(readFileSync(installSaltFile(), 'utf8'), 'base64');
|
|
62
|
+
const salt = randomBytes(32);
|
|
63
|
+
writeFile0600(installSaltFile(), salt.toString('base64'));
|
|
64
|
+
return salt;
|
|
65
|
+
}
|
|
66
|
+
function deriveKey(mode, salt, passphrase) {
|
|
67
|
+
if (mode === 'passphrase') {
|
|
68
|
+
if (!passphrase)
|
|
69
|
+
throw new KnowzError('Passphrase required to unlock credentials', ExitCode.Auth);
|
|
70
|
+
return scryptSync(passphrase, salt, 32, SCRYPT);
|
|
71
|
+
}
|
|
72
|
+
// machine-bound: key material = installSalt + hostname, salted by `salt`.
|
|
73
|
+
const material = Buffer.concat([installSalt(), Buffer.from(hostname())]);
|
|
74
|
+
return scryptSync(material, salt, 32, SCRYPT);
|
|
75
|
+
}
|
|
76
|
+
class FileStore {
|
|
77
|
+
mode;
|
|
78
|
+
passphrase;
|
|
79
|
+
constructor(mode, passphrase) {
|
|
80
|
+
this.mode = mode;
|
|
81
|
+
this.passphrase = passphrase;
|
|
82
|
+
}
|
|
83
|
+
backend() {
|
|
84
|
+
return 'encrypted-file';
|
|
85
|
+
}
|
|
86
|
+
fileKeyMode() {
|
|
87
|
+
return this.mode;
|
|
88
|
+
}
|
|
89
|
+
loadMap() {
|
|
90
|
+
if (!existsSync(encFile()))
|
|
91
|
+
return {};
|
|
92
|
+
const env = JSON.parse(readFileSync(encFile(), 'utf8'));
|
|
93
|
+
const salt = Buffer.from(env.salt, 'base64');
|
|
94
|
+
const key = deriveKey(env.mode, salt, this.passphrase);
|
|
95
|
+
const decipher = createDecipheriv('aes-256-gcm', key, Buffer.from(env.nonce, 'base64'));
|
|
96
|
+
decipher.setAuthTag(Buffer.from(env.tag, 'base64'));
|
|
97
|
+
let plain;
|
|
98
|
+
try {
|
|
99
|
+
plain = Buffer.concat([decipher.update(Buffer.from(env.ct, 'base64')), decipher.final()]);
|
|
100
|
+
}
|
|
101
|
+
catch (e) {
|
|
102
|
+
throw new KnowzError('Credential file failed integrity check (wrong passphrase or tampering)', ExitCode.Auth, { cause: e });
|
|
103
|
+
}
|
|
104
|
+
return JSON.parse(plain.toString('utf8'));
|
|
105
|
+
}
|
|
106
|
+
saveMap(map) {
|
|
107
|
+
// Reuse the existing salt when the mode matches; else mint a new one.
|
|
108
|
+
let salt = randomBytes(16);
|
|
109
|
+
if (existsSync(encFile())) {
|
|
110
|
+
try {
|
|
111
|
+
const prev = JSON.parse(readFileSync(encFile(), 'utf8'));
|
|
112
|
+
if (prev.mode === this.mode)
|
|
113
|
+
salt = Buffer.from(prev.salt, 'base64');
|
|
114
|
+
}
|
|
115
|
+
catch {
|
|
116
|
+
/* fall through with fresh salt */
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
const key = deriveKey(this.mode, salt, this.passphrase);
|
|
120
|
+
const nonce = randomBytes(12);
|
|
121
|
+
const cipher = createCipheriv('aes-256-gcm', key, nonce);
|
|
122
|
+
const ct = Buffer.concat([cipher.update(JSON.stringify(map), 'utf8'), cipher.final()]);
|
|
123
|
+
const tag = cipher.getAuthTag();
|
|
124
|
+
const env = {
|
|
125
|
+
v: 1,
|
|
126
|
+
mode: this.mode,
|
|
127
|
+
salt: salt.toString('base64'),
|
|
128
|
+
nonce: nonce.toString('base64'),
|
|
129
|
+
ct: ct.toString('base64'),
|
|
130
|
+
tag: tag.toString('base64'),
|
|
131
|
+
};
|
|
132
|
+
writeFile0600(encFile(), JSON.stringify(env));
|
|
133
|
+
}
|
|
134
|
+
async setSecret(profile, secret) {
|
|
135
|
+
const map = this.loadMap();
|
|
136
|
+
map[profile] = secret;
|
|
137
|
+
this.saveMap(map);
|
|
138
|
+
addToIndex(profile);
|
|
139
|
+
}
|
|
140
|
+
async getSecret(profile) {
|
|
141
|
+
return this.loadMap()[profile];
|
|
142
|
+
}
|
|
143
|
+
async deleteSecret(profile) {
|
|
144
|
+
const map = this.loadMap();
|
|
145
|
+
delete map[profile];
|
|
146
|
+
this.saveMap(map);
|
|
147
|
+
removeFromIndex(profile);
|
|
148
|
+
}
|
|
149
|
+
async deleteAll() {
|
|
150
|
+
rmSync(encFile(), { force: true });
|
|
151
|
+
writeIndex([]);
|
|
152
|
+
}
|
|
153
|
+
async listProfiles() {
|
|
154
|
+
return Object.keys(this.loadMap());
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
// --------------------------------------------------------------------------
|
|
158
|
+
// Keychain backend
|
|
159
|
+
// --------------------------------------------------------------------------
|
|
160
|
+
class KeychainStore {
|
|
161
|
+
Entry;
|
|
162
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
163
|
+
constructor(Entry) {
|
|
164
|
+
this.Entry = Entry;
|
|
165
|
+
}
|
|
166
|
+
backend() {
|
|
167
|
+
return 'keychain';
|
|
168
|
+
}
|
|
169
|
+
fileKeyMode() {
|
|
170
|
+
return null;
|
|
171
|
+
}
|
|
172
|
+
async setSecret(profile, secret) {
|
|
173
|
+
new this.Entry(SERVICE, profile).setPassword(secret);
|
|
174
|
+
addToIndex(profile);
|
|
175
|
+
}
|
|
176
|
+
async getSecret(profile) {
|
|
177
|
+
try {
|
|
178
|
+
return new this.Entry(SERVICE, profile).getPassword() ?? undefined;
|
|
179
|
+
}
|
|
180
|
+
catch {
|
|
181
|
+
return undefined;
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
async deleteSecret(profile) {
|
|
185
|
+
try {
|
|
186
|
+
new this.Entry(SERVICE, profile).deletePassword();
|
|
187
|
+
}
|
|
188
|
+
catch {
|
|
189
|
+
/* already absent */
|
|
190
|
+
}
|
|
191
|
+
removeFromIndex(profile);
|
|
192
|
+
}
|
|
193
|
+
async deleteAll() {
|
|
194
|
+
for (const p of readIndex())
|
|
195
|
+
await this.deleteSecret(p);
|
|
196
|
+
writeIndex([]);
|
|
197
|
+
}
|
|
198
|
+
async listProfiles() {
|
|
199
|
+
return readIndex();
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
/** Probe the OS keychain; fall back to the encrypted file when unavailable. */
|
|
203
|
+
export async function openCredentialStore(opts = {}) {
|
|
204
|
+
const passphrase = opts.passphrase ?? process.env.KNOWZ_KEYRING_PASSPHRASE;
|
|
205
|
+
if (!opts.forceFile && process.env.KNOWZ_FORCE_FILE_KEYSTORE !== '1') {
|
|
206
|
+
try {
|
|
207
|
+
const mod = (await import('@napi-rs/keyring'));
|
|
208
|
+
const Entry = mod.Entry;
|
|
209
|
+
// Probe an actual write/read/delete; throws AccessDenied in headless envs.
|
|
210
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
211
|
+
const probe = new Entry(SERVICE, '__probe__');
|
|
212
|
+
probe.setPassword('1');
|
|
213
|
+
probe.getPassword();
|
|
214
|
+
probe.deletePassword();
|
|
215
|
+
return new KeychainStore(Entry);
|
|
216
|
+
}
|
|
217
|
+
catch {
|
|
218
|
+
/* fall through to encrypted file */
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
const mode = passphrase ? 'passphrase' : 'machine-bound';
|
|
222
|
+
return new FileStore(mode, passphrase);
|
|
223
|
+
}
|
|
224
|
+
//# sourceMappingURL=credential-store.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"credential-store.js","sourceRoot":"","sources":["../src/credential-store.ts"],"names":[],"mappings":"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"}
|
package/dist/errors.d.ts
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/** Stable process exit-code contract (see FEAT_KnowzCliFoundation). */
|
|
2
|
+
export declare const ExitCode: {
|
|
3
|
+
readonly Success: 0;
|
|
4
|
+
readonly Generic: 1;
|
|
5
|
+
readonly Usage: 2;
|
|
6
|
+
readonly Auth: 3;
|
|
7
|
+
readonly Api: 4;
|
|
8
|
+
readonly NotFound: 5;
|
|
9
|
+
};
|
|
10
|
+
export type ExitCodeValue = (typeof ExitCode)[keyof typeof ExitCode];
|
|
11
|
+
/**
|
|
12
|
+
* A CLI error carrying the process exit code to use. The CLI's BaseCommand
|
|
13
|
+
* catch handler maps `exitCode` straight to `process.exitCode`; an unknown
|
|
14
|
+
* thrown Error maps to `ExitCode.Generic`.
|
|
15
|
+
*/
|
|
16
|
+
export declare class KnowzError extends Error {
|
|
17
|
+
readonly exitCode: ExitCodeValue;
|
|
18
|
+
constructor(message: string, exitCode?: ExitCodeValue, options?: {
|
|
19
|
+
cause?: unknown;
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
export declare function isKnowzError(e: unknown): e is KnowzError;
|
|
23
|
+
/**
|
|
24
|
+
* Map any thrown value to a process exit code:
|
|
25
|
+
* - KnowzError → its declared exitCode
|
|
26
|
+
* - ApiError → 404 NotFound(5), 401/403 Auth(3), else Api(4)
|
|
27
|
+
* - anything else → Generic(1)
|
|
28
|
+
*/
|
|
29
|
+
export declare function exitCodeForError(e: unknown): ExitCodeValue;
|
|
30
|
+
//# sourceMappingURL=errors.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA,uEAAuE;AACvE,eAAO,MAAM,QAAQ;;;;;;;CAOX,CAAC;AAEX,MAAM,MAAM,aAAa,GAAG,CAAC,OAAO,QAAQ,CAAC,CAAC,MAAM,OAAO,QAAQ,CAAC,CAAC;AAErE;;;;GAIG;AACH,qBAAa,UAAW,SAAQ,KAAK;IACnC,QAAQ,CAAC,QAAQ,EAAE,aAAa,CAAC;gBAErB,OAAO,EAAE,MAAM,EAAE,QAAQ,GAAE,aAAgC,EAAE,OAAO,CAAC,EAAE;QAAE,KAAK,CAAC,EAAE,OAAO,CAAA;KAAE;CAMvG;AAED,wBAAgB,YAAY,CAAC,CAAC,EAAE,OAAO,GAAG,CAAC,IAAI,UAAU,CAExD;AAED;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,CAAC,EAAE,OAAO,GAAG,aAAa,CAQ1D"}
|
package/dist/errors.js
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/** Stable process exit-code contract (see FEAT_KnowzCliFoundation). */
|
|
2
|
+
export const ExitCode = {
|
|
3
|
+
Success: 0,
|
|
4
|
+
Generic: 1,
|
|
5
|
+
Usage: 2,
|
|
6
|
+
Auth: 3,
|
|
7
|
+
Api: 4,
|
|
8
|
+
NotFound: 5,
|
|
9
|
+
};
|
|
10
|
+
/**
|
|
11
|
+
* A CLI error carrying the process exit code to use. The CLI's BaseCommand
|
|
12
|
+
* catch handler maps `exitCode` straight to `process.exitCode`; an unknown
|
|
13
|
+
* thrown Error maps to `ExitCode.Generic`.
|
|
14
|
+
*/
|
|
15
|
+
export class KnowzError extends Error {
|
|
16
|
+
exitCode;
|
|
17
|
+
constructor(message, exitCode = ExitCode.Generic, options) {
|
|
18
|
+
super(message);
|
|
19
|
+
this.name = 'KnowzError';
|
|
20
|
+
this.exitCode = exitCode;
|
|
21
|
+
if (options?.cause !== undefined)
|
|
22
|
+
this.cause = options.cause;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
export function isKnowzError(e) {
|
|
26
|
+
return e instanceof KnowzError;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Map any thrown value to a process exit code:
|
|
30
|
+
* - KnowzError → its declared exitCode
|
|
31
|
+
* - ApiError → 404 NotFound(5), 401/403 Auth(3), else Api(4)
|
|
32
|
+
* - anything else → Generic(1)
|
|
33
|
+
*/
|
|
34
|
+
export function exitCodeForError(e) {
|
|
35
|
+
if (isKnowzError(e))
|
|
36
|
+
return e.exitCode;
|
|
37
|
+
if (isApiError(e)) {
|
|
38
|
+
if (e.status === 404)
|
|
39
|
+
return ExitCode.NotFound;
|
|
40
|
+
if (e.status === 401 || e.status === 403)
|
|
41
|
+
return ExitCode.Auth;
|
|
42
|
+
return ExitCode.Api;
|
|
43
|
+
}
|
|
44
|
+
return ExitCode.Generic;
|
|
45
|
+
}
|
|
46
|
+
/** Structural check for ApiError without importing the class (avoids a type/runtime coupling). */
|
|
47
|
+
function isApiError(e) {
|
|
48
|
+
return (typeof e === 'object' &&
|
|
49
|
+
e !== null &&
|
|
50
|
+
e.name === 'ApiError' &&
|
|
51
|
+
typeof e.status === 'number');
|
|
52
|
+
}
|
|
53
|
+
//# sourceMappingURL=errors.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.js","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA,uEAAuE;AACvE,MAAM,CAAC,MAAM,QAAQ,GAAG;IACtB,OAAO,EAAE,CAAC;IACV,OAAO,EAAE,CAAC;IACV,KAAK,EAAE,CAAC;IACR,IAAI,EAAE,CAAC;IACP,GAAG,EAAE,CAAC;IACN,QAAQ,EAAE,CAAC;CACH,CAAC;AAIX;;;;GAIG;AACH,MAAM,OAAO,UAAW,SAAQ,KAAK;IAC1B,QAAQ,CAAgB;IAEjC,YAAY,OAAe,EAAE,WAA0B,QAAQ,CAAC,OAAO,EAAE,OAA6B;QACpG,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,YAAY,CAAC;QACzB,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAC;QACzB,IAAI,OAAO,EAAE,KAAK,KAAK,SAAS;YAAE,IAAI,CAAC,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC;IAC/D,CAAC;CACF;AAED,MAAM,UAAU,YAAY,CAAC,CAAU;IACrC,OAAO,CAAC,YAAY,UAAU,CAAC;AACjC,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,gBAAgB,CAAC,CAAU;IACzC,IAAI,YAAY,CAAC,CAAC,CAAC;QAAE,OAAO,CAAC,CAAC,QAAQ,CAAC;IACvC,IAAI,UAAU,CAAC,CAAC,CAAC,EAAE,CAAC;QAClB,IAAI,CAAC,CAAC,MAAM,KAAK,GAAG;YAAE,OAAO,QAAQ,CAAC,QAAQ,CAAC;QAC/C,IAAI,CAAC,CAAC,MAAM,KAAK,GAAG,IAAI,CAAC,CAAC,MAAM,KAAK,GAAG;YAAE,OAAO,QAAQ,CAAC,IAAI,CAAC;QAC/D,OAAO,QAAQ,CAAC,GAAG,CAAC;IACtB,CAAC;IACD,OAAO,QAAQ,CAAC,OAAO,CAAC;AAC1B,CAAC;AAED,kGAAkG;AAClG,SAAS,UAAU,CAAC,CAAU;IAC5B,OAAO,CACL,OAAO,CAAC,KAAK,QAAQ;QACrB,CAAC,KAAK,IAAI;QACT,CAAwB,CAAC,IAAI,KAAK,UAAU;QAC7C,OAAQ,CAA0B,CAAC,MAAM,KAAK,QAAQ,CACvD,CAAC;AACJ,CAAC"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,aAAa,CAAC;AAC5B,cAAc,aAAa,CAAC;AAC5B,cAAc,aAAa,CAAC;AAC5B,cAAc,uBAAuB,CAAC;AACtC,cAAc,eAAe,CAAC;AAC9B,cAAc,WAAW,CAAC;AAC1B,cAAc,eAAe,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,aAAa,CAAC;AAC5B,cAAc,aAAa,CAAC;AAC5B,cAAc,aAAa,CAAC;AAC5B,cAAc,uBAAuB,CAAC;AACtC,cAAc,eAAe,CAAC;AAC9B,cAAc,WAAW,CAAC;AAC1B,cAAc,eAAe,CAAC"}
|
package/dist/logger.d.ts
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Structured logger with a pluggable secret redactor seam.
|
|
3
|
+
*
|
|
4
|
+
* N1 ships a no-op redactor; N3 installs the real secret-redaction filter via
|
|
5
|
+
* `logger.setRedactor(...)` during CLI startup, BEFORE any auth command runs.
|
|
6
|
+
* Human/log output goes to stderr; machine output (`--json`) is written to
|
|
7
|
+
* stdout by commands directly (not through this logger).
|
|
8
|
+
*/
|
|
9
|
+
export type LogLevel = 'error' | 'warn' | 'info' | 'debug';
|
|
10
|
+
export type Redactor = (text: string) => string;
|
|
11
|
+
export declare class Logger {
|
|
12
|
+
level: LogLevel;
|
|
13
|
+
private redactor;
|
|
14
|
+
setRedactor(r: Redactor): void;
|
|
15
|
+
setLevel(level: LogLevel): void;
|
|
16
|
+
private write;
|
|
17
|
+
error(msg: string, meta?: unknown): void;
|
|
18
|
+
warn(msg: string, meta?: unknown): void;
|
|
19
|
+
info(msg: string, meta?: unknown): void;
|
|
20
|
+
debug(msg: string, meta?: unknown): void;
|
|
21
|
+
/** Redact an arbitrary string using the installed redactor (for error rendering). */
|
|
22
|
+
redact(text: string): string;
|
|
23
|
+
}
|
|
24
|
+
/** Process-wide logger singleton. */
|
|
25
|
+
export declare const logger: Logger;
|
|
26
|
+
//# sourceMappingURL=logger.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../src/logger.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,MAAM,MAAM,QAAQ,GAAG,OAAO,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC;AAC3D,MAAM,MAAM,QAAQ,GAAG,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,CAAC;AAUhD,qBAAa,MAAM;IACjB,KAAK,EAAE,QAAQ,CAAyB;IACxC,OAAO,CAAC,QAAQ,CAAsB;IAEtC,WAAW,CAAC,CAAC,EAAE,QAAQ,GAAG,IAAI;IAI9B,QAAQ,CAAC,KAAK,EAAE,QAAQ,GAAG,IAAI;IAI/B,OAAO,CAAC,KAAK;IAWb,KAAK,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,OAAO,GAAG,IAAI;IAGxC,IAAI,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,OAAO,GAAG,IAAI;IAGvC,IAAI,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,OAAO,GAAG,IAAI;IAGvC,KAAK,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,OAAO,GAAG,IAAI;IAIxC,qFAAqF;IACrF,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM;CAG7B;AAUD,qCAAqC;AACrC,eAAO,MAAM,MAAM,QAAe,CAAC"}
|