From c5cfea07420299359c793d883d20176eda280b00 Mon Sep 17 00:00:00 2001 From: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Date: Thu, 12 Dec 2024 10:06:35 +0000 Subject: [PATCH] fix: decode QP-encoded selectors before searching Co-Authored-By: shryas.londhe@gmail.com --- packages/helpers/src/sha-utils.ts | 62 ++++++++++++++++++++++++++++--- 1 file changed, 57 insertions(+), 5 deletions(-) diff --git a/packages/helpers/src/sha-utils.ts b/packages/helpers/src/sha-utils.ts index 941585ea..1baf3082 100644 --- a/packages/helpers/src/sha-utils.ts +++ b/packages/helpers/src/sha-utils.ts @@ -50,15 +50,67 @@ export function generatePartialSHA({ if (selectorString) { // Convert to Buffer for consistent handling const bodyBuffer = Buffer.from(body); - const bodyStr = bodyBuffer.toString(); + const result: number[] = []; + const positionMap = new Map(); // decoded -> original + let i = 0; + let decodedPos = 0; + + // Helper function to decode QP string + const decodeQP = (str: string): string => { + return str.replace(/=([0-9A-F]{2})/g, (_, hex) => + String.fromCharCode(parseInt(hex, 16)) + ); + }; + + // First decode the selector if it's QP-encoded + const decodedSelector = decodeQP(selectorString); + + 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); + positionMap.set(decodedPos, i); + decodedPos++; + i += 3; + continue; + } + } - // Find the selector in the body - const selectorIndex = bodyStr.indexOf(selectorString); + result.push(bodyBuffer[i]); + positionMap.set(decodedPos, i); + decodedPos++; + 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(decodedSelector); if (selectorIndex === -1) { - throw new Error(`SHA precompute selector "${selectorString}" not found in body`); + throw new Error(`SHA precompute selector "${decodedSelector}" not found in body`); + } + + // Map back to original position + const originalIndex = positionMap.get(selectorIndex); + if (originalIndex === undefined) { + throw new Error('Failed to map selector position back to original content'); } - shaCutoffIndex = selectorIndex; + shaCutoffIndex = originalIndex; } if (shaCutoffIndex < 0) {