@clduab11/gemini-flow
Version:
Revolutionary AI agent swarm coordination platform with Google Services integration, multimedia processing, and production-ready monitoring. Features 8 Google AI services, quantum computing capabilities, and enterprise-grade security.
381 lines (324 loc) • 10.2 kB
text/typescript
/**
* Security Utilities
*
* Helper functions for security validation, encryption, and audit
*/
import crypto from "crypto";
export class SecurityUtils {
/**
* Sanitize sensitive data from objects
*/
static sanitizeObject(
obj: any,
sensitiveFields: string[] = [
"password",
"token",
"key",
"secret",
"credential",
"authorization",
"auth",
"apiKey",
"webhook",
],
): any {
if (!obj || typeof obj !== "object") return obj;
const sanitized = Array.isArray(obj) ? [] : {};
for (const [key, value] of Object.entries(obj)) {
const isSensitive = sensitiveFields.some((field) =>
key.toLowerCase().includes(field.toLowerCase()),
);
if (isSensitive && typeof value === "string") {
(sanitized as any)[key] = "[REDACTED]";
} else if (typeof value === "object" && value !== null) {
(sanitized as any)[key] = this.sanitizeObject(value, sensitiveFields);
} else {
(sanitized as any)[key] = value;
}
}
return sanitized;
}
/**
* Generate cryptographic signature for data integrity
*/
static generateSignature(data: string, secret?: string): string {
const key = secret || process.env.GEMINI_FLOW_SECRET || "default-secret";
return crypto.createHmac("sha256", key).update(data).digest("hex");
}
/**
* Verify cryptographic signature
*/
static verifySignature(
data: string,
signature: string,
secret?: string,
): boolean {
const expectedSignature = this.generateSignature(data, secret);
return crypto.timingSafeEqual(
Buffer.from(signature, "hex"),
Buffer.from(expectedSignature, "hex"),
);
}
/**
* Generate secure random token
*/
static generateSecureToken(length: number = 32): string {
return crypto.randomBytes(length).toString("hex");
}
/**
* Hash sensitive data for storage
*/
static hashSensitiveData(data: string, salt?: string): string {
const actualSalt = salt || crypto.randomBytes(16).toString("hex");
const hash = crypto.pbkdf2Sync(data, actualSalt, 10000, 64, "sha512");
return `${actualSalt}:${hash.toString("hex")}`;
}
/**
* Verify hashed data
*/
static verifyHashedData(data: string, hashedData: string): boolean {
const [salt, hash] = hashedData.split(":");
const expectedHash = crypto.pbkdf2Sync(data, salt, 10000, 64, "sha512");
return crypto.timingSafeEqual(Buffer.from(hash, "hex"), expectedHash);
}
/**
* Validate URL security (HTTPS, no malicious patterns)
*/
static validateUrlSecurity(url: string): { valid: boolean; reason?: string } {
try {
const parsedUrl = new URL(url);
if (parsedUrl.protocol !== "https:") {
return { valid: false, reason: "URL must use HTTPS" };
}
// Check for suspicious patterns
const suspiciousPatterns = [
/localhost/i,
/127\.0\.0\.1/,
/0\.0\.0\.0/,
/\.\./,
/[<>'"]/,
];
for (const pattern of suspiciousPatterns) {
if (pattern.test(url)) {
return { valid: false, reason: "URL contains suspicious patterns" };
}
}
return { valid: true };
} catch (error) {
return { valid: false, reason: "Invalid URL format" };
}
}
/**
* Rate limiting implementation
*/
static createRateLimiter(maxRequests: number, windowMs: number) {
const requests = new Map<string, number[]>();
return (identifier: string): boolean => {
const now = Date.now();
const windowStart = now - windowMs;
// Get existing requests for this identifier
const userRequests = requests.get(identifier) || [];
// Filter out requests outside the window
const validRequests = userRequests.filter((time) => time > windowStart);
// Check if under limit
if (validRequests.length >= maxRequests) {
return false;
}
// Add new request
validRequests.push(now);
requests.set(identifier, validRequests);
return true;
};
}
/**
* Input validation and sanitization
*/
static validateInput(
input: any,
rules: {
type?: "string" | "number" | "boolean" | "object";
minLength?: number;
maxLength?: number;
pattern?: RegExp;
required?: boolean;
allowedValues?: any[];
},
): { valid: boolean; sanitized?: any; error?: string } {
if (rules.required && (input === undefined || input === null)) {
return { valid: false, error: "Field is required" };
}
if (input === undefined || input === null) {
return { valid: true, sanitized: input };
}
// Type validation
if (rules.type && typeof input !== rules.type) {
return {
valid: false,
error: `Expected ${rules.type}, got ${typeof input}`,
};
}
// String-specific validations
if (typeof input === "string") {
if (rules.minLength && input.length < rules.minLength) {
return { valid: false, error: `Minimum length is ${rules.minLength}` };
}
if (rules.maxLength && input.length > rules.maxLength) {
return { valid: false, error: `Maximum length is ${rules.maxLength}` };
}
if (rules.pattern && !rules.pattern.test(input)) {
return { valid: false, error: "Input does not match required pattern" };
}
// Sanitize string
const sanitized = input
.replace(/[<>]/g, "") // Remove potential HTML
.trim();
return { valid: true, sanitized };
}
// Allowed values validation
if (rules.allowedValues && !rules.allowedValues.includes(input)) {
return {
valid: false,
error: `Value must be one of: ${rules.allowedValues.join(", ")}`,
};
}
return { valid: true, sanitized: input };
}
/**
* Security audit logger
*/
static createSecurityAuditLogger() {
const auditEvents: Array<{
timestamp: Date;
level: "info" | "warning" | "error" | "critical";
event: string;
details: any;
signature: string;
}> = [];
return {
log: (
level: "info" | "warning" | "error" | "critical",
event: string,
details: any = {},
) => {
const sanitizedDetails = this.sanitizeObject(details);
const signature = this.generateSignature(
`${level}:${event}:${JSON.stringify(sanitizedDetails)}`,
);
auditEvents.push({
timestamp: new Date(),
level,
event,
details: sanitizedDetails,
signature,
});
// Keep only last 1000 events
if (auditEvents.length > 1000) {
auditEvents.splice(0, auditEvents.length - 1000);
}
},
getEvents: (level?: string, limit: number = 100) => {
let filtered = auditEvents;
if (level) {
filtered = auditEvents.filter((event) => event.level === level);
}
return filtered.slice(-limit);
},
verifyIntegrity: () => {
return auditEvents.every((event) => {
const data = `${event.level}:${event.event}:${JSON.stringify(event.details)}`;
return this.verifySignature(data, event.signature);
});
},
};
}
/**
* Encryption utilities for sensitive data
*/
static createEncryption(key?: string) {
const encryptionKey =
key ||
process.env.GEMINI_FLOW_ENCRYPTION_KEY ||
"default-key-32-chars-long-please!";
const algorithm = "aes-256-gcm";
return {
encrypt: (text: string): string => {
const iv = crypto.randomBytes(16);
const cipher = crypto.createCipheriv(
"aes-256-gcm",
Buffer.from(encryptionKey).subarray(0, 32),
iv,
);
cipher.setAAD(Buffer.from("gemini-flow", "utf8"));
let encrypted = cipher.update(text, "utf8", "hex");
encrypted += cipher.final("hex");
const authTag = cipher.getAuthTag();
return `${iv.toString("hex")}:${authTag.toString("hex")}:${encrypted}`;
},
decrypt: (encryptedText: string): string => {
const [ivHex, authTagHex, encrypted] = encryptedText.split(":");
const iv = Buffer.from(ivHex, "hex");
const authTag = Buffer.from(authTagHex, "hex");
const decipher = crypto.createDecipheriv(
"aes-256-gcm",
Buffer.from(encryptionKey).subarray(0, 32),
iv,
);
decipher.setAAD(Buffer.from("gemini-flow", "utf8"));
decipher.setAuthTag(authTag);
let decrypted = decipher.update(encrypted, "hex", "utf8");
decrypted += decipher.final("utf8");
return decrypted;
},
};
}
/**
* Security policy enforcement
*/
static enforceSecurityPolicy(
action: string,
resource: string,
userContext: any,
policy: any,
): {
allowed: boolean;
reason?: string;
requiredPermissions?: string[];
} {
// Check if action is allowed for resource
const resourcePolicy = policy.resources?.[resource];
if (resourcePolicy && !resourcePolicy.allowedActions?.includes(action)) {
return {
allowed: false,
reason: `Action '${action}' not allowed for resource '${resource}'`,
};
}
// Check user permissions
const requiredPermissions = resourcePolicy?.permissions?.[action] || [];
const userPermissions = userContext.permissions || [];
const hasAllPermissions = requiredPermissions.every((perm: string) =>
userPermissions.includes(perm),
);
if (!hasAllPermissions) {
return {
allowed: false,
reason: "Insufficient permissions",
requiredPermissions,
};
}
// Check rate limits
if (policy.rateLimits && policy.rateLimits[action]) {
const rateLimit = policy.rateLimits[action];
const rateLimiter = this.createRateLimiter(
rateLimit.max,
rateLimit.windowMs,
);
if (!rateLimiter(userContext.id)) {
return {
allowed: false,
reason: "Rate limit exceeded",
};
}
}
return { allowed: true };
}
}