Files
vendoo/app/core/security/secret-contract.mjs
T

52 lines
2.4 KiB
JavaScript

export const SECRET_DEFINITIONS = Object.freeze({
ANTHROPIC_API_KEY: { label: 'Anthropic API-Key', category: 'AI', editable: true },
OPENAI_API_KEY: { label: 'OpenAI API-Key', category: 'AI', editable: true },
OPENROUTER_API_KEY: { label: 'OpenRouter API-Key', category: 'AI', editable: true },
ETSY_API_KEY: { label: 'Etsy API-Key', category: 'Marktplatz', editable: true },
ETSY_ACCESS_TOKEN: { label: 'Etsy Access Token', category: 'Marktplatz', editable: false },
ETSY_REFRESH_TOKEN: { label: 'Etsy Refresh Token', category: 'Marktplatz', editable: false },
EBAY_CLIENT_SECRET: { label: 'eBay Client Secret', category: 'Marktplatz', editable: true },
EBAY_ACCESS_TOKEN: { label: 'eBay Access Token', category: 'Marktplatz', editable: false },
EBAY_REFRESH_TOKEN: { label: 'eBay Refresh Token', category: 'Marktplatz', editable: false },
LOCAL_IMAGE_TOKEN: { label: 'FLUX Dienst-Token', category: 'FLUX', editable: true },
SMTP_PASS: { label: 'SMTP-Passwort', category: 'E-Mail', editable: true },
VENDOO_SETUP_TOKEN: { label: 'Ersteinrichtungs-Token', category: 'System', editable: false },
COOLIFY_API_TOKEN: { label: 'Coolify API-Token', category: 'Deployment', editable: true },
COOLIFY_DEPLOY_WEBHOOK_URL: { label: 'Coolify Deploy-Webhook', category: 'Deployment', editable: true },
});
export const SECRET_NAMES = Object.freeze(Object.keys(SECRET_DEFINITIONS));
const SECRET_NAME = /^[A-Z][A-Z0-9_]{2,80}$/;
export function validateSecretName(name) {
const normalized = String(name || '').trim();
if (!SECRET_NAME.test(normalized) || !SECRET_DEFINITIONS[normalized]) {
const error = new Error(`Unbekanntes Secret: ${normalized || '(leer)'}`);
error.code = 'SECRET_NAME_INVALID';
throw error;
}
return normalized;
}
export function validateSecretValue(value) {
const normalized = String(value ?? '');
if (/\r|\n|\0/.test(normalized)) {
const error = new Error('Secrets dürfen keine Zeilenumbrüche oder Nullbytes enthalten.');
error.code = 'SECRET_VALUE_INVALID';
throw error;
}
if (Buffer.byteLength(normalized, 'utf8') > 16_384) {
const error = new Error('Secret ist zu groß.');
error.code = 'SECRET_VALUE_TOO_LARGE';
throw error;
}
return normalized;
}
export function maskSecret(value) {
const text = String(value || '');
if (!text) return '';
if (text.length <= 4) return '••••';
return `••••••••${text.slice(-4)}`;
}