{"version":3,"file":"legacy.mjs","names":[],"sources":["../../../../../../encryption/src/legacy.ts"],"sourcesContent":["import CryptoJS from \"crypto-js\";\nimport AES from \"crypto-js/aes\";\nimport { DecryptionError } from \"./errors\";\nimport { type LegacyCipherDriver } from \"./types\";\n\n/**\n * Base64 prefix of every ciphertext produced by @mongez/encryption v1.x.\n *\n * v1 always called crypto-js in passphrase mode, which emits\n * `\"Salted__\" + 8-byte salt + AES-CBC ciphertext`; the ASCII `Salted__` header\n * base64-encodes to this fixed 10-character prefix. A version-1 AES-GCM\n * envelope starts with byte 0x01 instead, so the two formats can never be\n * confused for one another.\n */\nexport const LEGACY_CIPHER_PREFIX = \"U2FsdGVkX1\";\n\n/**\n * Whether the given string is a v1.x (AES-CBC, MD5-KDF) ciphertext.\n *\n * Exposed so consumers can walk a store and re-encrypt legacy values, which is\n * the only way to get integrity protection over data written by v1.x.\n */\nexport function isLegacyCipher(cipher: string): boolean {\n  return typeof cipher === \"string\" && cipher.startsWith(LEGACY_CIPHER_PREFIX);\n}\n\n/**\n * Whether the given value can act as a crypto-js style cipher driver.\n *\n * Used both to accept a legacy driver in `decrypt`'s third positional slot and\n * to reject one in `encrypt`'s, where v1.x callers used to pass `AES`.\n */\nexport function isLegacyDriver(value: any): value is LegacyCipherDriver {\n  return (\n    !!value &&\n    typeof value === \"object\" &&\n    typeof value.encrypt === \"function\" &&\n    typeof value.decrypt === \"function\"\n  );\n}\n\n/**\n * Decrypt a v1.x ciphertext. **Decrypt only** — nothing in this package writes\n * this format any more.\n *\n * The value returned here is NOT authenticated: v1.x used AES-CBC with no MAC,\n * so a v1.x ciphertext an attacker can write to may have been tampered with\n * undetectably. That is exactly why this path is opt-in.\n */\nexport function legacyDecrypt(\n  cipher: string,\n  key: string,\n  driver: LegacyCipherDriver = AES\n): any {\n  let plainText: string;\n\n  try {\n    plainText = driver.decrypt(cipher, key).toString(CryptoJS.enc.Utf8);\n  } catch {\n    throw new DecryptionError(\n      \"Unable to decrypt the given legacy (v1.x) ciphertext: wrong key, wrong driver, or corrupt data.\"\n    );\n  }\n\n  if (!plainText) {\n    throw new DecryptionError(\n      \"Unable to decrypt the given legacy (v1.x) ciphertext: wrong key, wrong driver, or corrupt data.\"\n    );\n  }\n\n  try {\n    return JSON.parse(plainText).data;\n  } catch {\n    throw new DecryptionError(\n      \"Legacy (v1.x) ciphertext decrypted to something that is not a @mongez/encryption payload.\"\n    );\n  }\n}\n"],"mappings":";;;;;;;;;;;;;;AAcA,MAAa,uBAAuB;;;;;;;AAQpC,SAAgB,eAAe,QAAyB;CACtD,OAAO,OAAO,WAAW,YAAY,OAAO,uBAA+B;AAC7E;;;;;;;AAQA,SAAgB,eAAe,OAAyC;CACtE,OACE,CAAC,CAAC,SACF,OAAO,UAAU,YACjB,OAAO,MAAM,YAAY,cACzB,OAAO,MAAM,YAAY;AAE7B;;;;;;;;;AAUA,SAAgB,cACd,QACA,KACA,SAA6B,KACxB;CACL,IAAI;CAEJ,IAAI;EACF,YAAY,OAAO,QAAQ,QAAQ,GAAG,CAAC,CAAC,SAAS,SAAS,IAAI,IAAI;CACpE,QAAQ;EACN,MAAM,IAAI,gBACR,iGACF;CACF;CAEA,IAAI,CAAC,WACH,MAAM,IAAI,gBACR,iGACF;CAGF,IAAI;EACF,OAAO,KAAK,MAAM,SAAS,CAAC,CAAC;CAC/B,QAAQ;EACN,MAAM,IAAI,gBACR,2FACF;CACF;AACF"}