Merge krystie-improvements into main

Resolves 24 conflicts between Hermes (DC-008/009/010 + response-helper
envelope standardization) and Krystie (DC-005 src/ refactor path fixes,
DC-006 TOTP integration, DC-007 new test suites, cloud backup
destinations).

Conflict resolutions:
- src/utils/logging.js:    took ours (consumers depend on logError/
                            safeErrorMessage/createLogger exports)
- src/config/site.js:      merged (her factored validateAndLogConfig +
                            applyConfigFields helpers)
- src/context/dns.js:      took hers (admin/readonly role iteration for
                            write operations)
- src/utilities/backup-
  manager.js:              took hers (Dropbox/WebDAV/SFTP cloud feature)
- status/dist/*, status/
  sw.js:                   took hers (minified bundles + newer SW cache)

Additional fix (post-merge regression):
- src/monitoring/health-checker.js: fixed DC-005 path miss —
  'require(./platform-paths)' → 'require(../../platform-paths)'

Test status: 921/922 passing. One known failure in logging.test.js
(async file-handle timing) tracked as follow-up.
This commit is contained in:
Hermes
2026-06-25 16:43:10 -07:00
171 changed files with 11759 additions and 1006 deletions
+45 -7
View File
@@ -1,8 +1,14 @@
/**
* DNS context - Technitium DNS operations and token management
*
* DEPRECATED: This module is kept for backward compatibility.
* New code should use src/context/provider-dns.js which supports multiple providers.
*
* This module now delegates to the provider system internally.
*/
const { TIMEOUTS, SESSION_TTL, CADDY } = require('../../constants');
const { createCache, CACHE_CONFIGS } = require('../../cache-config');
const { TIMEOUTS, SESSION_TTL, CADDY } = require('../utilities/constants');
const { createCache, CACHE_CONFIGS } = require('../utilities/cache-config');
const { createProviderDnsContext } = require('./provider-dns');
// DNS token management
let dnsToken = process.env.DNS_ADMIN_TOKEN || '';
@@ -52,9 +58,9 @@ async function refreshDnsToken(username, password, server, fetchT, log) {
headers: {
'Accept': 'application/json',
'Content-Type': 'application/x-www-form-urlencoded'
},
timeout: 10000
}
}
},
10000
);
const result = await response.json();
@@ -95,6 +101,20 @@ async function refreshWithPerServerCredentials(dnsId, serverIp, credentialManage
/**
* Ensure we have a valid DNS token (auto-refresh if needed)
*/
async function tryCredentialPair(dnsId, role, primaryIp, siteConfig, credentialManager, fetchT, log) {
try {
const username = await credentialManager.retrieve(`dns.${dnsId}.${role}.username`);
const password = await credentialManager.retrieve(`dns.${dnsId}.${role}.password`);
if (username && password) {
return await refreshDnsToken(username, password, primaryIp, fetchT, log);
}
return null;
} catch (err) {
log.error('dns', `Per-server ${role} credential error`, { dnsId, error: err.message });
return null;
}
}
async function ensureValidDnsToken(siteConfig, credentialManager, fetchT, log) {
// Check if token is valid and not expired
if (dnsToken && dnsTokenExpiry && new Date() < new Date(dnsTokenExpiry)) {
@@ -105,8 +125,10 @@ async function ensureValidDnsToken(siteConfig, credentialManager, fetchT, log) {
if (primaryIp) {
const dnsId = dnsIpToDnsId(primaryIp, siteConfig);
if (dnsId) {
const result = await refreshWithPerServerCredentials(dnsId, primaryIp, credentialManager, fetchT, log);
if (result) return result;
for (const role of ['admin', 'readonly']) {
const result = await tryCredentialPair(dnsId, role, primaryIp, siteConfig, credentialManager, fetchT, log);
if (result) return result;
}
}
}
@@ -291,6 +313,10 @@ function invalidateTokenForServer(serverIp) {
}
function createDnsContext(siteConfig, buildDomain, credentialManager, fetchT, httpsAgent, log, DNS_CREDENTIALS_FILE) {
// Create the new provider-aware context
const providerCtx = createProviderDnsContext(siteConfig, buildDomain, credentialManager, fetchT, httpsAgent, log, DNS_CREDENTIALS_FILE);
// Legacy Technitium-specific wrappers (kept for backward compat)
const ensureToken = () => ensureValidDnsToken(siteConfig, credentialManager, fetchT, log);
const require = (providedToken) => requireDnsToken(providedToken, siteConfig, credentialManager, fetchT, log);
const getForServer = (server, role) => getTokenForServer(server, siteConfig, credentialManager, fetchT, log, role);
@@ -299,6 +325,7 @@ function createDnsContext(siteConfig, buildDomain, credentialManager, fetchT, ht
const call = (server, apiPath, params) => callDns(server, apiPath, params, fetchT, httpsAgent);
return {
// Legacy Technitium-specific interface (unchanged)
call,
buildUrl: buildDnsUrl,
requireToken: require,
@@ -312,6 +339,17 @@ function createDnsContext(siteConfig, buildDomain, credentialManager, fetchT, ht
invalidateTokenForServer,
refresh,
credentialsFile: DNS_CREDENTIALS_FILE,
// Provider-aware methods (new)
getProviderId: providerCtx.getProviderId,
getActiveProvider: providerCtx.getActiveProvider,
getAvailableProviders: providerCtx.getAvailableProviders,
supportsCapability: providerCtx.supportsCapability,
// Universal DNS helpers (delegated to provider context)
universalCreateRecord: providerCtx.universalCreateRecord,
universalDeleteRecord: providerCtx.universalDeleteRecord,
universalResolveRecord: providerCtx.universalResolveRecord,
};
}