mirror of
https://github.com/affaan-m/ECC.git
synced 2026-10-14 12:15:29 +02:00
Carry forward PR #3055 at92f53c4contoef648e01, preserving contributor attribution and current main. Focused maintainer fixes reuse shared input ceilings, preserve late root context through outer bootstrap, bound frontmatter before immutable parsing, and assert real oversized input in the limits workflow.
71 lines
2.1 KiB
JavaScript
71 lines
2.1 KiB
JavaScript
'use strict';
|
|
|
|
const { StringDecoder } = require('string_decoder');
|
|
|
|
const DEFAULT_MAX_STDIN = 1024 * 1024;
|
|
|
|
function resolveMaxStdin(value, options = {}) {
|
|
const writeDiagnostic = options.writeDiagnostic || (() => {});
|
|
if (value === undefined || value === '') return DEFAULT_MAX_STDIN;
|
|
|
|
const parsed = Number(value);
|
|
if (!Number.isSafeInteger(parsed) || parsed <= 0) {
|
|
writeDiagnostic(
|
|
'[Hook] ECC_HOOK_INPUT_MAX_BYTES must be a positive safe integer; using the 1 MiB default\n'
|
|
);
|
|
return DEFAULT_MAX_STDIN;
|
|
}
|
|
if (parsed > DEFAULT_MAX_STDIN) {
|
|
writeDiagnostic(
|
|
'[Hook] ECC_HOOK_INPUT_MAX_BYTES exceeds the 1 MiB safety maximum; clamping to 1 MiB\n'
|
|
);
|
|
return DEFAULT_MAX_STDIN;
|
|
}
|
|
return parsed;
|
|
}
|
|
|
|
function readStdinRaw(stream = process.stdin, options = {}) {
|
|
const maxStdin = options.maxStdin || DEFAULT_MAX_STDIN;
|
|
const decoder = new StringDecoder('utf8');
|
|
let raw = '';
|
|
let acceptedBytes = 0;
|
|
let truncated = options.truncated === true;
|
|
|
|
return new Promise(resolve => {
|
|
let settled = false;
|
|
stream.on('data', chunk => {
|
|
const buffer = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk);
|
|
if (typeof options.onChunk === 'function') options.onChunk(buffer);
|
|
const remaining = Math.max(0, maxStdin - acceptedBytes);
|
|
const accepted = buffer.subarray(0, remaining);
|
|
if (accepted.length > 0) {
|
|
raw += decoder.write(accepted);
|
|
acceptedBytes += accepted.length;
|
|
}
|
|
if (accepted.length < buffer.length) truncated = true;
|
|
});
|
|
const finish = () => {
|
|
if (settled) return;
|
|
settled = true;
|
|
if (!truncated) raw += decoder.end();
|
|
resolve({ raw, truncated });
|
|
};
|
|
const finishIncomplete = () => {
|
|
if (settled) return;
|
|
truncated = true;
|
|
finish();
|
|
};
|
|
stream.once('end', finish);
|
|
// A transport error or premature close can leave a syntactically plausible
|
|
// prefix behind. Mark it incomplete so safety hooks remain fail closed.
|
|
stream.once('error', finishIncomplete);
|
|
stream.once('close', finishIncomplete);
|
|
});
|
|
}
|
|
|
|
module.exports = {
|
|
DEFAULT_MAX_STDIN,
|
|
readStdinRaw,
|
|
resolveMaxStdin
|
|
};
|