Added the guarded, one-shot monero:pilot-address command
This commit is contained in:
+33
@@ -0,0 +1,33 @@
|
||||
import { constants } from 'node:fs';
|
||||
import { open } from 'node:fs/promises';
|
||||
import { isAbsolute } from 'node:path';
|
||||
|
||||
const MAX_REQUEST_BYTES = 64 * 1024;
|
||||
|
||||
/** Read a signed wallet request only from a bounded owner-only regular file. */
|
||||
export async function loadPilotMoneroDepositRequestFile(path: string): Promise<unknown> {
|
||||
if (process.platform === 'win32') throw new Error('Pilot address command requires POSIX protected-file permission checks');
|
||||
if (!isAbsolute(path)) throw new Error('Pilot address request file path must be absolute');
|
||||
let file;
|
||||
try { file = await open(path, constants.O_RDONLY | constants.O_NOFOLLOW); }
|
||||
catch { throw new Error('Pilot address request file is inaccessible or is a symbolic link'); }
|
||||
try {
|
||||
const info = await file.stat();
|
||||
if (!info.isFile() || info.size < 1 || info.size > MAX_REQUEST_BYTES || (info.mode & 0o077) !== 0) {
|
||||
throw new Error('Pilot address request file must be bounded and owner-only');
|
||||
}
|
||||
const chunks: Buffer[] = [];
|
||||
let total = 0;
|
||||
for (;;) {
|
||||
const chunk = Buffer.allocUnsafe(Math.min(4096, MAX_REQUEST_BYTES + 1 - total));
|
||||
const { bytesRead } = await file.read(chunk);
|
||||
if (bytesRead === 0) break;
|
||||
total += bytesRead;
|
||||
if (total > MAX_REQUEST_BYTES) throw new Error('Pilot address request file exceeds size limit');
|
||||
chunks.push(chunk.subarray(0, bytesRead));
|
||||
}
|
||||
const text = new TextDecoder('utf-8', { fatal: true }).decode(Buffer.concat(chunks));
|
||||
try { return JSON.parse(text) as unknown; }
|
||||
catch { throw new Error('Pilot address request file does not contain valid JSON'); }
|
||||
} finally { await file.close(); }
|
||||
}
|
||||
Reference in New Issue
Block a user