98 lines
2.7 KiB
JavaScript
98 lines
2.7 KiB
JavaScript
const fs = require('fs');
|
|
const path = require('path');
|
|
|
|
const SECRETS_PATH = process.env.SECRETS_PATH || path.join(__dirname, '..', 'secrets.json');
|
|
|
|
const SECRET_TYPES = ['api_token', 'ssl_certificate', 'password', 'generic'];
|
|
|
|
function load() {
|
|
try {
|
|
return JSON.parse(fs.readFileSync(SECRETS_PATH, 'utf8'));
|
|
} catch {
|
|
return [];
|
|
}
|
|
}
|
|
|
|
function save(secrets) {
|
|
fs.writeFileSync(SECRETS_PATH, JSON.stringify(secrets, null, 2), 'utf8');
|
|
}
|
|
|
|
function getAll() {
|
|
return load();
|
|
}
|
|
|
|
function getById(id) {
|
|
return load().find(s => s.id === id) ?? null;
|
|
}
|
|
|
|
function create(data) {
|
|
const secrets = load();
|
|
const secret = {
|
|
id: Date.now().toString(),
|
|
name: data.name,
|
|
type: data.type || 'generic',
|
|
description: data.description || '',
|
|
expires_at: data.expires_at,
|
|
warning_days: Number(data.warning_days) || 30,
|
|
notes: data.notes || '',
|
|
created_at: new Date().toISOString(),
|
|
updated_at: new Date().toISOString(),
|
|
};
|
|
secrets.push(secret);
|
|
save(secrets);
|
|
return secret;
|
|
}
|
|
|
|
function update(id, data) {
|
|
const secrets = load();
|
|
const idx = secrets.findIndex(s => s.id === id);
|
|
if (idx === -1) throw new Error('Secret not found');
|
|
secrets[idx] = {
|
|
...secrets[idx],
|
|
name: data.name ?? secrets[idx].name,
|
|
type: data.type ?? secrets[idx].type,
|
|
description: data.description ?? secrets[idx].description,
|
|
expires_at: data.expires_at ?? secrets[idx].expires_at,
|
|
warning_days: data.warning_days !== undefined ? Number(data.warning_days) : secrets[idx].warning_days,
|
|
notes: data.notes ?? secrets[idx].notes,
|
|
updated_at: new Date().toISOString(),
|
|
};
|
|
save(secrets);
|
|
return secrets[idx];
|
|
}
|
|
|
|
function remove(id) {
|
|
const secrets = load();
|
|
const filtered = secrets.filter(s => s.id !== id);
|
|
if (filtered.length === secrets.length) throw new Error('Secret not found');
|
|
save(filtered);
|
|
}
|
|
|
|
/**
|
|
* Returns secrets grouped by expiry status.
|
|
* Status: 'expired' | 'warning' | 'ok'
|
|
*/
|
|
function getStatus() {
|
|
const secrets = load();
|
|
const now = new Date();
|
|
|
|
return secrets.map(s => {
|
|
const expiry = new Date(s.expires_at);
|
|
const daysLeft = Math.ceil((expiry - now) / (1000 * 60 * 60 * 24));
|
|
let status;
|
|
if (daysLeft < 0) status = 'expired';
|
|
else if (daysLeft <= s.warning_days) status = 'warning';
|
|
else status = 'ok';
|
|
return { ...s, daysLeft, status };
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Returns secrets that are expired or within their warning window.
|
|
*/
|
|
function getExpiring() {
|
|
return getStatus().filter(s => s.status !== 'ok');
|
|
}
|
|
|
|
module.exports = { SECRET_TYPES, getAll, getById, create, update, remove, getStatus, getExpiring };
|