@kya-os/mcp-i
Version:
The TypeScript MCP framework with identity features built-in
57 lines (56 loc) • 1.96 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.RedisNonceCache = void 0;
/**
* Redis-based nonce cache implementation
* Suitable for multi-instance deployments
*/
class RedisNonceCache {
redis; // Redis client - type depends on redis library used
keyPrefix;
constructor(redis, keyPrefix = "mcpi:nonce:") {
this.redis = redis;
this.keyPrefix = keyPrefix;
}
getKey(nonce, agentDid) {
if (agentDid) {
return `${this.keyPrefix}${agentDid}:${nonce}`;
}
return `${this.keyPrefix}${nonce}`;
}
async has(nonce, agentDid) {
try {
const key = this.getKey(nonce, agentDid);
const exists = await this.redis.exists(key);
return exists === 1;
}
catch (error) {
console.error("Redis has() operation failed:", error);
throw new Error(`Failed to check nonce existence: ${error}`);
}
}
async add(nonce, ttl, agentDid) {
try {
const key = this.getKey(nonce, agentDid);
// Use SET with NX (not exists) and EX (expiry) for atomic add-if-absent
// This is truly atomic in Redis
const result = await this.redis.set(key, "1", "EX", ttl, "NX");
if (result !== "OK") {
throw new Error(`Nonce ${nonce} already exists - potential replay attack`);
}
}
catch (error) {
// Re-throw our own errors
if (error.message?.includes("already exists")) {
throw error;
}
console.error("Redis add() operation failed:", error);
throw new Error(`Failed to add nonce to cache: ${error}`);
}
}
async cleanup() {
// Redis handles expiry automatically, so this is a no-op
// This method exists to satisfy the interface
}
}
exports.RedisNonceCache = RedisNonceCache;