Files
SnowLuma/.pnpm-store/v11/files/b4/87ed3da907ef43455a3e98353a0bef3ea4fb8ac5797eae44eafb1d734868f142e687da9045e44d3882ee4c4983f6c182adaa2ddd8ed9f2d2e81c63994e1283
T
TanTan 2a69b23b47
Dev Build / cleanup (push) Waiting to run
Dev Build / typecheck (push) Waiting to run
docs: 仓库链接指向本镜像仓库
2026-11-13 09:27:07 +08:00

98 lines
5.9 KiB
Plaintext

Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
const require_http_exception = require("../../http-exception.js");
const require_utils_buffer = require("../../utils/buffer.js");
//#region src/middleware/bearer-auth/index.ts
const TOKEN_STRINGS = "[A-Za-z0-9._~+/-]+=*";
const PREFIX = "Bearer";
const HEADER = "Authorization";
/**
* Bearer Auth Middleware for Hono.
*
* @see {@link https://hono.dev/docs/middleware/builtin/bearer-auth}
*
* @template E - The environment type.
* @param {BearerAuthOptions} options - The options for the bearer authentication middleware.
* @param {string | string[]} [options.token] - The string or array of strings to validate the incoming bearer token against.
* @param {Function} [options.verifyToken] - The function to verify the token.
* @param {string} [options.realm=""] - The domain name of the realm, as part of the returned WWW-Authenticate challenge header.
* @param {string} [options.prefix="Bearer"] - The prefix (or known as `schema`) for the Authorization header value. If set to the empty string, no prefix is expected.
* @param {string} [options.headerName=Authorization] - The header name.
* @param {Function} [options.hashFunction] - A function to handle hashing for safe comparison of authentication tokens.
* @param {string | object | MessageFunction} [options.noAuthenticationHeader.message="Unauthorized"] - The no authentication header message.
* @param {string | object | MessageFunction} [options.noAuthenticationHeader.wwwAuthenticateHeader="Bearer realm=\"\""] - The response header value for the WWW-Authenticate header when no authentication header is provided.
* @param {string | object | MessageFunction} [options.invalidAuthenticationHeader.message="Bad Request"] - The invalid authentication header message.
* @param {string | object | MessageFunction} [options.invalidAuthenticationHeader.wwwAuthenticateHeader="Bearer error=\"invalid_request\""] - The response header value for the WWW-Authenticate header when authentication header is invalid.
* @param {string | object | MessageFunction} [options.invalidToken.message="Unauthorized"] - The invalid token message.
* @param {string | object | MessageFunction} [options.invalidToken.wwwAuthenticateHeader="Bearer error=\"invalid_token\""] - The response header value for the WWW-Authenticate header when token is invalid.
* @returns {MiddlewareHandler<E>} The middleware handler function.
* @throws {Error} If neither "token" nor "verifyToken" options are provided.
* @throws {HTTPException} If authentication fails, with 401 status code for missing or invalid token, or 400 status code for invalid request.
*
* @example
* ```ts
* const app = new Hono()
*
* const token = 'honoishot'
*
* app.use('/api/*', bearerAuth({ token }))
*
* app.get('/api/page', (c) => {
* return c.json({ message: 'You are authorized' })
* })
* ```
*/
const bearerAuth = (options) => {
if (!("token" in options || "verifyToken" in options)) throw new Error("bearer auth middleware requires options for \"token\" or \"verifyToken\"");
if (!options.realm) options.realm = "";
if (options.prefix === void 0) options.prefix = PREFIX;
const realm = options.realm?.replace(/"/g, "\\\"");
const prefix = options.prefix;
const tokenRegexp = new RegExp(`^${TOKEN_STRINGS}$`);
const wwwAuthenticatePrefix = prefix === "" ? "" : `${prefix} `;
const throwHTTPException = async (c, status, wwwAuthenticateHeader, messageOption) => {
const wwwAuthenticateHeaderValue = typeof wwwAuthenticateHeader === "function" ? await wwwAuthenticateHeader(c) : wwwAuthenticateHeader;
const headers = { "WWW-Authenticate": typeof wwwAuthenticateHeaderValue === "string" ? wwwAuthenticateHeaderValue : `${wwwAuthenticatePrefix}${Object.entries(wwwAuthenticateHeaderValue).map(([key, value]) => `${key}="${value}"`).join(",")}` };
const responseMessage = typeof messageOption === "function" ? await messageOption(c) : messageOption;
const res = typeof responseMessage === "string" ? new Response(responseMessage, {
status,
headers
}) : new Response(JSON.stringify(responseMessage), {
status,
headers: {
...headers,
"content-type": "application/json"
}
});
throw new require_http_exception.HTTPException(status, { res });
};
return async function bearerAuth(c, next) {
const headerToken = c.req.header(options.headerName || HEADER);
if (!headerToken) await throwHTTPException(c, 401, options.noAuthenticationHeader?.wwwAuthenticateHeader || `${wwwAuthenticatePrefix}realm="${realm}"`, options.noAuthenticationHeader?.message || options.noAuthenticationHeaderMessage || "Unauthorized");
else {
let tokenValue;
if (prefix === "") tokenValue = headerToken;
else {
const headerLower = headerToken.toLowerCase();
const prefixLower = prefix.toLowerCase();
if (headerLower.startsWith(prefixLower) && headerToken[prefix.length] === " ") tokenValue = headerToken.slice(prefix.length).trimStart();
}
if (!tokenValue || !tokenRegexp.test(tokenValue)) await throwHTTPException(c, 400, options.invalidAuthenticationHeader?.wwwAuthenticateHeader || `${wwwAuthenticatePrefix}error="invalid_request"`, options.invalidAuthenticationHeader?.message || options.invalidAuthenticationHeaderMessage || "Bad Request");
else {
let equal = false;
if ("verifyToken" in options) equal = await options.verifyToken(tokenValue, c);
else if (typeof options.token === "string") equal = await require_utils_buffer.timingSafeEqual(options.token, tokenValue, options.hashFunction);
else if (Array.isArray(options.token) && options.token.length > 0) {
for (const token of options.token) if (await require_utils_buffer.timingSafeEqual(token, tokenValue, options.hashFunction)) {
equal = true;
break;
}
}
if (!equal) await throwHTTPException(c, 401, options.invalidToken?.wwwAuthenticateHeader || `${wwwAuthenticatePrefix}error="invalid_token"`, options.invalidToken?.message || options.invalidTokenMessage || "Unauthorized");
}
}
await next();
};
};
//#endregion
exports.bearerAuth = bearerAuth;