UNPKG

@lock-dev/next-adapter

Version:

Nextjs adapter module for lock.dev security framework

317 lines (310 loc) 9.88 kB
"use strict"; var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __hasOwnProp = Object.prototype.hasOwnProperty; var __export = (target, all) => { for (var name in all) __defProp(target, name, { get: all[name], enumerable: true }); }; var __copyProps = (to, from, except, desc) => { if (from && typeof from === "object" || typeof from === "function") { for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); } return to; }; var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); // src/index.ts var index_exports = {}; __export(index_exports, { createEdgeMiddleware: () => createEdgeMiddleware, createErrorData: () => createErrorData, createErrorResponse: () => createErrorResponse, createResponseProxy: () => createResponseProxy, extractSecurityMetadata: () => extractSecurityMetadata, getErrorConfig: () => getErrorConfig, handleSecurityFailure: () => handleSecurityFailure, registerModule: () => import_core5.registerModule, secureAppRoute: () => secureAppRoute, securePagesApi: () => securePagesApi, secureServerAction: () => secureServerAction }); module.exports = __toCommonJS(index_exports); var import_core5 = require("@lock-dev/core"); // src/utils/index.ts function createResponseProxy() { return { headersSent: false, writableEnded: false, statusCode: 200, headers: new Headers(), status(code) { this.statusCode = code; return this; }, setHeader(name, value) { this.headers.set(name, value); return this; }, json(body) { return new Response(JSON.stringify(body), { status: this.statusCode, headers: this.headers }); } }; } function extractSecurityMetadata(result) { if (result.event) { return { module: result.event.moduleName, reason: result.event.message, type: result.event.type, timestamp: new Date(result.event.timestamp).toISOString(), severity: result.event.severity, details: result.event.data || {} }; } else { return { module: "unknown", reason: "Access denied by security policy", timestamp: (/* @__PURE__ */ new Date()).toISOString(), details: {} }; } } function getErrorConfig(context, result) { let statusCode = 403; let errorMessage = "Access denied by security policy"; if (result.event && result.event.moduleName) { const configKey = `${result.event.moduleName}:config`; const config = context.data.get(configKey); if (config) { statusCode = config.blockStatusCode || config.statusCode || statusCode; errorMessage = config.blockMessage || config.message || errorMessage; } } return { statusCode, errorMessage }; } function createErrorData(context, result) { const metadata = extractSecurityMetadata(result); const { statusCode, errorMessage } = getErrorConfig(context, result); return { error: errorMessage, blocked: true, meta: metadata, statusCode }; } function createErrorResponse(context, result) { const errorData = createErrorData(context, result); const headers = new Headers({ "Content-Type": "application/json" }); if (context.response && "headers" in context.response) { const responseHeaders = context.response.headers; if (responseHeaders instanceof Headers) { responseHeaders.forEach((value, key) => { headers.set(key, value); }); } else if (typeof responseHeaders === "object") { Object.entries(responseHeaders).forEach(([key, value]) => { if (typeof value === "string") { headers.set(key, value); } }); } } return new Response(JSON.stringify(errorData), { status: errorData.statusCode, headers }); } function handleSecurityFailure(context, result, res) { if (!res.headersSent && !res.writableEnded) { const errorData = createErrorData(context, result); res.status(errorData.statusCode).json({ error: errorData.error, blocked: true, meta: errorData.meta }); } } // src/pages-router.ts var import_core = require("@lock-dev/core"); function securePagesApi(handler) { return (...modules) => { const composedModule = (0, import_core.composeModules)(...modules); return async (req, res) => { const context = (0, import_core.createContext)(req, res, {}); try { const result = await composedModule.check(context); if (result.passed) { return handler(req, res); } else { handleSecurityFailure(context, result, res); } } catch (error) { console.error("Security middleware error:", error); if (!res.headersSent) { return res.status(500).json({ error: "Internal security error" }); } } }; }; } // src/app-router.ts var import_core2 = require("@lock-dev/core"); function secureAppRoute(handler) { return (...modules) => { const composedModule = (0, import_core2.composeModules)(...modules); return async (req) => { const resProxy = createResponseProxy(); const context = (0, import_core2.createContext)(req, resProxy, {}); try { const result = await composedModule.check(context); if (result.passed) { const originalResponse = await handler(req); const responseClone = new Response(originalResponse.body, { status: originalResponse.status, statusText: originalResponse.statusText, headers: new Headers({ ...Object.fromEntries(originalResponse.headers.entries()), ...Object.fromEntries(resProxy.headers.entries()) }) }); return responseClone; } else { return createErrorResponse(context, result); } } catch (error) { console.error("Middleware error:", error); return new Response(JSON.stringify({ error: "Internal security error" }), { status: 500, headers: { "Content-Type": "application/json" } }); } }; }; } // src/server-actions.ts var import_core3 = require("@lock-dev/core"); function secureServerAction(action) { return (...modules) => { const composedModule = (0, import_core3.composeModules)(...modules); return async (...args) => { const req = { headers: {}, cookies: {}, method: "POST", url: "/", body: {} }; const formDataArg = args.find((arg) => arg instanceof FormData); if (formDataArg && formDataArg instanceof FormData) { const requestHeaders = formDataArg.get("$REQUEST_HEADERS"); if (requestHeaders && typeof requestHeaders === "string") { try { req.headers = JSON.parse(requestHeaders); } catch (e) { console.warn("Failed to parse request headers in server action"); } } const csrfToken = formDataArg.get("csrf-token") || formDataArg.get("csrfToken"); if (csrfToken && typeof csrfToken === "string") { req.headers["x-csrf-token"] = csrfToken; } } const res = { headersSent: false, writableEnded: false, statusCode: 200, headers: {}, status(code) { this.statusCode = code; return this; }, setHeader(name, value) { this.headers[name] = value; return this; }, json(body) { return body; } }; const context = (0, import_core3.createContext)(req, res, {}); try { const result = await composedModule.check(context); if (result.passed) { return action(...args); } else { const errorData = createErrorData(context, result); throw new Error(JSON.stringify(errorData)); } } catch (error) { if (error instanceof Error && error.message.startsWith("{")) { throw error; } console.error("Security middleware error:", error); throw new Error( JSON.stringify({ error: "Internal security error", statusCode: 500 }) ); } }; }; } // src/edge.ts var import_core4 = require("@lock-dev/core"); function createEdgeMiddleware(...modules) { const composedModule = (0, import_core4.composeModules)(...modules); return async function middleware(req) { const resProxy = createResponseProxy(); const context = (0, import_core4.createContext)(req, resProxy, {}); try { const result = await composedModule.check(context); if (result.passed) { const headers = new Headers({ "x-middleware-next": "1" }); resProxy.headers.forEach((value, key) => { headers.set(key, value); }); return new Response(null, { status: 200, headers }); } else { return createErrorResponse(context, result); } } catch (error) { console.error("Security middleware error:", error); return new Response(JSON.stringify({ error: "Internal security error" }), { status: 500, headers: { "Content-Type": "application/json" } }); } }; } // Annotate the CommonJS export names for ESM import in node: 0 && (module.exports = { createEdgeMiddleware, createErrorData, createErrorResponse, createResponseProxy, extractSecurityMetadata, getErrorConfig, handleSecurityFailure, registerModule, secureAppRoute, securePagesApi, secureServerAction });