@guardcore/express 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs ADDED
@@ -0,0 +1,298 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+
30
+ // src/index.ts
31
+ var index_exports = {};
32
+ __export(index_exports, {
33
+ BaseSecurityDecorator: () => import_core2.BaseSecurityDecorator,
34
+ BehaviorRule: () => import_core2.BehaviorRule,
35
+ ExpressGuardRequest: () => ExpressGuardRequest,
36
+ ExpressGuardResponse: () => ExpressGuardResponse,
37
+ ExpressResponseFactory: () => ExpressResponseFactory,
38
+ RouteConfig: () => import_core2.RouteConfig,
39
+ SecurityConfigSchema: () => import_core2.SecurityConfigSchema,
40
+ SecurityDecorator: () => import_core2.SecurityDecorator,
41
+ configureCors: () => configureCors,
42
+ createSecurityMiddleware: () => createSecurityMiddleware,
43
+ defaultLogger: () => import_core2.defaultLogger,
44
+ guardBodyParser: () => guardBodyParser,
45
+ guardUrlEncodedParser: () => guardUrlEncodedParser,
46
+ sendGuardResponse: () => sendGuardResponse
47
+ });
48
+ module.exports = __toCommonJS(index_exports);
49
+
50
+ // src/middleware.ts
51
+ var import_core = require("@guardcore/core");
52
+
53
+ // src/adapters.ts
54
+ var ExpressGuardRequest = class {
55
+ constructor(req) {
56
+ this.req = req;
57
+ const raw = req["rawBody"];
58
+ if (raw instanceof Uint8Array) {
59
+ this.rawBody = raw;
60
+ } else if (raw instanceof Buffer) {
61
+ this.rawBody = new Uint8Array(raw);
62
+ }
63
+ }
64
+ _state = {};
65
+ rawBody = null;
66
+ get urlPath() {
67
+ return this.req.path;
68
+ }
69
+ get urlScheme() {
70
+ return this.req.protocol;
71
+ }
72
+ get urlFull() {
73
+ return `${this.req.protocol}://${this.req.get("host")}${this.req.originalUrl}`;
74
+ }
75
+ urlReplaceScheme(scheme) {
76
+ return this.urlFull.replace(/^https?/, scheme);
77
+ }
78
+ get method() {
79
+ return this.req.method;
80
+ }
81
+ get clientHost() {
82
+ return this.req.socket.remoteAddress ?? null;
83
+ }
84
+ get headers() {
85
+ return this.req.headers;
86
+ }
87
+ get queryParams() {
88
+ return this.req.query;
89
+ }
90
+ async body() {
91
+ return this.rawBody ?? new Uint8Array(0);
92
+ }
93
+ get state() {
94
+ return this._state;
95
+ }
96
+ get scope() {
97
+ return {};
98
+ }
99
+ };
100
+ var ExpressGuardResponse = class {
101
+ constructor(statusCode, content) {
102
+ this.statusCode = statusCode;
103
+ this._body = new TextEncoder().encode(content);
104
+ this._headers["content-type"] = "application/json";
105
+ }
106
+ _headers = {};
107
+ _body;
108
+ get headers() {
109
+ return this._headers;
110
+ }
111
+ setHeader(name, value) {
112
+ this._headers[name] = value;
113
+ }
114
+ get body() {
115
+ return this._body;
116
+ }
117
+ get bodyText() {
118
+ return this._body ? new TextDecoder().decode(this._body) : null;
119
+ }
120
+ };
121
+ var ExpressResponseFactory = class {
122
+ createResponse(content, statusCode) {
123
+ return new ExpressGuardResponse(statusCode, JSON.stringify({ detail: content }));
124
+ }
125
+ createRedirectResponse(url, statusCode) {
126
+ const resp = new ExpressGuardResponse(statusCode, "");
127
+ resp.setHeader("location", url);
128
+ return resp;
129
+ }
130
+ };
131
+ function sendGuardResponse(res, guardResponse) {
132
+ for (const [name, value] of Object.entries(guardResponse.headers)) {
133
+ res.setHeader(name, value);
134
+ }
135
+ if (guardResponse.headers["location"]) {
136
+ res.redirect(guardResponse.statusCode, guardResponse.headers["location"]);
137
+ return;
138
+ }
139
+ res.status(guardResponse.statusCode);
140
+ if (guardResponse.body) {
141
+ res.send(Buffer.from(guardResponse.body));
142
+ } else {
143
+ res.end();
144
+ }
145
+ }
146
+
147
+ // src/middleware.ts
148
+ function createSecurityMiddleware(options) {
149
+ const resolved = import_core.SecurityConfigSchema.parse(options.config);
150
+ const logger = resolved.logger ?? import_core.defaultLogger;
151
+ const responseFactory = new ExpressResponseFactory();
152
+ let initialized = false;
153
+ let components;
154
+ async function initialize() {
155
+ if (initialized) return;
156
+ components = await (0, import_core.initializeSecurityMiddleware)(
157
+ resolved,
158
+ logger,
159
+ responseFactory,
160
+ options.agentHandler,
161
+ options.geoIpHandler,
162
+ options.guardDecorator
163
+ );
164
+ initialized = true;
165
+ logger.info("Guard security middleware initialized");
166
+ }
167
+ return async function guardMiddleware(req, res, next) {
168
+ await initialize();
169
+ const startTime = performance.now();
170
+ const guardReq = new ExpressGuardRequest(req);
171
+ const passthrough = await components.bypassHandler.handlePassthrough(
172
+ guardReq,
173
+ async () => createPassthroughResponse()
174
+ );
175
+ if (passthrough) {
176
+ sendGuardResponse(res, passthrough);
177
+ return;
178
+ }
179
+ const routeConfig = components.routeResolver.getRouteConfig(guardReq);
180
+ const bypass = await components.bypassHandler.handleSecurityBypass(
181
+ guardReq,
182
+ async () => createPassthroughResponse(),
183
+ routeConfig
184
+ );
185
+ if (bypass) {
186
+ sendGuardResponse(res, bypass);
187
+ return;
188
+ }
189
+ const blockResponse = await components.pipeline.execute(guardReq);
190
+ if (blockResponse) {
191
+ sendGuardResponse(res, blockResponse);
192
+ return;
193
+ }
194
+ if (routeConfig && routeConfig.behaviorRules.length > 0) {
195
+ const clientIp = guardReq.clientHost ?? "unknown";
196
+ await components.behavioralProcessor.processUsageRules(guardReq, clientIp, routeConfig);
197
+ }
198
+ const originalEnd = res.end;
199
+ const chunks = [];
200
+ res.end = function(chunk, ...args) {
201
+ if (chunk) chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(String(chunk)));
202
+ const responseTime = (performance.now() - startTime) / 1e3;
203
+ const body = Buffer.concat(chunks);
204
+ const capturedResponse = {
205
+ statusCode: res.statusCode,
206
+ headers: Object.fromEntries(
207
+ Object.entries(res.getHeaders()).map(([k, v]) => [k, String(v)])
208
+ ),
209
+ setHeader(name, value) {
210
+ res.setHeader(name, value);
211
+ },
212
+ body: new Uint8Array(body),
213
+ bodyText: body.toString("utf-8")
214
+ };
215
+ components.errorResponseFactory.processResponse(
216
+ guardReq,
217
+ capturedResponse,
218
+ responseTime,
219
+ routeConfig ?? null,
220
+ routeConfig ? async (request, response, clientIp, rc) => {
221
+ await components.behavioralProcessor.processReturnRules(request, response, clientIp, rc);
222
+ } : void 0
223
+ ).catch(() => {
224
+ });
225
+ return originalEnd.apply(res, [chunk, ...args]);
226
+ };
227
+ next();
228
+ };
229
+ }
230
+ function createPassthroughResponse() {
231
+ return {
232
+ statusCode: 200,
233
+ headers: {},
234
+ setHeader() {
235
+ },
236
+ body: null,
237
+ bodyText: null
238
+ };
239
+ }
240
+
241
+ // src/cors.ts
242
+ function configureCors(app, config) {
243
+ if (!config.enableCors) return;
244
+ try {
245
+ const corsMiddleware = require("cors");
246
+ app.use(corsMiddleware({
247
+ origin: config.corsAllowOrigins,
248
+ methods: config.corsAllowMethods,
249
+ allowedHeaders: config.corsAllowHeaders,
250
+ credentials: config.corsAllowCredentials,
251
+ exposedHeaders: config.corsExposeHeaders,
252
+ maxAge: config.corsMaxAge
253
+ }));
254
+ } catch {
255
+ throw new Error(
256
+ '@guardcore/express: CORS is enabled but the "cors" package is not installed. Run: pnpm add cors'
257
+ );
258
+ }
259
+ }
260
+
261
+ // src/body-parser.ts
262
+ var import_express = __toESM(require("express"), 1);
263
+ function guardBodyParser() {
264
+ return import_express.default.json({
265
+ verify: (req, _res, buf, _encoding) => {
266
+ req["rawBody"] = buf;
267
+ }
268
+ });
269
+ }
270
+ function guardUrlEncodedParser() {
271
+ return import_express.default.urlencoded({
272
+ extended: true,
273
+ verify: (req, _res, buf, _encoding) => {
274
+ req["rawBody"] = buf;
275
+ }
276
+ });
277
+ }
278
+
279
+ // src/index.ts
280
+ var import_core2 = require("@guardcore/core");
281
+ // Annotate the CommonJS export names for ESM import in node:
282
+ 0 && (module.exports = {
283
+ BaseSecurityDecorator,
284
+ BehaviorRule,
285
+ ExpressGuardRequest,
286
+ ExpressGuardResponse,
287
+ ExpressResponseFactory,
288
+ RouteConfig,
289
+ SecurityConfigSchema,
290
+ SecurityDecorator,
291
+ configureCors,
292
+ createSecurityMiddleware,
293
+ defaultLogger,
294
+ guardBodyParser,
295
+ guardUrlEncodedParser,
296
+ sendGuardResponse
297
+ });
298
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts","../src/middleware.ts","../src/adapters.ts","../src/cors.ts","../src/body-parser.ts"],"sourcesContent":["export { createSecurityMiddleware } from './middleware.js';\nexport type { SecurityMiddlewareOptions } from './middleware.js';\nexport { configureCors } from './cors.js';\nexport { guardBodyParser, guardUrlEncodedParser } from './body-parser.js';\nexport { ExpressGuardRequest, ExpressGuardResponse, ExpressResponseFactory, sendGuardResponse } from './adapters.js';\n\nexport {\n SecurityConfigSchema,\n BaseSecurityDecorator,\n SecurityDecorator,\n RouteConfig,\n BehaviorRule,\n defaultLogger,\n} from '@guardcore/core';\n\nexport type {\n SecurityConfig,\n ResolvedSecurityConfig,\n GuardRequest,\n GuardResponse,\n Logger,\n SecurityMiddlewareComponents,\n HandlerRegistry,\n} from '@guardcore/core';\n","import type { Request, Response, NextFunction } from 'express';\nimport type {\n SecurityConfig,\n GuardRequest,\n GuardResponse,\n Logger,\n AgentHandlerProtocol,\n GeoIPHandler,\n SecurityMiddlewareComponents,\n RouteConfig,\n} from '@guardcore/core';\nimport { SecurityConfigSchema, defaultLogger, initializeSecurityMiddleware } from '@guardcore/core';\nimport { ExpressGuardRequest, ExpressResponseFactory, sendGuardResponse } from './adapters.js';\n\nexport interface SecurityMiddlewareOptions {\n config: SecurityConfig;\n agentHandler?: AgentHandlerProtocol;\n geoIpHandler?: GeoIPHandler;\n guardDecorator?: unknown;\n}\n\nexport function createSecurityMiddleware(options: SecurityMiddlewareOptions) {\n const resolved = SecurityConfigSchema.parse(options.config);\n const logger: Logger = resolved.logger ?? defaultLogger;\n const responseFactory = new ExpressResponseFactory();\n\n let initialized = false;\n let components: SecurityMiddlewareComponents;\n\n async function initialize(): Promise<void> {\n if (initialized) return;\n components = await initializeSecurityMiddleware(\n resolved, logger, responseFactory,\n options.agentHandler, options.geoIpHandler, options.guardDecorator,\n );\n initialized = true;\n logger.info('Guard security middleware initialized');\n }\n\n return async function guardMiddleware(req: Request, res: Response, next: NextFunction): Promise<void> {\n await initialize();\n\n const startTime = performance.now();\n const guardReq = new ExpressGuardRequest(req);\n\n const passthrough = await components.bypassHandler.handlePassthrough(\n guardReq,\n async () => createPassthroughResponse(),\n );\n if (passthrough) {\n sendGuardResponse(res, passthrough);\n return;\n }\n\n const routeConfig = components.routeResolver.getRouteConfig(guardReq);\n\n const bypass = await components.bypassHandler.handleSecurityBypass(\n guardReq,\n async () => createPassthroughResponse(),\n routeConfig,\n );\n if (bypass) {\n sendGuardResponse(res, bypass);\n return;\n }\n\n const blockResponse = await components.pipeline.execute(guardReq);\n if (blockResponse) {\n sendGuardResponse(res, blockResponse);\n return;\n }\n\n if (routeConfig && routeConfig.behaviorRules.length > 0) {\n const clientIp = guardReq.clientHost ?? 'unknown';\n await components.behavioralProcessor.processUsageRules(guardReq, clientIp, routeConfig);\n }\n\n const originalEnd = res.end;\n const chunks: Buffer[] = [];\n\n res.end = function (chunk: unknown, ...args: unknown[]): Response {\n if (chunk) chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(String(chunk)));\n\n const responseTime = (performance.now() - startTime) / 1000;\n const body = Buffer.concat(chunks);\n const capturedResponse: GuardResponse = {\n statusCode: res.statusCode,\n headers: Object.fromEntries(\n Object.entries(res.getHeaders()).map(([k, v]) => [k, String(v)]),\n ),\n setHeader(name: string, value: string) { res.setHeader(name, value); },\n body: new Uint8Array(body),\n bodyText: body.toString('utf-8'),\n };\n\n components.errorResponseFactory.processResponse(\n guardReq, capturedResponse, responseTime, routeConfig ?? null,\n routeConfig ? async (request: GuardRequest, response: GuardResponse, clientIp: string, rc: RouteConfig) => {\n await components.behavioralProcessor.processReturnRules(request, response, clientIp, rc);\n } : undefined,\n ).catch(() => {});\n\n return originalEnd.apply(res, [chunk, ...args] as Parameters<typeof originalEnd>);\n };\n\n next();\n };\n}\n\nfunction createPassthroughResponse(): GuardResponse {\n return {\n statusCode: 200,\n headers: {},\n setHeader() {},\n body: null,\n bodyText: null,\n };\n}\n","import type { Request, Response } from 'express';\nimport type { GuardRequest, GuardRequestState, GuardResponse, GuardResponseFactory } from '@guardcore/core';\n\nexport class ExpressGuardRequest implements GuardRequest {\n private _state: GuardRequestState = {};\n private rawBody: Uint8Array | null = null;\n\n constructor(private readonly req: Request) {\n const raw = (req as unknown as Record<string, unknown>)['rawBody'];\n if (raw instanceof Uint8Array) {\n this.rawBody = raw;\n } else if (raw instanceof Buffer) {\n this.rawBody = new Uint8Array(raw);\n }\n }\n\n get urlPath(): string { return this.req.path; }\n get urlScheme(): string { return this.req.protocol; }\n get urlFull(): string { return `${this.req.protocol}://${this.req.get('host')}${this.req.originalUrl}`; }\n urlReplaceScheme(scheme: string): string { return this.urlFull.replace(/^https?/, scheme); }\n get method(): string { return this.req.method; }\n get clientHost(): string | null { return this.req.socket.remoteAddress ?? null; }\n get headers(): Readonly<Record<string, string>> { return this.req.headers as Record<string, string>; }\n get queryParams(): Readonly<Record<string, string>> { return this.req.query as Record<string, string>; }\n async body(): Promise<Uint8Array> { return this.rawBody ?? new Uint8Array(0); }\n get state(): GuardRequestState { return this._state; }\n get scope(): Readonly<Record<string, unknown>> { return {}; }\n}\n\nexport class ExpressGuardResponse implements GuardResponse {\n private _headers: Record<string, string> = {};\n private _body: Uint8Array | null;\n\n constructor(\n readonly statusCode: number,\n content: string,\n ) {\n this._body = new TextEncoder().encode(content);\n this._headers['content-type'] = 'application/json';\n }\n\n get headers(): Record<string, string> { return this._headers; }\n setHeader(name: string, value: string): void { this._headers[name] = value; }\n get body(): Uint8Array | null { return this._body; }\n get bodyText(): string | null {\n return this._body ? new TextDecoder().decode(this._body) : null;\n }\n}\n\nexport class ExpressResponseFactory implements GuardResponseFactory {\n createResponse(content: string, statusCode: number): GuardResponse {\n return new ExpressGuardResponse(statusCode, JSON.stringify({ detail: content }));\n }\n\n createRedirectResponse(url: string, statusCode: number): GuardResponse {\n const resp = new ExpressGuardResponse(statusCode, '');\n resp.setHeader('location', url);\n return resp;\n }\n}\n\nexport function sendGuardResponse(res: Response, guardResponse: GuardResponse): void {\n for (const [name, value] of Object.entries(guardResponse.headers)) {\n res.setHeader(name, value);\n }\n\n if (guardResponse.headers['location']) {\n res.redirect(guardResponse.statusCode, guardResponse.headers['location']);\n return;\n }\n\n res.status(guardResponse.statusCode);\n if (guardResponse.body) {\n res.send(Buffer.from(guardResponse.body));\n } else {\n res.end();\n }\n}\n","import type { Express } from 'express';\nimport type { ResolvedSecurityConfig } from '@guardcore/core';\n\nexport function configureCors(app: Express, config: ResolvedSecurityConfig): void {\n if (!config.enableCors) return;\n\n try {\n const corsMiddleware = require('cors');\n app.use(corsMiddleware({\n origin: config.corsAllowOrigins,\n methods: config.corsAllowMethods,\n allowedHeaders: config.corsAllowHeaders,\n credentials: config.corsAllowCredentials,\n exposedHeaders: config.corsExposeHeaders,\n maxAge: config.corsMaxAge,\n }));\n } catch {\n throw new Error(\n '@guardcore/express: CORS is enabled but the \"cors\" package is not installed. ' +\n 'Run: pnpm add cors',\n );\n }\n}\n","import type { Request, Response, NextFunction, RequestHandler } from 'express';\nimport express from 'express';\n\nexport function guardBodyParser(): RequestHandler {\n return express.json({\n verify: (req: Request, _res: Response, buf: Buffer, _encoding: string) => {\n (req as unknown as Record<string, unknown>)['rawBody'] = buf;\n },\n });\n}\n\nexport function guardUrlEncodedParser(): RequestHandler {\n return express.urlencoded({\n extended: true,\n verify: (req: Request, _res: Response, buf: Buffer, _encoding: string) => {\n (req as unknown as Record<string, unknown>)['rawBody'] = buf;\n },\n });\n}\n"],"mappings":"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","names":["express","import_core"]}
@@ -0,0 +1,51 @@
1
+ import { Request, Response, NextFunction, Express, RequestHandler } from 'express';
2
+ import { SecurityConfig, AgentHandlerProtocol, GeoIPHandler, ResolvedSecurityConfig, GuardRequest, GuardRequestState, GuardResponse, GuardResponseFactory } from '@guardcore/core';
3
+ export { BaseSecurityDecorator, BehaviorRule, GuardRequest, GuardResponse, HandlerRegistry, Logger, ResolvedSecurityConfig, RouteConfig, SecurityConfig, SecurityConfigSchema, SecurityDecorator, SecurityMiddlewareComponents, defaultLogger } from '@guardcore/core';
4
+
5
+ interface SecurityMiddlewareOptions {
6
+ config: SecurityConfig;
7
+ agentHandler?: AgentHandlerProtocol;
8
+ geoIpHandler?: GeoIPHandler;
9
+ guardDecorator?: unknown;
10
+ }
11
+ declare function createSecurityMiddleware(options: SecurityMiddlewareOptions): (req: Request, res: Response, next: NextFunction) => Promise<void>;
12
+
13
+ declare function configureCors(app: Express, config: ResolvedSecurityConfig): void;
14
+
15
+ declare function guardBodyParser(): RequestHandler;
16
+ declare function guardUrlEncodedParser(): RequestHandler;
17
+
18
+ declare class ExpressGuardRequest implements GuardRequest {
19
+ private readonly req;
20
+ private _state;
21
+ private rawBody;
22
+ constructor(req: Request);
23
+ get urlPath(): string;
24
+ get urlScheme(): string;
25
+ get urlFull(): string;
26
+ urlReplaceScheme(scheme: string): string;
27
+ get method(): string;
28
+ get clientHost(): string | null;
29
+ get headers(): Readonly<Record<string, string>>;
30
+ get queryParams(): Readonly<Record<string, string>>;
31
+ body(): Promise<Uint8Array>;
32
+ get state(): GuardRequestState;
33
+ get scope(): Readonly<Record<string, unknown>>;
34
+ }
35
+ declare class ExpressGuardResponse implements GuardResponse {
36
+ readonly statusCode: number;
37
+ private _headers;
38
+ private _body;
39
+ constructor(statusCode: number, content: string);
40
+ get headers(): Record<string, string>;
41
+ setHeader(name: string, value: string): void;
42
+ get body(): Uint8Array | null;
43
+ get bodyText(): string | null;
44
+ }
45
+ declare class ExpressResponseFactory implements GuardResponseFactory {
46
+ createResponse(content: string, statusCode: number): GuardResponse;
47
+ createRedirectResponse(url: string, statusCode: number): GuardResponse;
48
+ }
49
+ declare function sendGuardResponse(res: Response, guardResponse: GuardResponse): void;
50
+
51
+ export { ExpressGuardRequest, ExpressGuardResponse, ExpressResponseFactory, type SecurityMiddlewareOptions, configureCors, createSecurityMiddleware, guardBodyParser, guardUrlEncodedParser, sendGuardResponse };
@@ -0,0 +1,51 @@
1
+ import { Request, Response, NextFunction, Express, RequestHandler } from 'express';
2
+ import { SecurityConfig, AgentHandlerProtocol, GeoIPHandler, ResolvedSecurityConfig, GuardRequest, GuardRequestState, GuardResponse, GuardResponseFactory } from '@guardcore/core';
3
+ export { BaseSecurityDecorator, BehaviorRule, GuardRequest, GuardResponse, HandlerRegistry, Logger, ResolvedSecurityConfig, RouteConfig, SecurityConfig, SecurityConfigSchema, SecurityDecorator, SecurityMiddlewareComponents, defaultLogger } from '@guardcore/core';
4
+
5
+ interface SecurityMiddlewareOptions {
6
+ config: SecurityConfig;
7
+ agentHandler?: AgentHandlerProtocol;
8
+ geoIpHandler?: GeoIPHandler;
9
+ guardDecorator?: unknown;
10
+ }
11
+ declare function createSecurityMiddleware(options: SecurityMiddlewareOptions): (req: Request, res: Response, next: NextFunction) => Promise<void>;
12
+
13
+ declare function configureCors(app: Express, config: ResolvedSecurityConfig): void;
14
+
15
+ declare function guardBodyParser(): RequestHandler;
16
+ declare function guardUrlEncodedParser(): RequestHandler;
17
+
18
+ declare class ExpressGuardRequest implements GuardRequest {
19
+ private readonly req;
20
+ private _state;
21
+ private rawBody;
22
+ constructor(req: Request);
23
+ get urlPath(): string;
24
+ get urlScheme(): string;
25
+ get urlFull(): string;
26
+ urlReplaceScheme(scheme: string): string;
27
+ get method(): string;
28
+ get clientHost(): string | null;
29
+ get headers(): Readonly<Record<string, string>>;
30
+ get queryParams(): Readonly<Record<string, string>>;
31
+ body(): Promise<Uint8Array>;
32
+ get state(): GuardRequestState;
33
+ get scope(): Readonly<Record<string, unknown>>;
34
+ }
35
+ declare class ExpressGuardResponse implements GuardResponse {
36
+ readonly statusCode: number;
37
+ private _headers;
38
+ private _body;
39
+ constructor(statusCode: number, content: string);
40
+ get headers(): Record<string, string>;
41
+ setHeader(name: string, value: string): void;
42
+ get body(): Uint8Array | null;
43
+ get bodyText(): string | null;
44
+ }
45
+ declare class ExpressResponseFactory implements GuardResponseFactory {
46
+ createResponse(content: string, statusCode: number): GuardResponse;
47
+ createRedirectResponse(url: string, statusCode: number): GuardResponse;
48
+ }
49
+ declare function sendGuardResponse(res: Response, guardResponse: GuardResponse): void;
50
+
51
+ export { ExpressGuardRequest, ExpressGuardResponse, ExpressResponseFactory, type SecurityMiddlewareOptions, configureCors, createSecurityMiddleware, guardBodyParser, guardUrlEncodedParser, sendGuardResponse };
package/dist/index.js ADDED
@@ -0,0 +1,262 @@
1
+ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
2
+ get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
3
+ }) : x)(function(x) {
4
+ if (typeof require !== "undefined") return require.apply(this, arguments);
5
+ throw Error('Dynamic require of "' + x + '" is not supported');
6
+ });
7
+
8
+ // src/middleware.ts
9
+ import { SecurityConfigSchema, defaultLogger, initializeSecurityMiddleware } from "@guardcore/core";
10
+
11
+ // src/adapters.ts
12
+ var ExpressGuardRequest = class {
13
+ constructor(req) {
14
+ this.req = req;
15
+ const raw = req["rawBody"];
16
+ if (raw instanceof Uint8Array) {
17
+ this.rawBody = raw;
18
+ } else if (raw instanceof Buffer) {
19
+ this.rawBody = new Uint8Array(raw);
20
+ }
21
+ }
22
+ _state = {};
23
+ rawBody = null;
24
+ get urlPath() {
25
+ return this.req.path;
26
+ }
27
+ get urlScheme() {
28
+ return this.req.protocol;
29
+ }
30
+ get urlFull() {
31
+ return `${this.req.protocol}://${this.req.get("host")}${this.req.originalUrl}`;
32
+ }
33
+ urlReplaceScheme(scheme) {
34
+ return this.urlFull.replace(/^https?/, scheme);
35
+ }
36
+ get method() {
37
+ return this.req.method;
38
+ }
39
+ get clientHost() {
40
+ return this.req.socket.remoteAddress ?? null;
41
+ }
42
+ get headers() {
43
+ return this.req.headers;
44
+ }
45
+ get queryParams() {
46
+ return this.req.query;
47
+ }
48
+ async body() {
49
+ return this.rawBody ?? new Uint8Array(0);
50
+ }
51
+ get state() {
52
+ return this._state;
53
+ }
54
+ get scope() {
55
+ return {};
56
+ }
57
+ };
58
+ var ExpressGuardResponse = class {
59
+ constructor(statusCode, content) {
60
+ this.statusCode = statusCode;
61
+ this._body = new TextEncoder().encode(content);
62
+ this._headers["content-type"] = "application/json";
63
+ }
64
+ _headers = {};
65
+ _body;
66
+ get headers() {
67
+ return this._headers;
68
+ }
69
+ setHeader(name, value) {
70
+ this._headers[name] = value;
71
+ }
72
+ get body() {
73
+ return this._body;
74
+ }
75
+ get bodyText() {
76
+ return this._body ? new TextDecoder().decode(this._body) : null;
77
+ }
78
+ };
79
+ var ExpressResponseFactory = class {
80
+ createResponse(content, statusCode) {
81
+ return new ExpressGuardResponse(statusCode, JSON.stringify({ detail: content }));
82
+ }
83
+ createRedirectResponse(url, statusCode) {
84
+ const resp = new ExpressGuardResponse(statusCode, "");
85
+ resp.setHeader("location", url);
86
+ return resp;
87
+ }
88
+ };
89
+ function sendGuardResponse(res, guardResponse) {
90
+ for (const [name, value] of Object.entries(guardResponse.headers)) {
91
+ res.setHeader(name, value);
92
+ }
93
+ if (guardResponse.headers["location"]) {
94
+ res.redirect(guardResponse.statusCode, guardResponse.headers["location"]);
95
+ return;
96
+ }
97
+ res.status(guardResponse.statusCode);
98
+ if (guardResponse.body) {
99
+ res.send(Buffer.from(guardResponse.body));
100
+ } else {
101
+ res.end();
102
+ }
103
+ }
104
+
105
+ // src/middleware.ts
106
+ function createSecurityMiddleware(options) {
107
+ const resolved = SecurityConfigSchema.parse(options.config);
108
+ const logger = resolved.logger ?? defaultLogger;
109
+ const responseFactory = new ExpressResponseFactory();
110
+ let initialized = false;
111
+ let components;
112
+ async function initialize() {
113
+ if (initialized) return;
114
+ components = await initializeSecurityMiddleware(
115
+ resolved,
116
+ logger,
117
+ responseFactory,
118
+ options.agentHandler,
119
+ options.geoIpHandler,
120
+ options.guardDecorator
121
+ );
122
+ initialized = true;
123
+ logger.info("Guard security middleware initialized");
124
+ }
125
+ return async function guardMiddleware(req, res, next) {
126
+ await initialize();
127
+ const startTime = performance.now();
128
+ const guardReq = new ExpressGuardRequest(req);
129
+ const passthrough = await components.bypassHandler.handlePassthrough(
130
+ guardReq,
131
+ async () => createPassthroughResponse()
132
+ );
133
+ if (passthrough) {
134
+ sendGuardResponse(res, passthrough);
135
+ return;
136
+ }
137
+ const routeConfig = components.routeResolver.getRouteConfig(guardReq);
138
+ const bypass = await components.bypassHandler.handleSecurityBypass(
139
+ guardReq,
140
+ async () => createPassthroughResponse(),
141
+ routeConfig
142
+ );
143
+ if (bypass) {
144
+ sendGuardResponse(res, bypass);
145
+ return;
146
+ }
147
+ const blockResponse = await components.pipeline.execute(guardReq);
148
+ if (blockResponse) {
149
+ sendGuardResponse(res, blockResponse);
150
+ return;
151
+ }
152
+ if (routeConfig && routeConfig.behaviorRules.length > 0) {
153
+ const clientIp = guardReq.clientHost ?? "unknown";
154
+ await components.behavioralProcessor.processUsageRules(guardReq, clientIp, routeConfig);
155
+ }
156
+ const originalEnd = res.end;
157
+ const chunks = [];
158
+ res.end = function(chunk, ...args) {
159
+ if (chunk) chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(String(chunk)));
160
+ const responseTime = (performance.now() - startTime) / 1e3;
161
+ const body = Buffer.concat(chunks);
162
+ const capturedResponse = {
163
+ statusCode: res.statusCode,
164
+ headers: Object.fromEntries(
165
+ Object.entries(res.getHeaders()).map(([k, v]) => [k, String(v)])
166
+ ),
167
+ setHeader(name, value) {
168
+ res.setHeader(name, value);
169
+ },
170
+ body: new Uint8Array(body),
171
+ bodyText: body.toString("utf-8")
172
+ };
173
+ components.errorResponseFactory.processResponse(
174
+ guardReq,
175
+ capturedResponse,
176
+ responseTime,
177
+ routeConfig ?? null,
178
+ routeConfig ? async (request, response, clientIp, rc) => {
179
+ await components.behavioralProcessor.processReturnRules(request, response, clientIp, rc);
180
+ } : void 0
181
+ ).catch(() => {
182
+ });
183
+ return originalEnd.apply(res, [chunk, ...args]);
184
+ };
185
+ next();
186
+ };
187
+ }
188
+ function createPassthroughResponse() {
189
+ return {
190
+ statusCode: 200,
191
+ headers: {},
192
+ setHeader() {
193
+ },
194
+ body: null,
195
+ bodyText: null
196
+ };
197
+ }
198
+
199
+ // src/cors.ts
200
+ function configureCors(app, config) {
201
+ if (!config.enableCors) return;
202
+ try {
203
+ const corsMiddleware = __require("cors");
204
+ app.use(corsMiddleware({
205
+ origin: config.corsAllowOrigins,
206
+ methods: config.corsAllowMethods,
207
+ allowedHeaders: config.corsAllowHeaders,
208
+ credentials: config.corsAllowCredentials,
209
+ exposedHeaders: config.corsExposeHeaders,
210
+ maxAge: config.corsMaxAge
211
+ }));
212
+ } catch {
213
+ throw new Error(
214
+ '@guardcore/express: CORS is enabled but the "cors" package is not installed. Run: pnpm add cors'
215
+ );
216
+ }
217
+ }
218
+
219
+ // src/body-parser.ts
220
+ import express from "express";
221
+ function guardBodyParser() {
222
+ return express.json({
223
+ verify: (req, _res, buf, _encoding) => {
224
+ req["rawBody"] = buf;
225
+ }
226
+ });
227
+ }
228
+ function guardUrlEncodedParser() {
229
+ return express.urlencoded({
230
+ extended: true,
231
+ verify: (req, _res, buf, _encoding) => {
232
+ req["rawBody"] = buf;
233
+ }
234
+ });
235
+ }
236
+
237
+ // src/index.ts
238
+ import {
239
+ SecurityConfigSchema as SecurityConfigSchema2,
240
+ BaseSecurityDecorator,
241
+ SecurityDecorator,
242
+ RouteConfig,
243
+ BehaviorRule,
244
+ defaultLogger as defaultLogger2
245
+ } from "@guardcore/core";
246
+ export {
247
+ BaseSecurityDecorator,
248
+ BehaviorRule,
249
+ ExpressGuardRequest,
250
+ ExpressGuardResponse,
251
+ ExpressResponseFactory,
252
+ RouteConfig,
253
+ SecurityConfigSchema2 as SecurityConfigSchema,
254
+ SecurityDecorator,
255
+ configureCors,
256
+ createSecurityMiddleware,
257
+ defaultLogger2 as defaultLogger,
258
+ guardBodyParser,
259
+ guardUrlEncodedParser,
260
+ sendGuardResponse
261
+ };
262
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/middleware.ts","../src/adapters.ts","../src/cors.ts","../src/body-parser.ts","../src/index.ts"],"sourcesContent":["import type { Request, Response, NextFunction } from 'express';\nimport type {\n SecurityConfig,\n GuardRequest,\n GuardResponse,\n Logger,\n AgentHandlerProtocol,\n GeoIPHandler,\n SecurityMiddlewareComponents,\n RouteConfig,\n} from '@guardcore/core';\nimport { SecurityConfigSchema, defaultLogger, initializeSecurityMiddleware } from '@guardcore/core';\nimport { ExpressGuardRequest, ExpressResponseFactory, sendGuardResponse } from './adapters.js';\n\nexport interface SecurityMiddlewareOptions {\n config: SecurityConfig;\n agentHandler?: AgentHandlerProtocol;\n geoIpHandler?: GeoIPHandler;\n guardDecorator?: unknown;\n}\n\nexport function createSecurityMiddleware(options: SecurityMiddlewareOptions) {\n const resolved = SecurityConfigSchema.parse(options.config);\n const logger: Logger = resolved.logger ?? defaultLogger;\n const responseFactory = new ExpressResponseFactory();\n\n let initialized = false;\n let components: SecurityMiddlewareComponents;\n\n async function initialize(): Promise<void> {\n if (initialized) return;\n components = await initializeSecurityMiddleware(\n resolved, logger, responseFactory,\n options.agentHandler, options.geoIpHandler, options.guardDecorator,\n );\n initialized = true;\n logger.info('Guard security middleware initialized');\n }\n\n return async function guardMiddleware(req: Request, res: Response, next: NextFunction): Promise<void> {\n await initialize();\n\n const startTime = performance.now();\n const guardReq = new ExpressGuardRequest(req);\n\n const passthrough = await components.bypassHandler.handlePassthrough(\n guardReq,\n async () => createPassthroughResponse(),\n );\n if (passthrough) {\n sendGuardResponse(res, passthrough);\n return;\n }\n\n const routeConfig = components.routeResolver.getRouteConfig(guardReq);\n\n const bypass = await components.bypassHandler.handleSecurityBypass(\n guardReq,\n async () => createPassthroughResponse(),\n routeConfig,\n );\n if (bypass) {\n sendGuardResponse(res, bypass);\n return;\n }\n\n const blockResponse = await components.pipeline.execute(guardReq);\n if (blockResponse) {\n sendGuardResponse(res, blockResponse);\n return;\n }\n\n if (routeConfig && routeConfig.behaviorRules.length > 0) {\n const clientIp = guardReq.clientHost ?? 'unknown';\n await components.behavioralProcessor.processUsageRules(guardReq, clientIp, routeConfig);\n }\n\n const originalEnd = res.end;\n const chunks: Buffer[] = [];\n\n res.end = function (chunk: unknown, ...args: unknown[]): Response {\n if (chunk) chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(String(chunk)));\n\n const responseTime = (performance.now() - startTime) / 1000;\n const body = Buffer.concat(chunks);\n const capturedResponse: GuardResponse = {\n statusCode: res.statusCode,\n headers: Object.fromEntries(\n Object.entries(res.getHeaders()).map(([k, v]) => [k, String(v)]),\n ),\n setHeader(name: string, value: string) { res.setHeader(name, value); },\n body: new Uint8Array(body),\n bodyText: body.toString('utf-8'),\n };\n\n components.errorResponseFactory.processResponse(\n guardReq, capturedResponse, responseTime, routeConfig ?? null,\n routeConfig ? async (request: GuardRequest, response: GuardResponse, clientIp: string, rc: RouteConfig) => {\n await components.behavioralProcessor.processReturnRules(request, response, clientIp, rc);\n } : undefined,\n ).catch(() => {});\n\n return originalEnd.apply(res, [chunk, ...args] as Parameters<typeof originalEnd>);\n };\n\n next();\n };\n}\n\nfunction createPassthroughResponse(): GuardResponse {\n return {\n statusCode: 200,\n headers: {},\n setHeader() {},\n body: null,\n bodyText: null,\n };\n}\n","import type { Request, Response } from 'express';\nimport type { GuardRequest, GuardRequestState, GuardResponse, GuardResponseFactory } from '@guardcore/core';\n\nexport class ExpressGuardRequest implements GuardRequest {\n private _state: GuardRequestState = {};\n private rawBody: Uint8Array | null = null;\n\n constructor(private readonly req: Request) {\n const raw = (req as unknown as Record<string, unknown>)['rawBody'];\n if (raw instanceof Uint8Array) {\n this.rawBody = raw;\n } else if (raw instanceof Buffer) {\n this.rawBody = new Uint8Array(raw);\n }\n }\n\n get urlPath(): string { return this.req.path; }\n get urlScheme(): string { return this.req.protocol; }\n get urlFull(): string { return `${this.req.protocol}://${this.req.get('host')}${this.req.originalUrl}`; }\n urlReplaceScheme(scheme: string): string { return this.urlFull.replace(/^https?/, scheme); }\n get method(): string { return this.req.method; }\n get clientHost(): string | null { return this.req.socket.remoteAddress ?? null; }\n get headers(): Readonly<Record<string, string>> { return this.req.headers as Record<string, string>; }\n get queryParams(): Readonly<Record<string, string>> { return this.req.query as Record<string, string>; }\n async body(): Promise<Uint8Array> { return this.rawBody ?? new Uint8Array(0); }\n get state(): GuardRequestState { return this._state; }\n get scope(): Readonly<Record<string, unknown>> { return {}; }\n}\n\nexport class ExpressGuardResponse implements GuardResponse {\n private _headers: Record<string, string> = {};\n private _body: Uint8Array | null;\n\n constructor(\n readonly statusCode: number,\n content: string,\n ) {\n this._body = new TextEncoder().encode(content);\n this._headers['content-type'] = 'application/json';\n }\n\n get headers(): Record<string, string> { return this._headers; }\n setHeader(name: string, value: string): void { this._headers[name] = value; }\n get body(): Uint8Array | null { return this._body; }\n get bodyText(): string | null {\n return this._body ? new TextDecoder().decode(this._body) : null;\n }\n}\n\nexport class ExpressResponseFactory implements GuardResponseFactory {\n createResponse(content: string, statusCode: number): GuardResponse {\n return new ExpressGuardResponse(statusCode, JSON.stringify({ detail: content }));\n }\n\n createRedirectResponse(url: string, statusCode: number): GuardResponse {\n const resp = new ExpressGuardResponse(statusCode, '');\n resp.setHeader('location', url);\n return resp;\n }\n}\n\nexport function sendGuardResponse(res: Response, guardResponse: GuardResponse): void {\n for (const [name, value] of Object.entries(guardResponse.headers)) {\n res.setHeader(name, value);\n }\n\n if (guardResponse.headers['location']) {\n res.redirect(guardResponse.statusCode, guardResponse.headers['location']);\n return;\n }\n\n res.status(guardResponse.statusCode);\n if (guardResponse.body) {\n res.send(Buffer.from(guardResponse.body));\n } else {\n res.end();\n }\n}\n","import type { Express } from 'express';\nimport type { ResolvedSecurityConfig } from '@guardcore/core';\n\nexport function configureCors(app: Express, config: ResolvedSecurityConfig): void {\n if (!config.enableCors) return;\n\n try {\n const corsMiddleware = require('cors');\n app.use(corsMiddleware({\n origin: config.corsAllowOrigins,\n methods: config.corsAllowMethods,\n allowedHeaders: config.corsAllowHeaders,\n credentials: config.corsAllowCredentials,\n exposedHeaders: config.corsExposeHeaders,\n maxAge: config.corsMaxAge,\n }));\n } catch {\n throw new Error(\n '@guardcore/express: CORS is enabled but the \"cors\" package is not installed. ' +\n 'Run: pnpm add cors',\n );\n }\n}\n","import type { Request, Response, NextFunction, RequestHandler } from 'express';\nimport express from 'express';\n\nexport function guardBodyParser(): RequestHandler {\n return express.json({\n verify: (req: Request, _res: Response, buf: Buffer, _encoding: string) => {\n (req as unknown as Record<string, unknown>)['rawBody'] = buf;\n },\n });\n}\n\nexport function guardUrlEncodedParser(): RequestHandler {\n return express.urlencoded({\n extended: true,\n verify: (req: Request, _res: Response, buf: Buffer, _encoding: string) => {\n (req as unknown as Record<string, unknown>)['rawBody'] = buf;\n },\n });\n}\n","export { createSecurityMiddleware } from './middleware.js';\nexport type { SecurityMiddlewareOptions } from './middleware.js';\nexport { configureCors } from './cors.js';\nexport { guardBodyParser, guardUrlEncodedParser } from './body-parser.js';\nexport { ExpressGuardRequest, ExpressGuardResponse, ExpressResponseFactory, sendGuardResponse } from './adapters.js';\n\nexport {\n SecurityConfigSchema,\n BaseSecurityDecorator,\n SecurityDecorator,\n RouteConfig,\n BehaviorRule,\n defaultLogger,\n} from '@guardcore/core';\n\nexport type {\n SecurityConfig,\n ResolvedSecurityConfig,\n GuardRequest,\n GuardResponse,\n Logger,\n SecurityMiddlewareComponents,\n HandlerRegistry,\n} from '@guardcore/core';\n"],"mappings":"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","names":["SecurityConfigSchema","defaultLogger"]}
package/package.json ADDED
@@ -0,0 +1,55 @@
1
+ {
2
+ "name": "@guardcore/express",
3
+ "version": "1.0.0",
4
+ "description": "Express adapter for @guardcore/core security middleware",
5
+ "type": "module",
6
+ "main": "./dist/index.cjs",
7
+ "module": "./dist/index.js",
8
+ "types": "./dist/index.d.ts",
9
+ "exports": {
10
+ ".": {
11
+ "types": "./dist/index.d.ts",
12
+ "import": "./dist/index.js",
13
+ "require": "./dist/index.cjs"
14
+ }
15
+ },
16
+ "files": [
17
+ "dist"
18
+ ],
19
+ "scripts": {
20
+ "build": "tsup",
21
+ "test": "vitest run",
22
+ "lint": "tsc --noEmit",
23
+ "clean": "rm -rf dist"
24
+ },
25
+ "dependencies": {
26
+ "@guardcore/core": "workspace:*"
27
+ },
28
+ "devDependencies": {
29
+ "tsup": "^8",
30
+ "vitest": "^4",
31
+ "typescript": "~5.9",
32
+ "@types/express": "^5"
33
+ },
34
+ "peerDependencies": {
35
+ "express": "^4 || ^5",
36
+ "cors": "^2"
37
+ },
38
+ "peerDependenciesMeta": {
39
+ "cors": {
40
+ "optional": true
41
+ }
42
+ },
43
+ "license": "MIT",
44
+ "engines": {
45
+ "node": ">=18"
46
+ },
47
+ "repository": {
48
+ "type": "git",
49
+ "url": "git+https://github.com/rennf93/guard-core-ts.git",
50
+ "directory": "packages/express"
51
+ },
52
+ "publishConfig": {
53
+ "access": "public"
54
+ }
55
+ }