Skip to content

Commit

Permalink
fix: improve QP decoding in generatePartialSHA to handle soft line br…
Browse files Browse the repository at this point in the history
…eaks

Co-Authored-By: [email protected] <[email protected]>
  • Loading branch information
1 parent 8785d2f commit 921d58d
Showing 1 changed file with 70 additions and 5 deletions.
75 changes: 70 additions & 5 deletions packages/helpers/src/sha-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,73 @@ export function generatePartialSHA({
throw new Error('Invalid input: body must be a Uint8Array');
}

const precomputeText = selectorString ? Buffer.from(selectorString) : body;
const shaCutoffIndex = selectorString ? body.indexOf(precomputeText[0]) : bodyLength;
let shaCutoffIndex = bodyLength;

if (selectorString) {
// First remove soft line breaks and decode QP content
const bodyBuffer = Buffer.from(body);
const result: number[] = [];
let i = 0;

while (i < bodyBuffer.length) {
// Skip soft line breaks
if (i < bodyBuffer.length - 2 &&
bodyBuffer[i] === 61 && // '='
bodyBuffer[i + 1] === 13 && // '\r'
bodyBuffer[i + 2] === 10) { // '\n'
i += 3;
continue;
}

// Handle QP sequences
if (i < bodyBuffer.length - 2 && bodyBuffer[i] === 61) { // '='
const nextTwo = bodyBuffer.slice(i + 1, i + 3).toString();
if (/[0-9A-F]{2}/.test(nextTwo)) {
const byte = parseInt(nextTwo, 16);
result.push(byte);
i += 3;
continue;
}
}

result.push(bodyBuffer[i]);
i++;
}

// Convert decoded content to string for searching
const decoder = new TextDecoder();
const decodedStr = decoder.decode(new Uint8Array(result));

// Find the selector in decoded content
const selectorIndex = decodedStr.indexOf(selectorString);
if (selectorIndex === -1) {
throw new Error(`SHA precompute selector "${selectorString}" not found in body`);
}

// Map back to original index
let originalIndex = 0;
let decodedIndex = 0;
while (decodedIndex < selectorIndex) {
if (bodyBuffer[originalIndex] === 61 && // '='
bodyBuffer[originalIndex + 1] === 13 && // '\r'
bodyBuffer[originalIndex + 2] === 10) { // '\n'
originalIndex += 3;
} else if (bodyBuffer[originalIndex] === 61) { // '='
const nextTwo = bodyBuffer.slice(originalIndex + 1, originalIndex + 3).toString();
if (/[0-9A-F]{2}/.test(nextTwo)) {
originalIndex += 3;
decodedIndex++;
} else {
originalIndex++;
decodedIndex++;
}
} else {
originalIndex++;
decodedIndex++;
}
}
shaCutoffIndex = originalIndex;
}

if (shaCutoffIndex < 0) {
throw new Error('Negative sha cutoff index');
Expand All @@ -60,20 +125,20 @@ export function generatePartialSHA({

const buffer = new ArrayBuffer(maxRemainingBodyLength);
const bodyRemaining = new Uint8Array(buffer);
const slicedBody = new Uint8Array(body.buffer, shaCutoffIndex);
const slicedBody = new Uint8Array(body.slice(shaCutoffIndex));
bodyRemaining.set(slicedBody);

if (bodyRemaining.length < maxRemainingBodyLength) {
return {
bodyRemaining: padUint8ArrayWithZeros(bodyRemaining, maxRemainingBodyLength),
precomputedSha: partialSha(precomputeText, shaCutoffIndex),
precomputedSha: partialSha(body.slice(0, shaCutoffIndex), shaCutoffIndex),
bodyRemainingLength: bodyRemaining.length
};
}

return {
bodyRemaining,
precomputedSha: partialSha(precomputeText, shaCutoffIndex),
precomputedSha: partialSha(body.slice(0, shaCutoffIndex), shaCutoffIndex),
bodyRemainingLength: bodyRemaining.length
};
}
Expand Down

0 comments on commit 921d58d

Please sign in to comment.