Reader:
- PAYLOAD_AGE reaches age in pieces of one STREAM chunk, read only when
asked (agefile.chunked): a whole payload was decrypted ahead of step
17, with more memory, and a later STREAM failure hid the failure of
the reader that Go reports. The text still differs from Go when the
capsule is cut right after a full chunk: age-encryption holds that
chunk until it sees one more byte.
- The unusable head extensions are found before the commit, so the
sink is never aborted after it; a registry whose validateData throws
rejects the data; getWriter of a created file is inside the failure
of the sink; the sink gets copies, which it may keep or transfer.
Writer:
- Each piece of a file is copied as it is read: a source that reuses
its buffer could make the head record a SHA-256 that is not that of
the bytes encrypted, and the capsule would not open.
- A FileSource written as a class works: open is called on its object,
and each property is read once. Extensions of the wrong types are a
TypeError. In memory, the limit is checked before reading anything.
A chunk that is not a Uint8Array, and a lone surrogate in a path, are
named.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
// In memory, the limit is known before reading anything.
if(opts.output===undefined){
consttotal=capsuleLength({
profileId: s.dateKey.profileId,
round: s.dateKey.round,
policy: s.policy,
length,
padding: s.code,
critical: s.critical,
noncritical: s.noncritical,
controlCritical: s.controlCritical,
controlNoncritical: s.controlNoncritical,
});
if(total>MAX_MEMORY_DKC)thrownewTypeError(`encrypt: a capsule of ${total} bytes needs EncryptOptions.output; in memory the limit is ${MAX_MEMORY_DKC}`);
}
// Step 3: the first reading, for the SHA-256 of each file.
constsums: Uint8Array[]=[];
@ -246,10 +261,13 @@ function copySources(files: readonly FileSource[]): FileSource[] {
if(!Array.isArray(files))thrownewTypeError('encrypt: the files are an array of FileSource');
returnfiles.map((f: FileSource,i)=>{
if(typeoff!=='object'||f===null)thrownewTypeError(`encrypt: file ${i} is not a FileSource`);
if(typeoff.path!=='string')thrownewTypeError(`encrypt: file ${i}: path is not a string`);
if(!Number.isSafeInteger(f.size))thrownewTypeError(`encrypt: file ${i}: size is not a safe integer`);
if(f.mtime!==undefined&&!Number.isFinite(f.mtime))thrownewTypeError(`encrypt: file ${i}: mtime is not a finite number of milliseconds`);