UNPKG

@azure/static-web-apps-cli

Version:
87 lines 3.94 kB
import chalk from "chalk"; import httpProxy from "http-proxy"; import { registerProcessExit } from "../../core/utils/cli.js"; import { decodeCookie, validateCookie } from "../../core/utils/cookie.js"; import { logger, logRequest } from "../../core/utils/logger.js"; import { SWA_CLI_DATA_API_URI } from "../../core/constants.js"; import { onConnectionLost } from "../middlewares/request.middleware.js"; const proxyApi = httpProxy.createProxyServer({ autoRewrite: true }); registerProcessExit(() => { logger.silly(`killing SWA CLI`); proxyApi.close(() => logger.log("Data-Api proxy stopped.")); process.exit(0); }); /** * Gets response from the Data Api * @param req http request url * @param res http response after redirecting to Data api builder */ export function handleDataApiRequest(req, res) { const target = SWA_CLI_DATA_API_URI(); proxyApi.web(req, res, { target, }, onConnectionLost(req, res, target, "↳")); proxyApi.once("proxyReq", (proxyReq) => { injectHeaders(proxyReq, target); injectClientPrincipalCookies(proxyReq); }); proxyApi.once("proxyRes", (proxyRes) => { logger.silly(`getting response from remote host`); logRequest(req, "", proxyRes.statusCode); }); logRequest(req, target); } // exported for testing export function injectHeaders(req, host) { const X_MS_ORIGINAL_URL_HEADER = "x-ms-original-url"; const X_MS_REQUEST_ID_HEADER = "x-ms-request-id"; logger.silly(`injecting headers to Data-api request:`); if (!req.getHeader(X_MS_ORIGINAL_URL_HEADER)) { req.setHeader(X_MS_ORIGINAL_URL_HEADER, encodeURI(new URL(req.path, host).toString())); logger.silly(` - x-ms-original-url: ${chalk.yellow(req.getHeader(X_MS_ORIGINAL_URL_HEADER))}`); } // generate a fake correlation ID req.setHeader(X_MS_REQUEST_ID_HEADER, `SWA-CLI-${Math.random().toString(36).substring(2).toUpperCase()}`); logger.silly(` - x-ms-request-id: ${chalk.yellow(req.getHeader(X_MS_REQUEST_ID_HEADER))}`); } /** * Checks if the request is Data-api request or not * @param req http request url * @param rewritePath * @returns true if the request is data-api Request else false */ export function isDataApiRequest(req, rewritePath) { const path = rewritePath || req.url; return Boolean(path?.toLowerCase().startsWith(`/data-api/`)); } // exported for testing export function injectClientPrincipalCookies(req) { const X_MS_CLIENT_PRINCIPAL_HEADER = "X-MS-CLIENT-PRINCIPAL"; const AUTH_HEADER = "authorization"; const COOKIE_HEADER = "cookie"; const CLAIMS_HEADER = "claims"; logger.silly(`injecting client principal to Functions request:`); const cookie = req.getHeader(COOKIE_HEADER); if (cookie && validateCookie(cookie)) { const user = decodeCookie(cookie); // Remove claims from client principal to match SWA behaviour. See https://github.com/MicrosoftDocs/azure-docs/issues/86803. // The following property deletion can be removed depending on outcome of the above issue. if (user) { delete user[CLAIMS_HEADER]; } const buff = Buffer.from(JSON.stringify(user), "utf-8"); const token = buff.toString("base64"); req.setHeader(X_MS_CLIENT_PRINCIPAL_HEADER, token); logger.silly(` - X-MS-CLIENT-PRINCIPAL: ${chalk.yellow(req.getHeader(X_MS_CLIENT_PRINCIPAL_HEADER))}`); // locally, we set the JWT bearer token to be the same as the cookie value because we are not using the real auth flow. // Note: on production, SWA uses a valid encrypted JWT token! if (!req.getHeader(AUTH_HEADER)) { req.setHeader(AUTH_HEADER, `Bearer ${token}`); logger.silly(` - Authorization: ${chalk.yellow(req.getHeader(AUTH_HEADER))}`); } } else { logger.silly(` - no valid cookie found`); } } //# sourceMappingURL=dab.handler.js.map