{"version":3,"file":"index.cjs","names":["authorization?: string","reason: string","a: string","b: string","credentials: string","authCredentials: AuthCredentials","input: BasicAuthResult","requiredCredentials: AuthCredentials","req: NextRequest","credentialsObject: AuthCredentials","NextResponse"],"sources":["../src/lib/auth.ts","../src/lib/compare.ts","../src/lib/credentials.ts","../src/middleware.ts"],"sourcesContent":["export type BasicAuthResult = {\n\tuser: string;\n\tpass: string;\n};\n\nexport function basicAuthentication(\n\tauthorization?: string,\n): BasicAuthResult | undefined {\n\tif (!authorization) {\n\t\treturn undefined;\n\t}\n\n\tconst [scheme, encoded] = authorization.split(\" \");\n\n\t// The Authorization header must start with Basic, followed by a space.\n\tif (!encoded || scheme !== \"Basic\") {\n\t\tthrow new BadRequestException(\"Malformed authorization header.\");\n\t}\n\n\t// Decodes the base64 value and performs unicode normalization.\n\t// @see https://datatracker.ietf.org/doc/html/rfc7613#section-3.3.2 (and #section-4.2.2)\n\t// @see https://dev.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String/normalize\n\tconst buffer = Uint8Array.from(atob(encoded), (character) =>\n\t\tcharacter.charCodeAt(0),\n\t);\n\tconst decoded = new TextDecoder().decode(buffer).normalize();\n\n\t// The username & password are split by the first colon.\n\t//=> example: \"username:password\"\n\tconst index = decoded.indexOf(\":\");\n\n\t// The user & password are split by the first colon and MUST NOT contain control characters.\n\t// @see https://tools.ietf.org/html/rfc5234#appendix-B.1 (=> \"CTL = %x00-1F / %x7F\")\n\t// biome-ignore lint/suspicious/noControlCharactersInRegex: intentional CTL character check per RFC 5234\n\tif (index === -1 || /[\\0-\\x1F\\x7F]/.test(decoded)) {\n\t\tthrow new BadRequestException(\"Invalid authorization value.\");\n\t}\n\n\treturn {\n\t\tuser: decoded.substring(0, index),\n\t\tpass: decoded.substring(index + 1),\n\t};\n}\n\nexport class BadRequestException extends Error {\n\tstatus: number;\n\tstatusText: string;\n\treason: string;\n\tconstructor(reason: string) {\n\t\tsuper(reason);\n\t\tthis.status = 400;\n\t\tthis.statusText = \"Bad Request\";\n\t\tthis.reason = reason;\n\t}\n}\n","/**\n * Constant time string comparison.\n * Typescript version of [Bruce17's safe-compare](https://github.com/Bruce17/safe-compare)\n * @returns Boolean that confirms whether the string is the same\n */\nexport const safeCompare = (a: string, b: string) => {\n\tconst stringA = String(a);\n\tconst lengthA = stringA.length;\n\tlet stringB = String(b);\n\tlet result = 0;\n\n\tif (lengthA !== stringB.length) {\n\t\tstringB = stringA;\n\t\tresult = 1;\n\t}\n\n\tfor (let i = 0; i < lengthA; i++) {\n\t\tresult |= stringA.charCodeAt(i) ^ stringB.charCodeAt(i);\n\t}\n\n\treturn result === 0;\n};\n","import type { BasicAuthResult } from \"./auth.ts\";\nimport { safeCompare } from \"./compare.ts\";\n\n// This contains all the logic for parsing and checking credentials\ntype AuthCredentialsObject = {\n\tname: string;\n\tpassword: string;\n};\n\nexport type AuthCredentials = AuthCredentialsObject[];\n\nexport const parseCredentials = (credentials: string): AuthCredentials => {\n\tconst authCredentials: AuthCredentials = [];\n\n\tcredentials.split(\"|\").forEach((item) => {\n\t\tconst index = item.indexOf(\":\");\n\t\tif (index < 1 || index === item.length - 1) {\n\t\t\tthrow new Error(\n\t\t\t\t`Received incorrect basic auth syntax, use <username>:<password>, received ${item}`,\n\t\t\t);\n\t\t}\n\n\t\tauthCredentials.push({\n\t\t\tname: item.substring(0, index),\n\t\t\tpassword: item.substring(index + 1),\n\t\t});\n\t});\n\n\treturn authCredentials;\n};\n\n/**\n * Compares the basic auth credentials with the configured user and password\n * @param credentials Basic Auth credentials object from `basic-auth`\n */\nexport const compareCredentials = (\n\tinput: BasicAuthResult,\n\trequiredCredentials: AuthCredentials,\n): boolean =>\n\trequiredCredentials.some((item) => {\n\t\tconst userMatch = safeCompare(input.user, item.name);\n\t\tconst passMatch = safeCompare(input.pass, item.password);\n\t\treturn userMatch && passMatch;\n\t});\n","import { type NextRequest, NextResponse } from \"next/server\";\nimport { basicAuthentication } from \"./lib/auth.ts\";\nimport {\n\ttype AuthCredentials,\n\tcompareCredentials,\n\tparseCredentials,\n} from \"./lib/credentials.ts\";\nimport type { MiddlewareOptions } from \"./types.js\";\n\n/**\n * Creates a default Next middleware function that returns `NextResponse.next()` if the basic auth passes\n * @param req Next middleware request\n * @param options Options object based on MiddlewareOptions\n * @returns Either a 401 error or goes to the next page\n */\nexport const createNextAuthMiddleware =\n\t({\n\t\tusers = [],\n\t\tmessage = \"Authentication failed\",\n\t\trealm = \"protected\",\n\t}: MiddlewareOptions = {}) =>\n\t(req: NextRequest) =>\n\t\tnextBasicAuthMiddleware({ users, message, realm }, req);\n\nexport const nextBasicAuthMiddleware = (\n\t{\n\t\tusers = [],\n\t\tmessage = \"Authentication failed\",\n\t\trealm = \"protected\",\n\t}: MiddlewareOptions = {},\n\treq: NextRequest,\n) => {\n\t// Check if credentials are set up\n\tconst environmentCredentials = process.env.BASIC_AUTH_CREDENTIALS || \"\";\n\tif (environmentCredentials.length === 0 && users.length === 0) {\n\t\t// No credentials set up, continue rendering the page as normal\n\t\treturn NextResponse.next();\n\t}\n\n\tconst credentialsObject: AuthCredentials =\n\t\tenvironmentCredentials.length > 0\n\t\t\t? parseCredentials(environmentCredentials)\n\t\t\t: users;\n\n\tconst authHeader = req.headers.get(\"authorization\");\n\n\tif (authHeader) {\n\t\ttry {\n\t\t\tconst currentUser = basicAuthentication(authHeader);\n\n\t\t\tif (currentUser && compareCredentials(currentUser, credentialsObject)) {\n\t\t\t\treturn NextResponse.next();\n\t\t\t}\n\t\t} catch {\n\t\t\t// Malformed authorization header — fall through to 401\n\t\t}\n\t}\n\n\treturn new NextResponse(message, {\n\t\tstatus: 401,\n\t\theaders: { \"WWW-Authenticate\": `Basic realm=\"${realm}\"` },\n\t});\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;AAKA,SAAgB,oBACfA,eAC8B;AAC9B,MAAK,cACJ;CAGD,MAAM,CAAC,QAAQ,QAAQ,GAAG,cAAc,MAAM,IAAI;AAGlD,MAAK,WAAW,WAAW,QAC1B,OAAM,IAAI,oBAAoB;CAM/B,MAAM,SAAS,WAAW,KAAK,KAAK,QAAQ,EAAE,CAAC,cAC9C,UAAU,WAAW,EAAE,CACvB;CACD,MAAM,UAAU,IAAI,cAAc,OAAO,OAAO,CAAC,WAAW;CAI5D,MAAM,QAAQ,QAAQ,QAAQ,IAAI;AAKlC,KAAI,UAAU,MAAM,gBAAgB,KAAK,QAAQ,CAChD,OAAM,IAAI,oBAAoB;AAG/B,QAAO;EACN,MAAM,QAAQ,UAAU,GAAG,MAAM;EACjC,MAAM,QAAQ,UAAU,QAAQ,EAAE;CAClC;AACD;AAED,IAAa,sBAAb,cAAyC,MAAM;CAC9C;CACA;CACA;CACA,YAAYC,QAAgB;AAC3B,QAAM,OAAO;AACb,OAAK,SAAS;AACd,OAAK,aAAa;AAClB,OAAK,SAAS;CACd;AACD;;;;;;;;;ACjDD,MAAa,cAAc,CAACC,GAAWC,MAAc;CACpD,MAAM,UAAU,OAAO,EAAE;CACzB,MAAM,UAAU,QAAQ;CACxB,IAAI,UAAU,OAAO,EAAE;CACvB,IAAI,SAAS;AAEb,KAAI,YAAY,QAAQ,QAAQ;AAC/B,YAAU;AACV,WAAS;CACT;AAED,MAAK,IAAI,IAAI,GAAG,IAAI,SAAS,IAC5B,WAAU,QAAQ,WAAW,EAAE,GAAG,QAAQ,WAAW,EAAE;AAGxD,QAAO,WAAW;AAClB;;;;ACVD,MAAa,mBAAmB,CAACC,gBAAyC;CACzE,MAAMC,kBAAmC,CAAE;AAE3C,aAAY,MAAM,IAAI,CAAC,QAAQ,CAAC,SAAS;EACxC,MAAM,QAAQ,KAAK,QAAQ,IAAI;AAC/B,MAAI,QAAQ,KAAK,UAAU,KAAK,SAAS,EACxC,OAAM,IAAI,OACR,4EAA4E,KAAK;AAIpF,kBAAgB,KAAK;GACpB,MAAM,KAAK,UAAU,GAAG,MAAM;GAC9B,UAAU,KAAK,UAAU,QAAQ,EAAE;EACnC,EAAC;CACF,EAAC;AAEF,QAAO;AACP;;;;;AAMD,MAAa,qBAAqB,CACjCC,OACAC,wBAEA,oBAAoB,KAAK,CAAC,SAAS;CAClC,MAAM,YAAY,YAAY,MAAM,MAAM,KAAK,KAAK;CACpD,MAAM,YAAY,YAAY,MAAM,MAAM,KAAK,SAAS;AACxD,QAAO,aAAa;AACpB,EAAC;;;;;;;;;;AC5BH,MAAa,2BACZ,CAAC,EACA,QAAQ,CAAE,GACV,UAAU,yBACV,QAAQ,aACW,GAAG,CAAE,MACzB,CAACC,QACA,wBAAwB;CAAE;CAAO;CAAS;AAAO,GAAE,IAAI;AAEzD,MAAa,0BAA0B,CACtC,EACC,QAAQ,CAAE,GACV,UAAU,yBACV,QAAQ,aACW,GAAG,CAAE,GACzBA,QACI;CAEJ,MAAM,yBAAyB,QAAQ,IAAI,0BAA0B;AACrE,KAAI,uBAAuB,WAAW,KAAK,MAAM,WAAW,EAE3D,QAAO,yBAAa,MAAM;CAG3B,MAAMC,oBACL,uBAAuB,SAAS,IAC7B,iBAAiB,uBAAuB,GACxC;CAEJ,MAAM,aAAa,IAAI,QAAQ,IAAI,gBAAgB;AAEnD,KAAI,WACH,KAAI;EACH,MAAM,cAAc,oBAAoB,WAAW;AAEnD,MAAI,eAAe,mBAAmB,aAAa,kBAAkB,CACpE,QAAO,yBAAa,MAAM;CAE3B,QAAO,CAEP;AAGF,QAAO,IAAIC,yBAAa,SAAS;EAChC,QAAQ;EACR,SAAS,EAAE,qBAAqB,eAAe,MAAM,GAAI;CACzD;AACD"}