better-auth
Version:
The most comprehensive authentication framework for TypeScript.
1 lines • 4.18 kB
Source Map (JSON)
{"version":3,"file":"index.mjs","names":[],"sources":["../../../src/plugins/haveibeenpwned/index.ts"],"sourcesContent":["import type { BetterAuthPlugin } from \"@better-auth/core\";\nimport { getCurrentAuthContext } from \"@better-auth/core/context\";\nimport { defineErrorCodes } from \"@better-auth/core/utils\";\nimport { createHash } from \"@better-auth/utils/hash\";\nimport { betterFetch } from \"@better-fetch/fetch\";\nimport { APIError } from \"../../api\";\n\nconst ERROR_CODES = defineErrorCodes({\n\tPASSWORD_COMPROMISED:\n\t\t\"The password you entered has been compromised. Please choose a different password.\",\n});\n\nasync function checkPasswordCompromise(\n\tpassword: string,\n\tcustomMessage?: string | undefined,\n) {\n\tif (!password) return;\n\n\tconst sha1Hash = (\n\t\tawait createHash(\"SHA-1\", \"hex\").digest(password)\n\t).toUpperCase();\n\tconst prefix = sha1Hash.substring(0, 5);\n\tconst suffix = sha1Hash.substring(5);\n\ttry {\n\t\tconst { data, error } = await betterFetch<string>(\n\t\t\t`https://api.pwnedpasswords.com/range/${prefix}`,\n\t\t\t{\n\t\t\t\theaders: {\n\t\t\t\t\t\"Add-Padding\": \"true\",\n\t\t\t\t\t\"User-Agent\": \"BetterAuth Password Checker\",\n\t\t\t\t},\n\t\t\t},\n\t\t);\n\n\t\tif (error) {\n\t\t\tthrow new APIError(\"INTERNAL_SERVER_ERROR\", {\n\t\t\t\tmessage: `Failed to check password. Status: ${error.status}`,\n\t\t\t});\n\t\t}\n\t\tconst lines = data.split(\"\\n\");\n\t\tconst found = lines.some(\n\t\t\t(line) => line.split(\":\")[0]!.toUpperCase() === suffix.toUpperCase(),\n\t\t);\n\n\t\tif (found) {\n\t\t\tthrow new APIError(\"BAD_REQUEST\", {\n\t\t\t\tmessage: customMessage || ERROR_CODES.PASSWORD_COMPROMISED,\n\t\t\t\tcode: \"PASSWORD_COMPROMISED\",\n\t\t\t});\n\t\t}\n\t} catch (error) {\n\t\tif (error instanceof APIError) throw error;\n\t\tthrow new APIError(\"INTERNAL_SERVER_ERROR\", {\n\t\t\tmessage: \"Failed to check password. Please try again later.\",\n\t\t});\n\t}\n}\n\nexport interface HaveIBeenPwnedOptions {\n\tcustomPasswordCompromisedMessage?: string | undefined;\n\t/**\n\t * Paths to check for password\n\t *\n\t * @default [\"/sign-up/email\", \"/change-password\", \"/reset-password\"]\n\t */\n\tpaths?: string[];\n}\n\nexport const haveIBeenPwned = (options?: HaveIBeenPwnedOptions | undefined) => {\n\tconst paths = options?.paths || [\n\t\t\"/sign-up/email\",\n\t\t\"/change-password\",\n\t\t\"/reset-password\",\n\t];\n\n\treturn {\n\t\tid: \"haveIBeenPwned\",\n\t\tinit(ctx) {\n\t\t\treturn {\n\t\t\t\tcontext: {\n\t\t\t\t\tpassword: {\n\t\t\t\t\t\t...ctx.password,\n\t\t\t\t\t\tasync hash(password) {\n\t\t\t\t\t\t\tconst c = await getCurrentAuthContext();\n\t\t\t\t\t\t\tif (!c.path || !paths.includes(c.path)) {\n\t\t\t\t\t\t\t\treturn ctx.password.hash(password);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tawait checkPasswordCompromise(\n\t\t\t\t\t\t\t\tpassword,\n\t\t\t\t\t\t\t\toptions?.customPasswordCompromisedMessage,\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\treturn ctx.password.hash(password);\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t};\n\t\t},\n\t\toptions,\n\t\t$ERROR_CODES: ERROR_CODES,\n\t} satisfies BetterAuthPlugin;\n};\n"],"mappings":";;;;;;;AAOA,MAAM,cAAc,iBAAiB,EACpC,sBACC,sFACD,CAAC;AAEF,eAAe,wBACd,UACA,eACC;AACD,KAAI,CAAC,SAAU;CAEf,MAAM,YACL,MAAM,WAAW,SAAS,MAAM,CAAC,OAAO,SAAS,EAChD,aAAa;CACf,MAAM,SAAS,SAAS,UAAU,GAAG,EAAE;CACvC,MAAM,SAAS,SAAS,UAAU,EAAE;AACpC,KAAI;EACH,MAAM,EAAE,MAAM,UAAU,MAAM,YAC7B,wCAAwC,UACxC,EACC,SAAS;GACR,eAAe;GACf,cAAc;GACd,EACD,CACD;AAED,MAAI,MACH,OAAM,IAAI,SAAS,yBAAyB,EAC3C,SAAS,qCAAqC,MAAM,UACpD,CAAC;AAOH,MALc,KAAK,MAAM,KAAK,CACV,MAClB,SAAS,KAAK,MAAM,IAAI,CAAC,GAAI,aAAa,KAAK,OAAO,aAAa,CACpE,CAGA,OAAM,IAAI,SAAS,eAAe;GACjC,SAAS,iBAAiB,YAAY;GACtC,MAAM;GACN,CAAC;UAEK,OAAO;AACf,MAAI,iBAAiB,SAAU,OAAM;AACrC,QAAM,IAAI,SAAS,yBAAyB,EAC3C,SAAS,qDACT,CAAC;;;AAcJ,MAAa,kBAAkB,YAAgD;CAC9E,MAAM,QAAQ,SAAS,SAAS;EAC/B;EACA;EACA;EACA;AAED,QAAO;EACN,IAAI;EACJ,KAAK,KAAK;AACT,UAAO,EACN,SAAS,EACR,UAAU;IACT,GAAG,IAAI;IACP,MAAM,KAAK,UAAU;KACpB,MAAM,IAAI,MAAM,uBAAuB;AACvC,SAAI,CAAC,EAAE,QAAQ,CAAC,MAAM,SAAS,EAAE,KAAK,CACrC,QAAO,IAAI,SAAS,KAAK,SAAS;AAEnC,WAAM,wBACL,UACA,SAAS,iCACT;AACD,YAAO,IAAI,SAAS,KAAK,SAAS;;IAEnC,EACD,EACD;;EAEF;EACA,cAAc;EACd"}