Sync DNS2 production changes - removed obsolete test suite and refactored structure
This commit is contained in:
@@ -34,7 +34,7 @@ module.exports = function(ctx) {
|
||||
dashcaddyVersion: '1.0.0',
|
||||
files: {},
|
||||
themes: {},
|
||||
assets: {},
|
||||
assets: {}
|
||||
};
|
||||
|
||||
// Collect all configuration files (encryption key now included for self-contained restore)
|
||||
@@ -48,7 +48,7 @@ module.exports = function(ctx) {
|
||||
{ key: 'encryptionKey', path: ENCRYPTION_KEY_FILE, required: false },
|
||||
{ key: 'totpConfig', path: ctx.TOTP_CONFIG_FILE, required: false },
|
||||
{ key: 'tailscaleConfig', path: ctx.TAILSCALE_CONFIG_FILE, required: false },
|
||||
{ key: 'notifications', path: ctx.NOTIFICATIONS_FILE, required: false },
|
||||
{ key: 'notifications', path: ctx.NOTIFICATIONS_FILE, required: false }
|
||||
];
|
||||
|
||||
for (const file of filesToBackup) {
|
||||
@@ -59,12 +59,12 @@ module.exports = function(ctx) {
|
||||
try {
|
||||
backup.files[file.key] = {
|
||||
type: 'json',
|
||||
data: JSON.parse(content),
|
||||
data: JSON.parse(content)
|
||||
};
|
||||
} catch {
|
||||
backup.files[file.key] = {
|
||||
type: 'text',
|
||||
data: content,
|
||||
data: content
|
||||
};
|
||||
}
|
||||
} else if (file.required) {
|
||||
@@ -85,7 +85,7 @@ module.exports = function(ctx) {
|
||||
const otpauth = authenticator.keyuri('user', 'DashCaddy', secret);
|
||||
const qrDataUrl = await QRCode.toDataURL(otpauth, {
|
||||
width: 256, margin: 2,
|
||||
color: { dark: '#000000', light: '#ffffff' },
|
||||
color: { dark: '#000000', light: '#ffffff' }
|
||||
});
|
||||
backup.totp = { qrCode: qrDataUrl, issuer: 'DashCaddy' };
|
||||
}
|
||||
@@ -140,7 +140,7 @@ module.exports = function(ctx) {
|
||||
valid: true,
|
||||
version: backup.version,
|
||||
exportedAt: backup.exportedAt,
|
||||
files: {},
|
||||
files: {}
|
||||
};
|
||||
|
||||
// Check each file in the backup
|
||||
@@ -154,7 +154,7 @@ module.exports = function(ctx) {
|
||||
encryptionKey: { path: ENCRYPTION_KEY_FILE, description: 'Encryption key (for credentials)' },
|
||||
totpConfig: { path: ctx.TOTP_CONFIG_FILE, description: 'TOTP authentication config' },
|
||||
tailscaleConfig: { path: ctx.TAILSCALE_CONFIG_FILE, description: 'Tailscale config' },
|
||||
notifications: { path: ctx.NOTIFICATIONS_FILE, description: 'Notification settings' },
|
||||
notifications: { path: ctx.NOTIFICATIONS_FILE, description: 'Notification settings' }
|
||||
};
|
||||
|
||||
for (const [key, value] of Object.entries(backup.files)) {
|
||||
@@ -167,7 +167,7 @@ module.exports = function(ctx) {
|
||||
inBackup: true,
|
||||
currentExists,
|
||||
action: currentExists ? 'overwrite' : 'create',
|
||||
type: value.type,
|
||||
type: value.type
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -204,7 +204,7 @@ module.exports = function(ctx) {
|
||||
// Require TOTP verification for restores that include security-sensitive files
|
||||
const sensitiveKeys = ['credentials', 'totpConfig', 'encryptionKey'];
|
||||
const restoresSensitive = sensitiveKeys.some(key =>
|
||||
backup.files[key] && backup.files[key].type !== 'missing' && !(options.skip || []).includes(key),
|
||||
backup.files[key] && backup.files[key].type !== 'missing' && !(options.skip || []).includes(key)
|
||||
);
|
||||
if (restoresSensitive && ctx.totpConfig.enabled && ctx.totpConfig.isSetUp) {
|
||||
if (!totpCode || !/^\d{6}$/.test(totpCode)) {
|
||||
@@ -223,7 +223,7 @@ module.exports = function(ctx) {
|
||||
const results = {
|
||||
restored: [],
|
||||
skipped: [],
|
||||
errors: [],
|
||||
errors: []
|
||||
};
|
||||
|
||||
const ENCRYPTION_KEY_FILE = process.env.ENCRYPTION_KEY_FILE || path.join(path.dirname(ctx.SERVICES_FILE), '.encryption-key');
|
||||
@@ -236,7 +236,7 @@ module.exports = function(ctx) {
|
||||
encryptionKey: ENCRYPTION_KEY_FILE,
|
||||
totpConfig: ctx.TOTP_CONFIG_FILE,
|
||||
tailscaleConfig: ctx.TAILSCALE_CONFIG_FILE,
|
||||
notifications: ctx.NOTIFICATIONS_FILE,
|
||||
notifications: ctx.NOTIFICATIONS_FILE
|
||||
};
|
||||
|
||||
// Restore each file
|
||||
@@ -286,7 +286,7 @@ module.exports = function(ctx) {
|
||||
const loadResponse = await ctx.fetchT(`${ctx.caddy.adminUrl}/load`, {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': CADDY.CONTENT_TYPE },
|
||||
body: caddyContent,
|
||||
body: caddyContent
|
||||
});
|
||||
|
||||
if (loadResponse.ok) {
|
||||
@@ -345,7 +345,7 @@ module.exports = function(ctx) {
|
||||
if (!fs.existsSync(THEMES_DIR)) fs.mkdirSync(THEMES_DIR, { recursive: true });
|
||||
for (const [slug, data] of Object.entries(backup.themes)) {
|
||||
if (/^[a-z0-9-]+$/.test(slug)) {
|
||||
fs.writeFileSync(path.join(THEMES_DIR, `${slug }.json`), JSON.stringify(data, null, 2), 'utf8');
|
||||
fs.writeFileSync(path.join(THEMES_DIR, slug + '.json'), JSON.stringify(data, null, 2), 'utf8');
|
||||
}
|
||||
}
|
||||
results.restored.push(`themes:${Object.keys(backup.themes).length}`);
|
||||
@@ -376,7 +376,7 @@ module.exports = function(ctx) {
|
||||
message: success
|
||||
? `Restored ${results.restored.length} file(s) successfully`
|
||||
: `Restore completed with ${results.errors.length} error(s)`,
|
||||
results,
|
||||
results
|
||||
});
|
||||
|
||||
ctx.log.info('backup', 'Backup restore completed', { restored: results.restored.length, errors: results.errors.length });
|
||||
|
||||
Reference in New Issue
Block a user