registry.json holds each server's bearer token (the connection secret). It was written with the process default umask, leaving it group/world-readable on POSIX multi-user hosts. Write with mode 0o600 and chmod the existing file (writeFile only applies mode on creation). No-op on Windows (NTFS uses ACLs, and the file already sits under the user profile and is gitignored), effective on Linux/macOS where the gateway may run. Gateway-only change — not part of the app installer or auto-updater, so no version bump. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
52 lines
1.5 KiB
JavaScript
52 lines
1.5 KiB
JavaScript
import { readFile, writeFile, chmod } from 'node:fs/promises';
|
|
import { fileURLToPath } from 'node:url';
|
|
import { dirname, join } from 'node:path';
|
|
|
|
const HERE = dirname(fileURLToPath(import.meta.url));
|
|
const REGISTRY_PATH = join(HERE, 'registry.json');
|
|
|
|
export async function loadRegistry() {
|
|
try {
|
|
const raw = await readFile(REGISTRY_PATH, 'utf8');
|
|
const parsed = JSON.parse(raw);
|
|
if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) {
|
|
return {};
|
|
}
|
|
return parsed;
|
|
} catch {
|
|
return {};
|
|
}
|
|
}
|
|
|
|
export async function saveRegistry(registry) {
|
|
const data = registry && typeof registry === 'object' ? registry : {};
|
|
await writeFile(REGISTRY_PATH, JSON.stringify(data, null, 2) + '\n', { encoding: 'utf8', mode: 0o600 });
|
|
try { await chmod(REGISTRY_PATH, 0o600); } catch {}
|
|
}
|
|
|
|
export async function upsertEntry(entry) {
|
|
if (!entry || typeof entry.label !== 'string' || entry.label.length === 0) {
|
|
throw new Error('upsertEntry: entry.label is required');
|
|
}
|
|
const registry = await loadRegistry();
|
|
registry[entry.label] = {
|
|
host: entry.host,
|
|
port: entry.port,
|
|
token: entry.token,
|
|
fp: entry.fp,
|
|
label: entry.label,
|
|
version: entry.version,
|
|
lastConnectedAt: entry.lastConnectedAt ?? new Date().toISOString(),
|
|
};
|
|
await saveRegistry(registry);
|
|
return registry[entry.label];
|
|
}
|
|
|
|
export async function getEntry(label) {
|
|
if (typeof label !== 'string' || label.length === 0) return null;
|
|
const registry = await loadRegistry();
|
|
return registry[label] ?? null;
|
|
}
|
|
|
|
export { REGISTRY_PATH };
|