ubon
Version:
Security scanner for AI-generated React/Next.js and Python apps. Catches hardcoded secrets, accessibility issues, and vulnerabilities that traditional linters miss.
139 lines (138 loc) • 4.28 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.CACHE_TTL = exports.FileCache = void 0;
exports.createOSVCacheKey = createOSVCacheKey;
const crypto_1 = require("crypto");
const fs_1 = require("fs");
const path_1 = require("path");
const os_1 = require("os");
class FileCache {
constructor(name) {
// Use ~/.ubon/cache/ directory
this.cacheDir = (0, path_1.join)((0, os_1.homedir)(), '.ubon', 'cache', name);
this.ensureCacheDir();
}
ensureCacheDir() {
try {
(0, fs_1.mkdirSync)(this.cacheDir, { recursive: true });
}
catch (error) {
// Cache directory creation failed, will fall back to no caching
}
}
getCacheFilePath(key) {
// Create a safe filename from the key
const hash = (0, crypto_1.createHash)('sha256').update(key).digest('hex');
return (0, path_1.join)(this.cacheDir, `${hash}.json`);
}
/**
* Get cached data if it exists and hasn't expired
*/
get(key) {
try {
const filePath = this.getCacheFilePath(key);
if (!(0, fs_1.existsSync)(filePath)) {
return null;
}
const content = (0, fs_1.readFileSync)(filePath, 'utf8');
const entry = JSON.parse(content);
// Check if expired
const now = Date.now();
if (now - entry.timestamp > entry.ttl) {
return null;
}
return entry.data;
}
catch (error) {
// Cache read failed, return null
return null;
}
}
/**
* Store data in cache with TTL
*/
set(key, data, ttlMs) {
try {
const filePath = this.getCacheFilePath(key);
const entry = {
data,
timestamp: Date.now(),
ttl: ttlMs
};
(0, fs_1.writeFileSync)(filePath, JSON.stringify(entry), 'utf8');
}
catch (error) {
// Cache write failed, silently continue
}
}
/**
* Clear all cached entries (cleanup utility)
*/
clear() {
try {
const fs = require('fs');
if ((0, fs_1.existsSync)(this.cacheDir)) {
const files = fs.readdirSync(this.cacheDir);
for (const file of files) {
if (file.endsWith('.json')) {
fs.unlinkSync((0, path_1.join)(this.cacheDir, file));
}
}
}
}
catch (error) {
// Clear failed, silently continue
}
}
/**
* Remove expired entries (maintenance utility)
*/
cleanup() {
try {
const fs = require('fs');
if (!(0, fs_1.existsSync)(this.cacheDir))
return;
const files = fs.readdirSync(this.cacheDir);
const now = Date.now();
for (const file of files) {
if (!file.endsWith('.json'))
continue;
try {
const filePath = (0, path_1.join)(this.cacheDir, file);
const content = (0, fs_1.readFileSync)(filePath, 'utf8');
const entry = JSON.parse(content);
if (now - entry.timestamp > entry.ttl) {
fs.unlinkSync(filePath);
}
}
catch {
// Skip invalid cache files
}
}
}
catch (error) {
// Cleanup failed, silently continue
}
}
}
exports.FileCache = FileCache;
/**
* Create a cache key for OSV queries
*/
function createOSVCacheKey(queries) {
// Sort queries to ensure consistent cache keys
const sortedQueries = queries
.map(q => `${q.package.ecosystem}:${q.package.name}@${q.version}`)
.sort()
.join('|');
return `osv-batch:${sortedQueries}`;
}
/**
* Default TTL values
*/
exports.CACHE_TTL = {
OSV_VULNERABILITIES: 24 * 60 * 60 * 1000, // 24 hours
SHORT: 60 * 60 * 1000, // 1 hour
MEDIUM: 6 * 60 * 60 * 1000, // 6 hours
LONG: 7 * 24 * 60 * 60 * 1000 // 7 days
};