diff --git a/src/lib/utils/base64.ts b/src/lib/utils/base64.ts new file mode 100644 index 000000000..a93d1f8ba --- /dev/null +++ b/src/lib/utils/base64.ts @@ -0,0 +1,43 @@ +/** + * Decode Base64 encoded UTF-8 string + * + * This function handles various Base64 edge cases that can occur when + * Base64 strings are passed through URLs: + * - Spaces (URL parsing may convert '+' to space) + * - Missing padding ('=' characters) + * - Different Base64 variants + * + * @param str - Base64 encoded string + * @returns Decoded UTF-8 string + */ +export function decodeBase64Utf8(str: string): string { + try { + // Clean up the input: replace spaces with + (URL parsing may convert + to space) + let cleaned = str.trim().replace(/ /g, "+"); + + // Try to decode with standard Base64 first + try { + const binString = atob(cleaned); + const bytes = Uint8Array.from(binString, (m) => m.codePointAt(0)!); + return new TextDecoder("utf-8", { fatal: false }).decode(bytes); + } catch (e1) { + // If standard fails, try adding padding + const remainder = cleaned.length % 4; + if (remainder !== 0) { + cleaned += "=".repeat(4 - remainder); + } + const binString = atob(cleaned); + const bytes = Uint8Array.from(binString, (m) => m.codePointAt(0)!); + return new TextDecoder("utf-8", { fatal: false }).decode(bytes); + } + } catch (e) { + console.error("Base64 decode error:", e, "Input:", str); + // Last resort fallback using deprecated but sometimes working method + try { + return decodeURIComponent(escape(atob(str.replace(/ /g, "+")))); + } catch { + // If all else fails, return original string + return str; + } + } +}