CTX7-272: ip address header

This commit is contained in:
buggyhunter 2025-07-18 19:24:48 +03:00
parent 086d4c2083
commit 294df1d487
2 changed files with 30 additions and 24 deletions

View File

@ -55,7 +55,7 @@ function getClientIp(req: IncomingMessage): string | undefined {
const ips = Array.isArray(forwardedFor) ? forwardedFor[0] : forwardedFor;
return ips.split(",")[0].trim();
}
// Fall back to socket remote address
return req.socket?.remoteAddress || undefined;
}
@ -165,10 +165,14 @@ ${resultsText}`,
),
},
async ({ context7CompatibleLibraryID, tokens = DEFAULT_MINIMUM_TOKENS, topic = "" }) => {
const fetchDocsResponse = await fetchLibraryDocumentation(context7CompatibleLibraryID, {
tokens,
topic,
}, clientIp);
const fetchDocsResponse = await fetchLibraryDocumentation(
context7CompatibleLibraryID,
{
tokens,
topic,
},
clientIp
);
if (!fetchDocsResponse) {
return {
@ -221,7 +225,7 @@ async function main() {
try {
// Extract client IP address using socket remote address (most reliable)
const clientIp = getClientIp(req);
// Create new server instance for each request
const requestServer = createServerInstance(clientIp);

View File

@ -5,8 +5,10 @@ const CONTEXT7_API_BASE_URL = "https://context7.com/api";
const DEFAULT_TYPE = "txt";
// Encryption configuration
const ENCRYPTION_KEY = process.env.CLIENT_IP_ENCRYPTION_KEY || "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f";
const ALGORITHM = 'aes-256-cbc';
const ENCRYPTION_KEY =
process.env.CLIENT_IP_ENCRYPTION_KEY ||
"000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f";
const ALGORITHM = "aes-256-cbc";
// Validate encryption key
function validateEncryptionKey(key: string): boolean {
@ -19,13 +21,13 @@ function encryptClientIp(clientIp: string): string {
console.error("Invalid encryption key format. Must be 64 hex characters.");
return clientIp; // Fallback to unencrypted
}
try {
const iv = randomBytes(16);
const cipher = createCipheriv(ALGORITHM, Buffer.from(ENCRYPTION_KEY, 'hex'), iv);
let encrypted = cipher.update(clientIp, 'utf8', 'hex');
encrypted += cipher.final('hex');
return iv.toString('hex') + ':' + encrypted;
const cipher = createCipheriv(ALGORITHM, Buffer.from(ENCRYPTION_KEY, "hex"), iv);
let encrypted = cipher.update(clientIp, "utf8", "hex");
encrypted += cipher.final("hex");
return iv.toString("hex") + ":" + encrypted;
} catch (error) {
console.error("Error encrypting client IP:", error);
return clientIp; // Fallback to unencrypted
@ -37,19 +39,19 @@ export function decryptClientIp(encryptedIp: string): string | null {
console.error("Invalid encryption key format. Cannot decrypt.");
return null;
}
try {
const parts = encryptedIp.split(':');
const parts = encryptedIp.split(":");
if (parts.length !== 2) {
// Not encrypted, return as-is
return encryptedIp;
}
const iv = Buffer.from(parts[0], 'hex');
const iv = Buffer.from(parts[0], "hex");
const encrypted = parts[1];
const decipher = createDecipheriv(ALGORITHM, Buffer.from(ENCRYPTION_KEY, 'hex'), iv);
let decrypted = decipher.update(encrypted, 'hex', 'utf8');
decrypted += decipher.final('utf8');
const decipher = createDecipheriv(ALGORITHM, Buffer.from(ENCRYPTION_KEY, "hex"), iv);
let decrypted = decipher.update(encrypted, "hex", "utf8");
decrypted += decipher.final("utf8");
return decrypted;
} catch (error) {
console.error("Error decrypting client IP:", error);
@ -67,12 +69,12 @@ export async function searchLibraries(query: string, clientIp?: string): Promise
try {
const url = new URL(`${CONTEXT7_API_BASE_URL}/v1/search`);
url.searchParams.set("query", query);
const headers: Record<string, string> = {};
if (clientIp) {
headers["mcp-client-ip"] = encryptClientIp(clientIp);
}
const response = await fetch(url, { headers });
if (!response.ok) {
const errorCode = response.status;
@ -119,14 +121,14 @@ export async function fetchLibraryDocumentation(
if (options.tokens) url.searchParams.set("tokens", options.tokens.toString());
if (options.topic) url.searchParams.set("topic", options.topic);
url.searchParams.set("type", DEFAULT_TYPE);
const headers: Record<string, string> = {
"X-Context7-Source": "mcp-server",
};
if (clientIp) {
headers["mcp-client-ip"] = encryptClientIp(clientIp);
}
const response = await fetch(url, { headers });
if (!response.ok) {
const errorCode = response.status;