@openguardrails/gateway 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/config.d.ts +13 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +100 -0
- package/dist/config.js.map +1 -0
- package/dist/handlers/anthropic.d.ts +12 -0
- package/dist/handlers/anthropic.d.ts.map +1 -0
- package/dist/handlers/anthropic.js +150 -0
- package/dist/handlers/anthropic.js.map +1 -0
- package/dist/handlers/gemini.d.ts +12 -0
- package/dist/handlers/gemini.d.ts.map +1 -0
- package/dist/handlers/gemini.js +80 -0
- package/dist/handlers/gemini.js.map +1 -0
- package/dist/handlers/openai.d.ts +13 -0
- package/dist/handlers/openai.d.ts.map +1 -0
- package/dist/handlers/openai.js +145 -0
- package/dist/handlers/openai.js.map +1 -0
- package/dist/index.d.ts +16 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +136 -0
- package/dist/index.js.map +1 -0
- package/dist/restorer.d.ts +21 -0
- package/dist/restorer.d.ts.map +1 -0
- package/dist/restorer.js +91 -0
- package/dist/restorer.js.map +1 -0
- package/dist/sanitizer.d.ts +17 -0
- package/dist/sanitizer.d.ts.map +1 -0
- package/dist/sanitizer.js +226 -0
- package/dist/sanitizer.js.map +1 -0
- package/dist/types.d.ts +35 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +5 -0
- package/dist/types.js.map +1 -0
- package/package.json +55 -0
- package/src/config.ts +122 -0
- package/src/handlers/anthropic.ts +195 -0
- package/src/handlers/gemini.ts +99 -0
- package/src/handlers/openai.ts +188 -0
- package/src/index.ts +159 -0
- package/src/restorer.ts +101 -0
- package/src/sanitizer.ts +278 -0
- package/src/types.ts +43 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* OpenGuardrails AI Security Gateway
|
|
4
|
+
*
|
|
5
|
+
* Local HTTP proxy that intercepts LLM API calls, sanitizes sensitive data
|
|
6
|
+
* before sending to providers, and restores it in responses.
|
|
7
|
+
* Supports Anthropic, OpenAI, and Gemini protocols.
|
|
8
|
+
*/
|
|
9
|
+
import { createServer } from "node:http";
|
|
10
|
+
import { loadConfig, validateConfig } from "./config.js";
|
|
11
|
+
import { handleAnthropicRequest } from "./handlers/anthropic.js";
|
|
12
|
+
import { handleOpenAIRequest } from "./handlers/openai.js";
|
|
13
|
+
import { handleGeminiRequest } from "./handlers/gemini.js";
|
|
14
|
+
const GATEWAY_MODE = process.env.GATEWAY_MODE || "selfhosted";
|
|
15
|
+
let config;
|
|
16
|
+
/**
|
|
17
|
+
* Main request handler
|
|
18
|
+
*/
|
|
19
|
+
async function handleRequest(req, res) {
|
|
20
|
+
const { method, url } = req;
|
|
21
|
+
// Log request
|
|
22
|
+
console.log(`[ai-security-gateway] ${method} ${url}`);
|
|
23
|
+
// CORS headers (for browser-based clients)
|
|
24
|
+
res.setHeader("Access-Control-Allow-Origin", "*");
|
|
25
|
+
res.setHeader("Access-Control-Allow-Methods", "GET, POST, OPTIONS");
|
|
26
|
+
res.setHeader("Access-Control-Allow-Headers", "Content-Type, Authorization, x-api-key, anthropic-version");
|
|
27
|
+
// Handle OPTIONS for CORS preflight
|
|
28
|
+
if (method === "OPTIONS") {
|
|
29
|
+
res.writeHead(204);
|
|
30
|
+
res.end();
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
// Health check (allow GET)
|
|
34
|
+
if (url === "/health") {
|
|
35
|
+
res.writeHead(200, { "Content-Type": "application/json" });
|
|
36
|
+
res.end(JSON.stringify({ status: "ok", version: "1.0.0" }));
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
// Only allow POST for API endpoints
|
|
40
|
+
if (method !== "POST") {
|
|
41
|
+
res.writeHead(405, { "Content-Type": "application/json" });
|
|
42
|
+
res.end(JSON.stringify({ error: "Method not allowed" }));
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
// Route to appropriate handler
|
|
46
|
+
try {
|
|
47
|
+
if (url === "/v1/messages") {
|
|
48
|
+
// Anthropic Messages API
|
|
49
|
+
await handleAnthropicRequest(req, res, config);
|
|
50
|
+
}
|
|
51
|
+
else if (url === "/v1/chat/completions") {
|
|
52
|
+
// OpenAI Chat Completions API
|
|
53
|
+
await handleOpenAIRequest(req, res, config);
|
|
54
|
+
}
|
|
55
|
+
else if (url?.match(/^\/v1\/models\/(.+):generateContent$/)) {
|
|
56
|
+
// Gemini API
|
|
57
|
+
const match = url.match(/^\/v1\/models\/(.+):generateContent$/);
|
|
58
|
+
const modelName = match?.[1];
|
|
59
|
+
if (modelName) {
|
|
60
|
+
await handleGeminiRequest(req, res, config, modelName);
|
|
61
|
+
}
|
|
62
|
+
else {
|
|
63
|
+
res.writeHead(404, { "Content-Type": "application/json" });
|
|
64
|
+
res.end(JSON.stringify({ error: "Model name required" }));
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
else {
|
|
68
|
+
// Unknown endpoint
|
|
69
|
+
res.writeHead(404, { "Content-Type": "application/json" });
|
|
70
|
+
res.end(JSON.stringify({ error: "Not found", url }));
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
catch (error) {
|
|
74
|
+
console.error("[ai-security-gateway] Request handler error:", error);
|
|
75
|
+
res.writeHead(500, { "Content-Type": "application/json" });
|
|
76
|
+
res.end(JSON.stringify({
|
|
77
|
+
error: "Internal server error",
|
|
78
|
+
message: error instanceof Error ? error.message : String(error),
|
|
79
|
+
}));
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Start gateway server
|
|
84
|
+
*/
|
|
85
|
+
export function startGateway(configPath) {
|
|
86
|
+
try {
|
|
87
|
+
// Load and validate configuration
|
|
88
|
+
config = loadConfig(configPath);
|
|
89
|
+
validateConfig(config);
|
|
90
|
+
console.log("[ai-security-gateway] Configuration loaded:");
|
|
91
|
+
console.log(` Mode: ${GATEWAY_MODE}`);
|
|
92
|
+
console.log(` Port: ${config.port}`);
|
|
93
|
+
console.log(` Backends: ${Object.keys(config.backends).join(", ")}`);
|
|
94
|
+
// Create HTTP server
|
|
95
|
+
const server = createServer(handleRequest);
|
|
96
|
+
// Start listening
|
|
97
|
+
server.listen(config.port, "127.0.0.1", () => {
|
|
98
|
+
console.log(`[ai-security-gateway] Server listening on http://127.0.0.1:${config.port}`);
|
|
99
|
+
console.log("[ai-security-gateway] Ready to proxy requests");
|
|
100
|
+
console.log("");
|
|
101
|
+
console.log("Endpoints:");
|
|
102
|
+
console.log(` POST http://127.0.0.1:${config.port}/v1/messages - Anthropic`);
|
|
103
|
+
console.log(` POST http://127.0.0.1:${config.port}/v1/chat/completions - OpenAI`);
|
|
104
|
+
console.log(` POST http://127.0.0.1:${config.port}/v1/models/:model:generateContent - Gemini`);
|
|
105
|
+
console.log(` GET http://127.0.0.1:${config.port}/health - Health check`);
|
|
106
|
+
});
|
|
107
|
+
// Handle shutdown
|
|
108
|
+
process.on("SIGINT", () => {
|
|
109
|
+
console.log("\n[ai-security-gateway] Shutting down...");
|
|
110
|
+
server.close(() => {
|
|
111
|
+
console.log("[ai-security-gateway] Server stopped");
|
|
112
|
+
process.exit(0);
|
|
113
|
+
});
|
|
114
|
+
});
|
|
115
|
+
process.on("SIGTERM", () => {
|
|
116
|
+
console.log("\n[ai-security-gateway] Shutting down...");
|
|
117
|
+
server.close(() => {
|
|
118
|
+
console.log("[ai-security-gateway] Server stopped");
|
|
119
|
+
process.exit(0);
|
|
120
|
+
});
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
catch (error) {
|
|
124
|
+
console.error("[ai-security-gateway] Failed to start:", error);
|
|
125
|
+
process.exit(1);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
// Re-export for programmatic use
|
|
129
|
+
export { sanitize, sanitizeMessages } from "./sanitizer.js";
|
|
130
|
+
export { restore, restoreJSON, restoreSSELine } from "./restorer.js";
|
|
131
|
+
// Start if run directly
|
|
132
|
+
if (import.meta.url === `file://${process.argv[1]}`) {
|
|
133
|
+
const configPath = process.argv[2];
|
|
134
|
+
startGateway(configPath);
|
|
135
|
+
}
|
|
136
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AI Security Gateway - Content restorer
|
|
3
|
+
*
|
|
4
|
+
* Restores sanitized placeholders back to original values using the mapping table.
|
|
5
|
+
*/
|
|
6
|
+
import type { MappingTable } from "./types.js";
|
|
7
|
+
/**
|
|
8
|
+
* Restore any content (object, array, string) using the mapping table
|
|
9
|
+
*/
|
|
10
|
+
export declare function restore(content: any, mappingTable: MappingTable): any;
|
|
11
|
+
/**
|
|
12
|
+
* Restore a JSON string
|
|
13
|
+
* Useful for SSE streaming where each chunk is a JSON string
|
|
14
|
+
*/
|
|
15
|
+
export declare function restoreJSON(jsonString: string, mappingTable: MappingTable): string;
|
|
16
|
+
/**
|
|
17
|
+
* Restore SSE data line (for streaming responses)
|
|
18
|
+
* Format: "data: {...}\n"
|
|
19
|
+
*/
|
|
20
|
+
export declare function restoreSSELine(line: string, mappingTable: MappingTable): string;
|
|
21
|
+
//# sourceMappingURL=restorer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"restorer.d.ts","sourceRoot":"","sources":["../src/restorer.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAiD/C;;GAEG;AACH,wBAAgB,OAAO,CAAC,OAAO,EAAE,GAAG,EAAE,YAAY,EAAE,YAAY,GAAG,GAAG,CAGrE;AAED;;;GAGG;AACH,wBAAgB,WAAW,CAAC,UAAU,EAAE,MAAM,EAAE,YAAY,EAAE,YAAY,GAAG,MAAM,CAYlF;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,YAAY,EAAE,YAAY,GAAG,MAAM,CAe/E"}
|
package/dist/restorer.js
ADDED
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AI Security Gateway - Content restorer
|
|
3
|
+
*
|
|
4
|
+
* Restores sanitized placeholders back to original values using the mapping table.
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* Restore placeholders in a string
|
|
8
|
+
*/
|
|
9
|
+
function restoreText(text, mappingTable) {
|
|
10
|
+
let restored = text;
|
|
11
|
+
// Sort placeholders by length descending to handle nested cases
|
|
12
|
+
const placeholders = Array.from(mappingTable.keys()).sort((a, b) => b.length - a.length);
|
|
13
|
+
for (const placeholder of placeholders) {
|
|
14
|
+
const originalValue = mappingTable.get(placeholder);
|
|
15
|
+
// Use split/join for safe replacement (handles special regex chars)
|
|
16
|
+
restored = restored.split(placeholder).join(originalValue);
|
|
17
|
+
}
|
|
18
|
+
return restored;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Recursively restore any value (string, object, array)
|
|
22
|
+
*/
|
|
23
|
+
function restoreValue(value, mappingTable) {
|
|
24
|
+
// String: restore placeholders
|
|
25
|
+
if (typeof value === "string") {
|
|
26
|
+
return restoreText(value, mappingTable);
|
|
27
|
+
}
|
|
28
|
+
// Array: restore each element
|
|
29
|
+
if (Array.isArray(value)) {
|
|
30
|
+
return value.map((item) => restoreValue(item, mappingTable));
|
|
31
|
+
}
|
|
32
|
+
// Object: restore each property
|
|
33
|
+
if (value !== null && typeof value === "object") {
|
|
34
|
+
const restored = {};
|
|
35
|
+
for (const [key, val] of Object.entries(value)) {
|
|
36
|
+
restored[key] = restoreValue(val, mappingTable);
|
|
37
|
+
}
|
|
38
|
+
return restored;
|
|
39
|
+
}
|
|
40
|
+
// Primitives: return as-is
|
|
41
|
+
return value;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Restore any content (object, array, string) using the mapping table
|
|
45
|
+
*/
|
|
46
|
+
export function restore(content, mappingTable) {
|
|
47
|
+
if (mappingTable.size === 0)
|
|
48
|
+
return content;
|
|
49
|
+
return restoreValue(content, mappingTable);
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Restore a JSON string
|
|
53
|
+
* Useful for SSE streaming where each chunk is a JSON string
|
|
54
|
+
*/
|
|
55
|
+
export function restoreJSON(jsonString, mappingTable) {
|
|
56
|
+
if (mappingTable.size === 0)
|
|
57
|
+
return jsonString;
|
|
58
|
+
try {
|
|
59
|
+
// Try to parse as JSON first
|
|
60
|
+
const parsed = JSON.parse(jsonString);
|
|
61
|
+
const restored = restore(parsed, mappingTable);
|
|
62
|
+
return JSON.stringify(restored);
|
|
63
|
+
}
|
|
64
|
+
catch {
|
|
65
|
+
// If not valid JSON, treat as plain text
|
|
66
|
+
return restoreText(jsonString, mappingTable);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Restore SSE data line (for streaming responses)
|
|
71
|
+
* Format: "data: {...}\n"
|
|
72
|
+
*/
|
|
73
|
+
export function restoreSSELine(line, mappingTable) {
|
|
74
|
+
if (mappingTable.size === 0)
|
|
75
|
+
return line;
|
|
76
|
+
if (!line.startsWith("data: "))
|
|
77
|
+
return line;
|
|
78
|
+
const dataContent = line.slice(6); // Remove "data: " prefix
|
|
79
|
+
if (dataContent === "[DONE]")
|
|
80
|
+
return line;
|
|
81
|
+
try {
|
|
82
|
+
const parsed = JSON.parse(dataContent);
|
|
83
|
+
const restored = restore(parsed, mappingTable);
|
|
84
|
+
return `data: ${JSON.stringify(restored)}\n`;
|
|
85
|
+
}
|
|
86
|
+
catch {
|
|
87
|
+
// Fallback to text restoration
|
|
88
|
+
return `data: ${restoreText(dataContent, mappingTable)}\n`;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
//# sourceMappingURL=restorer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"restorer.js","sourceRoot":"","sources":["../src/restorer.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAIH;;GAEG;AACH,SAAS,WAAW,CAAC,IAAY,EAAE,YAA0B;IAC3D,IAAI,QAAQ,GAAG,IAAI,CAAC;IAEpB,gEAAgE;IAChE,MAAM,YAAY,GAAG,KAAK,CAAC,IAAI,CAAC,YAAY,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,CACvD,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,MAAM,CAC9B,CAAC;IAEF,KAAK,MAAM,WAAW,IAAI,YAAY,EAAE,CAAC;QACvC,MAAM,aAAa,GAAG,YAAY,CAAC,GAAG,CAAC,WAAW,CAAE,CAAC;QACrD,oEAAoE;QACpE,QAAQ,GAAG,QAAQ,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC;IAC7D,CAAC;IAED,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED;;GAEG;AACH,SAAS,YAAY,CAAC,KAAU,EAAE,YAA0B;IAC1D,+BAA+B;IAC/B,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QAC9B,OAAO,WAAW,CAAC,KAAK,EAAE,YAAY,CAAC,CAAC;IAC1C,CAAC;IAED,8BAA8B;IAC9B,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;QACzB,OAAO,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,YAAY,CAAC,IAAI,EAAE,YAAY,CAAC,CAAC,CAAC;IAC/D,CAAC;IAED,gCAAgC;IAChC,IAAI,KAAK,KAAK,IAAI,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QAChD,MAAM,QAAQ,GAAQ,EAAE,CAAC;QACzB,KAAK,MAAM,CAAC,GAAG,EAAE,GAAG,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;YAC/C,QAAQ,CAAC,GAAG,CAAC,GAAG,YAAY,CAAC,GAAG,EAAE,YAAY,CAAC,CAAC;QAClD,CAAC;QACD,OAAO,QAAQ,CAAC;IAClB,CAAC;IAED,2BAA2B;IAC3B,OAAO,KAAK,CAAC;AACf,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,OAAO,CAAC,OAAY,EAAE,YAA0B;IAC9D,IAAI,YAAY,CAAC,IAAI,KAAK,CAAC;QAAE,OAAO,OAAO,CAAC;IAC5C,OAAO,YAAY,CAAC,OAAO,EAAE,YAAY,CAAC,CAAC;AAC7C,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,WAAW,CAAC,UAAkB,EAAE,YAA0B;IACxE,IAAI,YAAY,CAAC,IAAI,KAAK,CAAC;QAAE,OAAO,UAAU,CAAC;IAE/C,IAAI,CAAC;QACH,6BAA6B;QAC7B,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;QACtC,MAAM,QAAQ,GAAG,OAAO,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC;QAC/C,OAAO,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC;IAClC,CAAC;IAAC,MAAM,CAAC;QACP,yCAAyC;QACzC,OAAO,WAAW,CAAC,UAAU,EAAE,YAAY,CAAC,CAAC;IAC/C,CAAC;AACH,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,cAAc,CAAC,IAAY,EAAE,YAA0B;IACrE,IAAI,YAAY,CAAC,IAAI,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IACzC,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC;QAAE,OAAO,IAAI,CAAC;IAE5C,MAAM,WAAW,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,yBAAyB;IAC5D,IAAI,WAAW,KAAK,QAAQ;QAAE,OAAO,IAAI,CAAC;IAE1C,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC;QACvC,MAAM,QAAQ,GAAG,OAAO,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC;QAC/C,OAAO,SAAS,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,IAAI,CAAC;IAC/C,CAAC;IAAC,MAAM,CAAC;QACP,+BAA+B;QAC/B,OAAO,SAAS,WAAW,CAAC,WAAW,EAAE,YAAY,CAAC,IAAI,CAAC;IAC7D,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AI Security Gateway - Content sanitizer
|
|
3
|
+
*
|
|
4
|
+
* Recursively processes message structures, replaces sensitive data with
|
|
5
|
+
* numbered placeholders, and returns a mapping table for restoration.
|
|
6
|
+
*/
|
|
7
|
+
import type { SanitizeResult } from "./types.js";
|
|
8
|
+
/**
|
|
9
|
+
* Sanitize any content (messages array, object, string)
|
|
10
|
+
* Returns sanitized content and mapping table for restoration
|
|
11
|
+
*/
|
|
12
|
+
export declare function sanitize(content: any): SanitizeResult;
|
|
13
|
+
/**
|
|
14
|
+
* Sanitize messages array (common case for LLM APIs)
|
|
15
|
+
*/
|
|
16
|
+
export declare function sanitizeMessages(messages: any[]): SanitizeResult;
|
|
17
|
+
//# sourceMappingURL=sanitizer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sanitizer.d.ts","sourceRoot":"","sources":["../src/sanitizer.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,cAAc,EAA6B,MAAM,YAAY,CAAC;AAwP5E;;;GAGG;AACH,wBAAgB,QAAQ,CAAC,OAAO,EAAE,GAAG,GAAG,cAAc,CAWrD;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,GAAG,EAAE,GAAG,cAAc,CAEhE"}
|
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AI Security Gateway - Content sanitizer
|
|
3
|
+
*
|
|
4
|
+
* Recursively processes message structures, replaces sensitive data with
|
|
5
|
+
* numbered placeholders, and returns a mapping table for restoration.
|
|
6
|
+
*/
|
|
7
|
+
const ENTITIES = [
|
|
8
|
+
// URLs (must come before email to avoid partial matches)
|
|
9
|
+
{
|
|
10
|
+
category: "URL",
|
|
11
|
+
categoryKey: "url",
|
|
12
|
+
pattern: /https?:\/\/[^\s<>"{}|\\^`\[\]]+/g,
|
|
13
|
+
},
|
|
14
|
+
// Email
|
|
15
|
+
{
|
|
16
|
+
category: "EMAIL",
|
|
17
|
+
categoryKey: "email",
|
|
18
|
+
pattern: /[A-Za-z0-9._%+\-]+@[A-Za-z0-9.\-]+\.[A-Za-z]{2,}/g,
|
|
19
|
+
},
|
|
20
|
+
// Credit Card (4 groups of 4 digits)
|
|
21
|
+
{
|
|
22
|
+
category: "CREDIT_CARD",
|
|
23
|
+
categoryKey: "credit_card",
|
|
24
|
+
pattern: /\b\d{4}[-\s]?\d{4}[-\s]?\d{4}[-\s]?\d{4}\b/g,
|
|
25
|
+
},
|
|
26
|
+
// Bank Card (Chinese format: 16-19 digits)
|
|
27
|
+
{
|
|
28
|
+
category: "BANK_CARD",
|
|
29
|
+
categoryKey: "bank_card",
|
|
30
|
+
pattern: /\b\d{16,19}\b/g,
|
|
31
|
+
},
|
|
32
|
+
// SSN (###-##-####)
|
|
33
|
+
{
|
|
34
|
+
category: "SSN",
|
|
35
|
+
categoryKey: "ssn",
|
|
36
|
+
pattern: /\b\d{3}-\d{2}-\d{4}\b/g,
|
|
37
|
+
},
|
|
38
|
+
// IBAN
|
|
39
|
+
{
|
|
40
|
+
category: "IBAN",
|
|
41
|
+
categoryKey: "iban",
|
|
42
|
+
pattern: /\b[A-Z]{2}\d{2}[A-Z0-9]{4}\d{7}[A-Z0-9]{0,16}\b/g,
|
|
43
|
+
},
|
|
44
|
+
// IP Address
|
|
45
|
+
{
|
|
46
|
+
category: "IP_ADDRESS",
|
|
47
|
+
categoryKey: "ip",
|
|
48
|
+
pattern: /\b(?:[0-9]{1,3}\.){3}[0-9]{1,3}\b/g,
|
|
49
|
+
},
|
|
50
|
+
// Phone numbers (US/intl formats, including +86-xxx-xxxx-xxxx)
|
|
51
|
+
{
|
|
52
|
+
category: "PHONE",
|
|
53
|
+
categoryKey: "phone",
|
|
54
|
+
pattern: /[+]?[0-9]{1,3}?[-\s.]?[(]?[0-9]{3}[)]?[-\s.][0-9]{3,4}[-\s.][0-9]{4,6}\b/g,
|
|
55
|
+
},
|
|
56
|
+
];
|
|
57
|
+
// Known secret prefixes
|
|
58
|
+
const SECRET_PREFIXES = [
|
|
59
|
+
"sk-",
|
|
60
|
+
"sk_",
|
|
61
|
+
"pk_",
|
|
62
|
+
"ghp_",
|
|
63
|
+
"AKIA",
|
|
64
|
+
"xox",
|
|
65
|
+
"SG.",
|
|
66
|
+
"hf_",
|
|
67
|
+
"api-",
|
|
68
|
+
"token-",
|
|
69
|
+
"secret-",
|
|
70
|
+
];
|
|
71
|
+
const BEARER_PATTERN = /Bearer\s+[A-Za-z0-9\-_.~+/]+=*/g;
|
|
72
|
+
const SECRET_PREFIX_PATTERN = new RegExp(`(?:${SECRET_PREFIXES.map((p) => p.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")).join("|")})[A-Za-z0-9\\-_.~+/]{8,}=*`, "g");
|
|
73
|
+
// =============================================================================
|
|
74
|
+
// Shannon Entropy
|
|
75
|
+
// =============================================================================
|
|
76
|
+
function shannonEntropy(s) {
|
|
77
|
+
if (s.length === 0)
|
|
78
|
+
return 0;
|
|
79
|
+
const freq = new Map();
|
|
80
|
+
for (const ch of s) {
|
|
81
|
+
freq.set(ch, (freq.get(ch) ?? 0) + 1);
|
|
82
|
+
}
|
|
83
|
+
let entropy = 0;
|
|
84
|
+
for (const count of freq.values()) {
|
|
85
|
+
const p = count / s.length;
|
|
86
|
+
entropy -= p * Math.log2(p);
|
|
87
|
+
}
|
|
88
|
+
return entropy;
|
|
89
|
+
}
|
|
90
|
+
// =============================================================================
|
|
91
|
+
// Match Collection
|
|
92
|
+
// =============================================================================
|
|
93
|
+
function collectMatches(content) {
|
|
94
|
+
const matches = [];
|
|
95
|
+
// Regex-based entities
|
|
96
|
+
for (const entity of ENTITIES) {
|
|
97
|
+
entity.pattern.lastIndex = 0;
|
|
98
|
+
let m;
|
|
99
|
+
while ((m = entity.pattern.exec(content)) !== null) {
|
|
100
|
+
matches.push({
|
|
101
|
+
originalText: m[0],
|
|
102
|
+
category: entity.categoryKey,
|
|
103
|
+
placeholder: "", // Will be set later with numbering
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
// Secret prefixes
|
|
108
|
+
SECRET_PREFIX_PATTERN.lastIndex = 0;
|
|
109
|
+
let m;
|
|
110
|
+
while ((m = SECRET_PREFIX_PATTERN.exec(content)) !== null) {
|
|
111
|
+
matches.push({
|
|
112
|
+
originalText: m[0],
|
|
113
|
+
category: "secret",
|
|
114
|
+
placeholder: "",
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
// Bearer tokens
|
|
118
|
+
BEARER_PATTERN.lastIndex = 0;
|
|
119
|
+
while ((m = BEARER_PATTERN.exec(content)) !== null) {
|
|
120
|
+
matches.push({
|
|
121
|
+
originalText: m[0],
|
|
122
|
+
category: "secret",
|
|
123
|
+
placeholder: "",
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
// High-entropy tokens
|
|
127
|
+
const tokenPattern = /\b[A-Za-z0-9\-_.~+/]{20,}={0,3}\b/g;
|
|
128
|
+
tokenPattern.lastIndex = 0;
|
|
129
|
+
while ((m = tokenPattern.exec(content)) !== null) {
|
|
130
|
+
const token = m[0];
|
|
131
|
+
if (matches.some((existing) => existing.originalText === token))
|
|
132
|
+
continue;
|
|
133
|
+
if (/^[a-z]+$/.test(token))
|
|
134
|
+
continue;
|
|
135
|
+
if (shannonEntropy(token) >= 4.0) {
|
|
136
|
+
matches.push({
|
|
137
|
+
originalText: token,
|
|
138
|
+
category: "secret",
|
|
139
|
+
placeholder: "",
|
|
140
|
+
});
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
return matches;
|
|
144
|
+
}
|
|
145
|
+
// =============================================================================
|
|
146
|
+
// Text Sanitization
|
|
147
|
+
// =============================================================================
|
|
148
|
+
function sanitizeText(text, mappingTable, categoryCounters) {
|
|
149
|
+
const matches = collectMatches(text);
|
|
150
|
+
if (matches.length === 0)
|
|
151
|
+
return text;
|
|
152
|
+
// Deduplicate by original text
|
|
153
|
+
const unique = new Map();
|
|
154
|
+
for (const match of matches) {
|
|
155
|
+
if (!unique.has(match.originalText)) {
|
|
156
|
+
unique.set(match.originalText, match);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
// Sort by length descending
|
|
160
|
+
const sorted = [...unique.values()].sort((a, b) => b.originalText.length - a.originalText.length);
|
|
161
|
+
// Replace and build mapping table
|
|
162
|
+
let sanitized = text;
|
|
163
|
+
for (const match of sorted) {
|
|
164
|
+
// Generate numbered placeholder
|
|
165
|
+
const counter = (categoryCounters.get(match.category) ?? 0) + 1;
|
|
166
|
+
categoryCounters.set(match.category, counter);
|
|
167
|
+
const placeholder = `__${match.category}_${counter}__`;
|
|
168
|
+
// Replace all occurrences
|
|
169
|
+
const parts = sanitized.split(match.originalText);
|
|
170
|
+
if (parts.length > 1) {
|
|
171
|
+
sanitized = parts.join(placeholder);
|
|
172
|
+
mappingTable.set(placeholder, match.originalText);
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
return sanitized;
|
|
176
|
+
}
|
|
177
|
+
// =============================================================================
|
|
178
|
+
// Recursive Sanitization
|
|
179
|
+
// =============================================================================
|
|
180
|
+
/**
|
|
181
|
+
* Recursively sanitize any value (string, object, array)
|
|
182
|
+
*/
|
|
183
|
+
function sanitizeValue(value, mappingTable, categoryCounters) {
|
|
184
|
+
// String: sanitize directly
|
|
185
|
+
if (typeof value === "string") {
|
|
186
|
+
return sanitizeText(value, mappingTable, categoryCounters);
|
|
187
|
+
}
|
|
188
|
+
// Array: sanitize each element
|
|
189
|
+
if (Array.isArray(value)) {
|
|
190
|
+
return value.map((item) => sanitizeValue(item, mappingTable, categoryCounters));
|
|
191
|
+
}
|
|
192
|
+
// Object: sanitize each property
|
|
193
|
+
if (value !== null && typeof value === "object") {
|
|
194
|
+
const sanitized = {};
|
|
195
|
+
for (const [key, val] of Object.entries(value)) {
|
|
196
|
+
sanitized[key] = sanitizeValue(val, mappingTable, categoryCounters);
|
|
197
|
+
}
|
|
198
|
+
return sanitized;
|
|
199
|
+
}
|
|
200
|
+
// Primitives: return as-is
|
|
201
|
+
return value;
|
|
202
|
+
}
|
|
203
|
+
// =============================================================================
|
|
204
|
+
// Public API
|
|
205
|
+
// =============================================================================
|
|
206
|
+
/**
|
|
207
|
+
* Sanitize any content (messages array, object, string)
|
|
208
|
+
* Returns sanitized content and mapping table for restoration
|
|
209
|
+
*/
|
|
210
|
+
export function sanitize(content) {
|
|
211
|
+
const mappingTable = new Map();
|
|
212
|
+
const categoryCounters = new Map();
|
|
213
|
+
const sanitized = sanitizeValue(content, mappingTable, categoryCounters);
|
|
214
|
+
return {
|
|
215
|
+
sanitized,
|
|
216
|
+
mappingTable,
|
|
217
|
+
redactionCount: mappingTable.size,
|
|
218
|
+
};
|
|
219
|
+
}
|
|
220
|
+
/**
|
|
221
|
+
* Sanitize messages array (common case for LLM APIs)
|
|
222
|
+
*/
|
|
223
|
+
export function sanitizeMessages(messages) {
|
|
224
|
+
return sanitize(messages);
|
|
225
|
+
}
|
|
226
|
+
//# sourceMappingURL=sanitizer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sanitizer.js","sourceRoot":"","sources":["../src/sanitizer.ts"],"names":[],"mappings":"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"}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AI Security Gateway types
|
|
3
|
+
*/
|
|
4
|
+
export type MappingTable = Map<string, string>;
|
|
5
|
+
export type SanitizeResult = {
|
|
6
|
+
sanitized: any;
|
|
7
|
+
mappingTable: MappingTable;
|
|
8
|
+
redactionCount: number;
|
|
9
|
+
};
|
|
10
|
+
export type GatewayConfig = {
|
|
11
|
+
port: number;
|
|
12
|
+
backends: {
|
|
13
|
+
anthropic?: {
|
|
14
|
+
baseUrl: string;
|
|
15
|
+
apiKey: string;
|
|
16
|
+
};
|
|
17
|
+
openai?: {
|
|
18
|
+
baseUrl: string;
|
|
19
|
+
apiKey: string;
|
|
20
|
+
};
|
|
21
|
+
gemini?: {
|
|
22
|
+
baseUrl: string;
|
|
23
|
+
apiKey: string;
|
|
24
|
+
};
|
|
25
|
+
};
|
|
26
|
+
routing?: {
|
|
27
|
+
[path: string]: keyof GatewayConfig["backends"];
|
|
28
|
+
};
|
|
29
|
+
};
|
|
30
|
+
export type EntityMatch = {
|
|
31
|
+
originalText: string;
|
|
32
|
+
category: string;
|
|
33
|
+
placeholder: string;
|
|
34
|
+
};
|
|
35
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AAGH,MAAM,MAAM,YAAY,GAAG,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;AAG/C,MAAM,MAAM,cAAc,GAAG;IAC3B,SAAS,EAAE,GAAG,CAAC;IACf,YAAY,EAAE,YAAY,CAAC;IAC3B,cAAc,EAAE,MAAM,CAAC;CACxB,CAAC;AAGF,MAAM,MAAM,aAAa,GAAG;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE;QACR,SAAS,CAAC,EAAE;YACV,OAAO,EAAE,MAAM,CAAC;YAChB,MAAM,EAAE,MAAM,CAAC;SAChB,CAAC;QACF,MAAM,CAAC,EAAE;YACP,OAAO,EAAE,MAAM,CAAC;YAChB,MAAM,EAAE,MAAM,CAAC;SAChB,CAAC;QACF,MAAM,CAAC,EAAE;YACP,OAAO,EAAE,MAAM,CAAC;YAChB,MAAM,EAAE,MAAM,CAAC;SAChB,CAAC;KACH,CAAC;IAEF,OAAO,CAAC,EAAE;QACR,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,aAAa,CAAC,UAAU,CAAC,CAAC;KACjD,CAAC;CACH,CAAC;AAGF,MAAM,MAAM,WAAW,GAAG;IACxB,YAAY,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;CACrB,CAAC"}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;GAEG"}
|
package/package.json
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@openguardrails/gateway",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "AI Security Gateway — secure proxy for LLM APIs with PII sanitization, credential detection, and content security",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "dist/index.js",
|
|
7
|
+
"types": "dist/index.d.ts",
|
|
8
|
+
"bin": {
|
|
9
|
+
"og-gateway": "./dist/index.js"
|
|
10
|
+
},
|
|
11
|
+
"scripts": {
|
|
12
|
+
"build": "tsc",
|
|
13
|
+
"dev": "tsx src/index.ts",
|
|
14
|
+
"start": "node dist/index.js",
|
|
15
|
+
"typecheck": "tsc --noEmit",
|
|
16
|
+
"test": "tsx test/sanitizer.test.ts"
|
|
17
|
+
},
|
|
18
|
+
"keywords": [
|
|
19
|
+
"ai-security",
|
|
20
|
+
"ai-gateway",
|
|
21
|
+
"llm-proxy",
|
|
22
|
+
"pii-sanitization",
|
|
23
|
+
"credential-detection",
|
|
24
|
+
"openguardrails",
|
|
25
|
+
"anthropic",
|
|
26
|
+
"openai",
|
|
27
|
+
"gemini"
|
|
28
|
+
],
|
|
29
|
+
"author": "OpenGuardrails",
|
|
30
|
+
"license": "Apache-2.0",
|
|
31
|
+
"publishConfig": {
|
|
32
|
+
"access": "public"
|
|
33
|
+
},
|
|
34
|
+
"repository": {
|
|
35
|
+
"type": "git",
|
|
36
|
+
"url": "git+https://github.com/openguardrails/openguardrails.git",
|
|
37
|
+
"directory": "gateway"
|
|
38
|
+
},
|
|
39
|
+
"bugs": {
|
|
40
|
+
"url": "https://github.com/openguardrails/openguardrails/issues"
|
|
41
|
+
},
|
|
42
|
+
"homepage": "https://github.com/openguardrails/openguardrails/tree/main/gateway#readme",
|
|
43
|
+
"files": [
|
|
44
|
+
"dist/",
|
|
45
|
+
"src/"
|
|
46
|
+
],
|
|
47
|
+
"devDependencies": {
|
|
48
|
+
"@types/node": "^22.0.0",
|
|
49
|
+
"tsx": "^4.0.0",
|
|
50
|
+
"typescript": "^5.6.0"
|
|
51
|
+
},
|
|
52
|
+
"engines": {
|
|
53
|
+
"node": ">=22.0.0"
|
|
54
|
+
}
|
|
55
|
+
}
|