{"record":{"id":"44e1d9c75bfa3dfb","repo":"Hmbown/CodeWhale","slug":"invalid-base64","errorCode":"invalid-base64","errorMessage":"invalid-base64","messagePattern":"invalid-base64","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"web/lib/cloud-facts.ts","lineNumber":95,"sourceCode":"  fetchImpl?: typeof fetch;\n  keys?: readonly TrustedKey[];\n  timeoutMs?: number;\n  now?: () => number;\n}\n\nexport function isValidChannel(slug: string): boolean {\n  return CHANNEL_RE.test(slug);\n}\n\nfunction isObject(value: unknown): value is Record<string, unknown> {\n  return value !== null && typeof value === \"object\" && !Array.isArray(value);\n}\n\n/** Reject noncanonical/oversized encodings before either decoder allocates. */\nfunction b64ToBytes(value: unknown, maxBytes: number): Uint8Array {\n  if (typeof value !== \"string\" || !value.length || value.length > 4 * Math.ceil(maxBytes / 3) ||\n      (value.length % 4 !== 0 || !/^[A-Za-z0-9+/]*={0,2}$/.test(value))) {\n    throw new Error(\"invalid-base64\");\n  }\n  const bin = atob(value);\n  if (bin.length > maxBytes || btoa(bin) !== value) throw new Error(\"invalid-base64\");\n  return Uint8Array.from(bin, (char) => char.charCodeAt(0));\n}\n\nexport async function sha256Hex(bytes: Uint8Array): Promise<string> {\n  const digest = await crypto.subtle.digest(\"SHA-256\", bytes as BufferSource);\n  return [...new Uint8Array(digest)].map((b) => b.toString(16).padStart(2, \"0\")).join(\"\");\n}\n\nexport function signingMessage(keyId: string, payload: Uint8Array): Uint8Array {\n  const prefix = new TextEncoder().encode(`${DOMAIN}${keyId}\\0`);\n  const out = new Uint8Array(prefix.length + payload.length);\n  out.set(prefix);\n  out.set(payload, prefix.length);\n  return out;\n}","sourceCodeStart":77,"sourceCodeEnd":113,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/433685b2024e7bc4c99e1e2e326bcad39b4d9d65/web/lib/cloud-facts.ts#L77-L113","documentation":"b64ToBytes validates base64 input before decoding: the value must be a non-empty string, fit the maxBytes budget, have length divisible by 4, match the standard base64 alphabet with at most two padding '='s. It throws \"invalid-base64\" if any structural check fails, before atob allocates.","triggerScenarios":"Passing a non-string, empty string, URL-safe base64 (using - and _), base64 without padding, whitespace/newlines inside the value, or a string longer than 4*ceil(maxBytes/3) to any consumer of b64ToBytes (hasActiveKeys, validSignature, verifyEnvelope, publicKey).","commonSituations":"Generating tokens with base64url (JWT-style) encoders; hand-trimming or concatenating base64 chunks; copying values with trailing whitespace or quotes; oversized values from upstream.","solutions":["Re-encode the value with standard base64 (btoa/Buffer.toString('base64')), which pads to a multiple of 4.","Convert URL-safe base64 to standard: replace '-' with '+' and '_' with '/', then pad with '=' to a multiple of 4.","Trim surrounding whitespace and ensure no internal line breaks before passing the value.","Check the decoded byte size is within maxBytes for the field (keys, signatures, envelopes have separate caps)."],"exampleFix":"// before\nconst token = btoaUrlSafe(raw).replace(/=+$/, \"\");\n// after\nconst token = btoa(raw); // standard alphabet, padded, length % 4 === 0","handlingStrategy":"validation","validationCode":"function isStandardBase64(v: unknown, maxLen: number): boolean {\n  return typeof v === \"string\" && v.length > 0 && v.length <= maxLen &&\n    v.length % 4 === 0 && /^[A-Za-z0-9+/]*={0,2}$/.test(v);\n}","typeGuard":"function isBase64String(v: unknown): v is string {\n  return typeof v === \"string\" && v.length > 0 && v.length % 4 === 0 && /^[A-Za-z0-9+/]*={0,2}$/.test(v);\n}","tryCatchPattern":"try {\n  const bytes = b64ToBytes(value, maxBytes);\n} catch (err) {\n  if (err.message === \"invalid-base64\") {\n    // Re-encode or reject the input; do not retry the same value.\n    value = btoa(String(value).replace(/-/g, \"+\").replace(/_/g, \"/\").replace(/=+$/, \"\"));\n  }\n}","preventionTips":["Always use standard (padded) base64 encoders, not base64url, for values sent to this library.","Strip whitespace/newlines from base64 strings before transmitting or storing them.","Prefer btoa/Buffer.toString('base64') over hand-built encoders so padding is correct."],"tags":["base64","validation","encoding"],"backgroundTag":"invalid-base64-encoding","analyzedSha":"433685b2024e7bc4c99e1e2e326bcad39b4d9d65","analyzedAt":"2026-09-15T12:24:24.634Z","contentChangedAt":"2026-09-15T12:24:24.634Z","schemaVersion":2},"datasetVersion":"2026-09-22T16:17:23.217Z"}