@dharshansr/gitgenius
Version:
AI-powered commit message generator with enhanced features
183 lines • 5.7 kB
JavaScript
import { SecurityUtils } from '../utils/SecurityUtils.js';
export const DEFAULT_SECURITY_CONFIG = {
enforceHttps: true,
verifyCertificates: true,
rateLimitEnabled: true,
maxRequestsPerMinute: 60,
apiKeyRotationEnabled: false,
apiKeyRotationDays: 90,
requestTimeout: 30000, // 30 seconds
maxRetries: 3,
strictInputValidation: true,
maxInputLength: 100000,
auditLogEnabled: true,
logSensitiveData: false
};
/**
* API Key rotation manager
*/
export class ApiKeyRotationManager {
constructor() {
this.rotationSchedule = new Map();
}
/**
* Check if API key needs rotation
*/
shouldRotate(keyId, rotationDays) {
const lastRotation = this.rotationSchedule.get(keyId);
if (!lastRotation) {
// No rotation recorded, should rotate
return true;
}
const daysSinceRotation = (Date.now() - lastRotation.getTime()) / (1000 * 60 * 60 * 24);
return daysSinceRotation >= rotationDays;
}
/**
* Record API key rotation
*/
recordRotation(keyId) {
this.rotationSchedule.set(keyId, new Date());
}
/**
* Get days until next rotation
*/
getDaysUntilRotation(keyId, rotationDays) {
const lastRotation = this.rotationSchedule.get(keyId);
if (!lastRotation) {
return 0;
}
const daysSinceRotation = (Date.now() - lastRotation.getTime()) / (1000 * 60 * 60 * 24);
return Math.max(0, Math.ceil(rotationDays - daysSinceRotation));
}
/**
* Generate rotation reminder message
*/
getRotationReminder(keyId, rotationDays) {
const daysUntil = this.getDaysUntilRotation(keyId, rotationDays);
if (daysUntil === 0) {
return '⚠️ API key rotation is due. Please rotate your API key.';
}
else if (daysUntil <= 7) {
return `⚠️ API key rotation is due in ${daysUntil} days.`;
}
return null;
}
}
/**
* Security manager for GitGenius
*/
export class SecurityManager {
constructor(config = {}) {
this.config = { ...DEFAULT_SECURITY_CONFIG, ...config };
this.rotationManager = new ApiKeyRotationManager();
}
/**
* Validate URL and enforce HTTPS
*/
validateUrl(url) {
if (this.config.enforceHttps && !SecurityUtils.validateSecureUrl(url)) {
throw new Error('HTTPS is required for all API communications');
}
}
/**
* Check if request should be rate limited
*/
checkRateLimit(identifier) {
if (!this.config.rateLimitEnabled) {
return true;
}
const windowMs = 60000; // 1 minute
return SecurityUtils.checkRateLimit(identifier, this.config.maxRequestsPerMinute, windowMs);
}
/**
* Get secure request configuration
*/
getSecureRequestConfig(apiKey) {
const config = {
timeout: this.config.requestTimeout,
headers: SecurityUtils.getSecureHeaders(apiKey)
};
// Add HTTPS agent with certificate verification
if (this.config.verifyCertificates) {
// Certificate verification is enabled by default in axios
// We just need to ensure rejectUnauthorized is not set to false
config.httpsAgent = { rejectUnauthorized: true };
}
return config;
}
/**
* Validate and sanitize input
*/
sanitizeInput(input) {
if (this.config.strictInputValidation) {
if (input.length > this.config.maxInputLength) {
throw new Error(`Input exceeds maximum length of ${this.config.maxInputLength}`);
}
return SecurityUtils.sanitizeInput(input);
}
return input;
}
/**
* Check API key rotation status
*/
checkApiKeyRotation(keyId) {
if (!this.config.apiKeyRotationEnabled) {
return null;
}
return this.rotationManager.getRotationReminder(keyId, this.config.apiKeyRotationDays);
}
/**
* Record API key rotation
*/
recordApiKeyRotation(keyId) {
this.rotationManager.recordRotation(keyId);
}
/**
* Get security configuration
*/
getConfig() {
return { ...this.config };
}
/**
* Update security configuration
*/
updateConfig(updates) {
this.config = { ...this.config, ...updates };
}
/**
* Audit log for security-sensitive operations
*/
auditLog(operation, details) {
if (!this.config.auditLogEnabled) {
return;
}
const logEntry = {
timestamp: new Date().toISOString(),
operation,
details: this.config.logSensitiveData
? details
: this.maskSensitiveDetails(details)
};
// In a production environment, this would write to a secure log file or service
console.log('[AUDIT]', JSON.stringify(logEntry));
}
/**
* Mask sensitive details in audit logs
*/
maskSensitiveDetails(details) {
const masked = {};
const sensitiveKeys = ['apiKey', 'token', 'password', 'secret', 'authorization'];
for (const [key, value] of Object.entries(details)) {
if (sensitiveKeys.some(sk => key.toLowerCase().includes(sk))) {
masked[key] = typeof value === 'string'
? SecurityUtils.maskSensitiveData(value)
: '***';
}
else {
masked[key] = value;
}
}
return masked;
}
}
//# sourceMappingURL=SecurityConfig.js.map