2026-02-14 09:53:14 +01:00
import assert from 'node:assert' ;
import BoxError from './boxerror.js' ;
import constants from './constants.js' ;
import crypto from 'node:crypto' ;
2026-02-14 15:43:24 +01:00
import dashboard from './dashboard.js' ;
import database from './database.js' ;
2026-02-14 09:53:14 +01:00
import debugModule from 'debug' ;
import eventlog from './eventlog.js' ;
2026-02-14 15:43:24 +01:00
import mailServer from './mailserver.js' ;
import notifications from './notifications.js' ;
import openssl from './openssl.js' ;
import reverseProxy from './reverseproxy.js' ;
2026-02-14 09:53:14 +01:00
import safe from 'safetydance' ;
import tld from 'tldjs' ;
2026-02-14 15:43:24 +01:00
import _ from './underscore.js' ;
import dnsBunny from './dns/bunny.js' ;
import dnsCloudflare from './dns/cloudflare.js' ;
import dnsDesec from './dns/desec.js' ;
import dnsDnsimple from './dns/dnsimple.js' ;
import dnsRoute53 from './dns/route53.js' ;
import dnsGcdns from './dns/gcdns.js' ;
import dnsDigitalocean from './dns/digitalocean.js' ;
import dnsGandi from './dns/gandi.js' ;
import dnsGodaddy from './dns/godaddy.js' ;
import dnsHetzner from './dns/hetzner.js' ;
import dnsHetznercloud from './dns/hetznercloud.js' ;
import dnsInwx from './dns/inwx.js' ;
import dnsLinode from './dns/linode.js' ;
import dnsVultr from './dns/vultr.js' ;
import dnsNamecom from './dns/namecom.js' ;
import dnsNamecheap from './dns/namecheap.js' ;
import dnsNetcup from './dns/netcup.js' ;
import dnsNoop from './dns/noop.js' ;
import dnsOvh from './dns/ovh.js' ;
import dnsManual from './dns/manual.js' ;
import dnsPorkbun from './dns/porkbun.js' ;
import dnsWildcard from './dns/wildcard.js' ;
2026-02-14 09:53:14 +01:00
const debug = debugModule ( 'box:domains' ) ;
2017-10-28 22:18:07 +02:00
2021-08-13 17:22:28 -07:00
const DOMAINS _FIELDS = [ 'domain' , 'zoneName' , 'provider' , 'configJson' , 'tlsConfigJson' , 'wellKnownJson' , 'fallbackCertificateJson' ] . join ( ',' ) ;
function postProcess ( data ) {
data . config = safe . JSON . parse ( data . configJson ) ;
delete data . configJson ;
data . tlsConfig = safe . JSON . parse ( data . tlsConfigJson ) ;
delete data . tlsConfigJson ;
data . wellKnown = safe . JSON . parse ( data . wellKnownJson ) ;
delete data . wellKnownJson ;
data . fallbackCertificate = safe . JSON . parse ( data . fallbackCertificateJson ) ;
delete data . fallbackCertificateJson ;
return data ;
}
2026-02-14 09:53:14 +01:00
const DNS _PROVIDERS = {
bunny : dnsBunny , cloudflare : dnsCloudflare , desec : dnsDesec , dnsimple : dnsDnsimple ,
route53 : dnsRoute53 , gcdns : dnsGcdns , digitalocean : dnsDigitalocean , gandi : dnsGandi ,
godaddy : dnsGodaddy , hetzner : dnsHetzner , hetznercloud : dnsHetznercloud , inwx : dnsInwx ,
linode : dnsLinode , vultr : dnsVultr , namecom : dnsNamecom , namecheap : dnsNamecheap ,
netcup : dnsNetcup , noop : dnsNoop , ovh : dnsOvh , manual : dnsManual ,
porkbun : dnsPorkbun , wildcard : dnsWildcard
} ;
2017-10-29 00:15:11 +02:00
// choose which subdomain backend we use for test purpose we use route53
function api ( provider ) {
assert . strictEqual ( typeof provider , 'string' ) ;
2026-02-14 09:53:14 +01:00
return DNS _PROVIDERS [ provider ] || null ;
2017-10-29 00:15:11 +02:00
}
2022-01-05 22:41:41 -08:00
async function verifyDomainConfig ( domainConfig , domain , zoneName , provider ) {
assert ( domainConfig && typeof domainConfig === 'object' ) ; // the dns config to test with
2017-10-29 00:15:11 +02:00
assert . strictEqual ( typeof domain , 'string' ) ;
assert . strictEqual ( typeof zoneName , 'string' ) ;
2018-01-09 14:46:38 -08:00
assert . strictEqual ( typeof provider , 'string' ) ;
2017-10-29 00:15:11 +02:00
2021-08-27 09:52:24 -07:00
const backend = api ( provider ) ;
2022-02-07 13:19:59 -08:00
if ( ! backend ) throw new BoxError ( BoxError . BAD _FIELD , 'Invalid provider' ) ;
2017-10-29 00:15:11 +02:00
2024-04-29 15:51:16 +02:00
const domainObject = { config : domainConfig , domain , zoneName } ;
2022-07-14 10:32:30 +05:30
const [ error , sanitizedConfig ] = await safe ( api ( provider ) . verifyDomainConfig ( domainObject ) ) ;
if ( error && error . reason === BoxError . ACCESS _DENIED ) throw new BoxError ( BoxError . BAD _FIELD , ` Access denied: ${ error . message } ` ) ;
if ( error && error . reason === BoxError . NOT _FOUND ) throw new BoxError ( BoxError . BAD _FIELD , ` Zone not found: ${ error . message } ` ) ;
if ( error && error . reason === BoxError . EXTERNAL _ERROR ) throw new BoxError ( BoxError . BAD _FIELD , ` Configuration error: ${ error . message } ` ) ;
if ( error ) throw error ;
2021-08-27 09:52:24 -07:00
2022-07-14 10:32:30 +05:30
return sanitizedConfig ;
2018-08-22 11:53:23 +02:00
}
2017-10-29 00:15:11 +02:00
2018-09-12 12:25:07 -07:00
function validateTlsConfig ( tlsConfig , dnsProvider ) {
2018-09-11 21:53:18 -07:00
assert . strictEqual ( typeof tlsConfig , 'object' ) ;
2018-09-12 12:25:07 -07:00
assert . strictEqual ( typeof dnsProvider , 'string' ) ;
switch ( tlsConfig . provider ) {
case 'letsencrypt-prod' :
case 'letsencrypt-staging' :
case 'fallback' :
break ;
default :
2022-02-07 13:19:59 -08:00
return new BoxError ( BoxError . BAD _FIELD , 'tlsConfig.provider must be fallback, letsencrypt-prod/staging' ) ;
2018-09-12 12:25:07 -07:00
}
2018-09-11 21:53:18 -07:00
2018-09-12 12:25:07 -07:00
if ( tlsConfig . wildcard ) {
2022-02-07 13:19:59 -08:00
if ( ! tlsConfig . provider . startsWith ( 'letsencrypt' ) ) return new BoxError ( BoxError . BAD _FIELD , 'wildcard can only be set with letsencrypt' ) ;
if ( dnsProvider === 'manual' || dnsProvider === 'noop' || dnsProvider === 'wildcard' ) return new BoxError ( BoxError . BAD _FIELD , 'wildcard cert requires a programmable DNS backend' ) ;
2018-09-11 21:53:18 -07:00
}
return null ;
}
2020-12-23 15:34:23 -08:00
function validateWellKnown ( wellKnown ) {
assert . strictEqual ( typeof wellKnown , 'object' ) ;
2026-02-25 05:55:14 +01:00
if ( wellKnown === null ) return null ;
for ( const key of Object . keys ( wellKnown ) ) {
if ( typeof wellKnown [ key ] !== 'string' ) return new BoxError ( BoxError . BAD _FIELD , ` well-known value for ${ key } must be a string ` ) ;
}
if ( wellKnown . carddav && wellKnown . carddav . includes ( '://' ) ) return new BoxError ( BoxError . BAD _FIELD , 'carddav must be a domain, not a URL' ) ;
if ( wellKnown . caldav && wellKnown . caldav . includes ( '://' ) ) return new BoxError ( BoxError . BAD _FIELD , 'caldav must be a domain, not a URL' ) ;
2020-12-23 15:34:23 -08:00
return null ;
}
2021-08-13 17:22:28 -07:00
async function add ( domain , data , auditSource ) {
2017-10-28 22:18:07 +02:00
assert . strictEqual ( typeof domain , 'string' ) ;
2018-11-10 00:43:46 -08:00
assert . strictEqual ( typeof data . zoneName , 'string' ) ;
assert . strictEqual ( typeof data . provider , 'string' ) ;
assert . strictEqual ( typeof data . config , 'object' ) ;
assert . strictEqual ( typeof data . fallbackCertificate , 'object' ) ;
assert . strictEqual ( typeof data . tlsConfig , 'object' ) ;
2017-10-28 22:18:07 +02:00
2024-04-29 13:05:07 +02:00
const { provider , config , tlsConfig } = data ;
2018-11-10 00:43:46 -08:00
2025-02-05 10:51:05 +01:00
if ( ! tld . isValid ( domain ) ) throw new BoxError ( BoxError . BAD _FIELD , 'Invalid domain' ) ;
2022-02-07 13:19:59 -08:00
if ( domain . endsWith ( '.' ) ) throw new BoxError ( BoxError . BAD _FIELD , 'Invalid domain' ) ;
2018-01-23 18:54:05 -08:00
2024-04-29 13:05:07 +02:00
let zoneName ;
if ( data . zoneName ) {
2025-02-05 10:51:05 +01:00
if ( ! tld . isValid ( data . zoneName ) ) throw new BoxError ( BoxError . BAD _FIELD , 'Invalid zoneName' ) ;
2024-04-29 15:51:16 +02:00
if ( data . zoneName . endsWith ( '.' ) ) throw new BoxError ( BoxError . BAD _FIELD , 'Invalid zoneName' ) ;
2024-04-29 13:05:07 +02:00
zoneName = data . zoneName ;
2018-01-23 18:54:05 -08:00
} else {
2018-01-24 14:17:26 -08:00
zoneName = tld . getDomain ( domain ) || domain ;
2018-01-23 18:54:05 -08:00
}
2017-10-28 22:18:07 +02:00
2024-04-29 13:05:07 +02:00
let fallbackCertificate ;
if ( data . fallbackCertificate ) {
2026-01-17 13:38:17 +01:00
await openssl . validateCertificate ( 'test' , domain , data . fallbackCertificate ) ;
2024-04-29 13:05:07 +02:00
fallbackCertificate = data . fallbackCertificate ;
2018-11-05 19:09:58 -08:00
} else {
2026-01-17 13:38:17 +01:00
fallbackCertificate = await openssl . generateCertificate ( domain ) ;
2017-11-09 02:06:36 +01:00
}
2018-09-12 12:25:07 -07:00
let error = validateTlsConfig ( tlsConfig , provider ) ;
2021-08-13 17:22:28 -07:00
if ( error ) throw error ;
2018-01-31 18:20:11 +01:00
2026-01-17 13:38:17 +01:00
const dkimKey = await openssl . generateDkimKey ( ) ;
2021-10-11 19:51:29 -07:00
2024-04-29 13:05:07 +02:00
let dkimSelector = data . dkimSelector ;
if ( ! data . dkimSelector ) {
2023-08-11 19:41:05 +05:30
const { domain : dashboardDomain } = await dashboard . getLocation ( ) ;
2021-02-24 11:40:23 -08:00
// create a unique suffix. this lets one add this domain can be added in another cloudron instance and not have their dkim selector conflict
2023-08-11 19:41:05 +05:30
const suffix = crypto . createHash ( 'sha256' ) . update ( dashboardDomain ) . digest ( 'hex' ) . substr ( 0 , 6 ) ;
2021-02-24 11:40:23 -08:00
dkimSelector = ` cloudron- ${ suffix } ` ;
}
2020-03-31 12:04:46 -07:00
2022-07-14 10:32:30 +05:30
const sanitizedConfig = await verifyDomainConfig ( config , domain , zoneName , provider ) ;
2017-10-28 23:23:58 +02:00
2022-07-14 10:32:30 +05:30
const queries = [
2021-08-13 17:22:28 -07:00
{ query : 'INSERT INTO domains (domain, zoneName, provider, configJson, tlsConfigJson, fallbackCertificateJson) VALUES (?, ?, ?, ?, ?, ?)' ,
2022-07-14 10:32:30 +05:30
args : [ domain , zoneName , provider , JSON . stringify ( sanitizedConfig ) , JSON . stringify ( tlsConfig ) , JSON . stringify ( fallbackCertificate ) ] } ,
2021-10-11 19:51:29 -07:00
{ query : 'INSERT INTO mail (domain, dkimKeyJson, dkimSelector) VALUES (?, ?, ?)' , args : [ domain , JSON . stringify ( dkimKey ) , dkimSelector || 'cloudron' ] } ,
2021-08-13 17:22:28 -07:00
] ;
2017-10-28 23:23:58 +02:00
2021-08-13 17:22:28 -07:00
[ error ] = await safe ( database . transaction ( queries ) ) ;
2025-09-29 11:55:15 +02:00
if ( error && error . sqlCode === 'ER_DUP_ENTRY' ) throw new BoxError ( BoxError . ALREADY _EXISTS , 'Domain already exists' ) ;
2021-08-13 17:22:28 -07:00
if ( error ) throw new BoxError ( BoxError . DATABASE _ERROR , error ) ;
2018-01-26 19:16:43 -08:00
2021-08-13 17:22:28 -07:00
await reverseProxy . setFallbackCertificate ( domain , fallbackCertificate ) ;
2020-03-31 12:04:46 -07:00
2022-02-24 20:04:46 -08:00
await eventlog . add ( eventlog . ACTION _DOMAIN _ADD , auditSource , { domain , zoneName , provider } ) ;
2021-08-13 17:22:28 -07:00
2023-08-04 20:54:16 +05:30
safe ( mailServer . onDomainAdded ( domain ) , { debug } ) ; // background
2017-10-28 22:18:07 +02:00
}
2021-08-13 17:22:28 -07:00
async function get ( domain ) {
2017-10-28 22:18:07 +02:00
assert . strictEqual ( typeof domain , 'string' ) ;
2021-08-13 17:22:28 -07:00
const result = await database . query ( ` SELECT ${ DOMAINS _FIELDS } FROM domains WHERE domain=? ` , [ domain ] ) ;
if ( result . length === 0 ) return null ;
return postProcess ( result [ 0 ] ) ;
2017-10-28 22:18:07 +02:00
}
2021-08-13 17:22:28 -07:00
async function list ( ) {
const results = await database . query ( ` SELECT ${ DOMAINS _FIELDS } FROM domains ORDER BY domain ` ) ;
2025-04-28 16:36:37 +02:00
2021-08-13 17:22:28 -07:00
results . forEach ( postProcess ) ;
2025-04-28 16:36:37 +02:00
2025-10-17 18:55:22 +02:00
return results . sort ( ( d1 , d2 ) => { // domains are alphabetically sorted
return d1 . domain . localeCompare ( d2 . domain ) ;
2025-05-06 10:03:20 +02:00
} ) ;
2017-10-28 22:18:07 +02:00
}
2021-12-03 13:46:54 -08:00
async function setConfig ( domain , data , auditSource ) {
2017-10-28 22:18:07 +02:00
assert . strictEqual ( typeof domain , 'string' ) ;
2018-11-10 00:43:46 -08:00
assert . strictEqual ( typeof data . zoneName , 'string' ) ;
assert . strictEqual ( typeof data . provider , 'string' ) ;
assert . strictEqual ( typeof data . config , 'object' ) ;
assert . strictEqual ( typeof data . fallbackCertificate , 'object' ) ;
assert . strictEqual ( typeof data . tlsConfig , 'object' ) ;
assert . strictEqual ( typeof auditSource , 'object' ) ;
2017-10-28 22:18:07 +02:00
2024-04-29 13:05:07 +02:00
const { provider , config , fallbackCertificate , tlsConfig } = data ;
2023-08-11 19:41:05 +05:30
const { domain : dashboardDomain } = await dashboard . getLocation ( ) ;
2024-01-13 21:15:41 +01:00
if ( constants . DEMO && ( domain === dashboardDomain ) ) throw new BoxError ( BoxError . BAD _STATE , 'Not allowed in demo mode' ) ;
2020-02-19 10:45:55 -08:00
2021-08-13 17:22:28 -07:00
const domainObject = await get ( domain ) ;
2024-04-29 13:05:07 +02:00
let zoneName ;
if ( data . zoneName ) {
2025-02-05 10:51:05 +01:00
if ( ! tld . isValid ( data . zoneName ) ) throw new BoxError ( BoxError . BAD _FIELD , 'Invalid zoneName' ) ;
2024-04-29 13:05:07 +02:00
zoneName = data . zoneName ;
2021-08-13 17:22:28 -07:00
} else {
zoneName = domainObject . zoneName ;
}
2017-10-28 22:18:07 +02:00
2026-01-17 13:38:17 +01:00
if ( fallbackCertificate ) await openssl . validateCertificate ( 'test' , domain , fallbackCertificate ) ;
2018-05-15 13:51:00 -07:00
2022-07-14 10:35:59 +05:30
const tlsConfigError = validateTlsConfig ( tlsConfig , provider ) ;
if ( tlsConfigError ) throw tlsConfigError ;
2017-11-09 02:06:36 +01:00
2021-08-13 17:22:28 -07:00
if ( provider === domainObject . provider ) api ( provider ) . injectPrivateFields ( config , domainObject . config ) ;
2020-12-23 15:34:23 -08:00
2022-07-14 10:32:30 +05:30
const sanitizedConfig = await verifyDomainConfig ( config , domain , zoneName , provider ) ;
2017-10-28 23:23:58 +02:00
2021-08-27 09:52:24 -07:00
const newData = {
2022-07-14 10:32:30 +05:30
config : sanitizedConfig ,
2021-08-13 17:22:28 -07:00
zoneName ,
provider ,
tlsConfig ,
} ;
2019-02-08 20:35:05 -08:00
2021-08-13 17:22:28 -07:00
if ( fallbackCertificate ) newData . fallbackCertificate = fallbackCertificate ;
2021-05-04 21:40:11 -07:00
2022-07-14 10:32:30 +05:30
const args = [ ] , fields = [ ] ;
2021-08-13 17:22:28 -07:00
for ( const k in newData ) {
2021-12-03 13:46:54 -08:00
if ( k === 'config' || k === 'tlsConfig' || k === 'fallbackCertificate' ) { // json fields
2021-08-13 17:22:28 -07:00
fields . push ( ` ${ k } Json = ? ` ) ;
args . push ( JSON . stringify ( newData [ k ] ) ) ;
} else {
fields . push ( k + ' = ?' ) ;
args . push ( newData [ k ] ) ;
}
}
args . push ( domain ) ;
2017-10-28 23:23:58 +02:00
2022-07-14 10:35:59 +05:30
const result = await database . query ( 'UPDATE domains SET ' + fields . join ( ', ' ) + ' WHERE domain=?' , args ) ;
if ( result . affectedRows === 0 ) throw new BoxError ( BoxError . NOT _FOUND , 'Domain not found' ) ;
2018-01-26 22:27:32 -08:00
2022-11-14 10:58:32 +01:00
if ( fallbackCertificate ) await reverseProxy . setFallbackCertificate ( domain , fallbackCertificate ) ;
2022-11-29 18:11:22 +01:00
if ( ! _ . isEqual ( domainObject . tlsConfig , tlsConfig . provider ) ) await reverseProxy . handleCertificateProviderChanged ( domain ) ;
2018-11-10 00:43:46 -08:00
2022-02-24 20:04:46 -08:00
await eventlog . add ( eventlog . ACTION _DOMAIN _UPDATE , auditSource , { domain , zoneName , provider } ) ;
2017-10-28 22:18:07 +02:00
}
2021-12-03 13:46:54 -08:00
async function setWellKnown ( domain , wellKnown , auditSource ) {
assert . strictEqual ( typeof domain , 'string' ) ;
assert . strictEqual ( typeof wellKnown , 'object' ) ;
assert . strictEqual ( typeof auditSource , 'object' ) ;
2022-07-14 10:35:59 +05:30
const wellKnownError = validateWellKnown ( wellKnown ) ;
if ( wellKnownError ) throw wellKnownError ;
2021-12-03 13:46:54 -08:00
2022-07-14 10:35:59 +05:30
const result = await database . query ( 'UPDATE domains SET wellKnownJson = ? WHERE domain=?' , [ JSON . stringify ( wellKnown ) , domain ] ) ;
if ( result . affectedRows === 0 ) throw new BoxError ( BoxError . NOT _FOUND , 'Domain not found' ) ;
2021-12-03 13:46:54 -08:00
2022-02-24 20:04:46 -08:00
await eventlog . add ( eventlog . ACTION _DOMAIN _UPDATE , auditSource , { domain , wellKnown } ) ;
2021-12-03 13:46:54 -08:00
}
2021-08-13 17:22:28 -07:00
async function del ( domain , auditSource ) {
2017-10-28 22:18:07 +02:00
assert . strictEqual ( typeof domain , 'string' ) ;
2018-11-10 00:43:46 -08:00
assert . strictEqual ( typeof auditSource , 'object' ) ;
2018-01-23 20:25:45 -08:00
2023-08-11 19:41:05 +05:30
const { domain : dashboardDomain } = await dashboard . getLocation ( ) ;
if ( domain === dashboardDomain ) throw new BoxError ( BoxError . CONFLICT , 'Cannot remove admin domain' ) ;
2023-08-04 21:37:38 +05:30
const { domain : mailDomain } = await mailServer . getLocation ( ) ;
if ( domain === mailDomain ) throw new BoxError ( BoxError . CONFLICT , 'Cannot remove mail domain. Change the mail server location first' ) ;
2018-01-23 20:25:45 -08:00
2024-04-29 13:05:07 +02:00
const queries = [
2021-08-13 17:22:28 -07:00
{ query : 'DELETE FROM mail WHERE domain = ?' , args : [ domain ] } ,
{ query : 'DELETE FROM domains WHERE domain = ?' , args : [ domain ] } ,
] ;
2017-10-29 00:15:11 +02:00
2021-08-13 17:22:28 -07:00
const [ error , results ] = await safe ( database . transaction ( queries ) ) ;
2025-09-29 11:55:15 +02:00
if ( error && error . sqlCode === 'ER_ROW_IS_REFERENCED_2' ) {
2024-01-02 17:18:37 +01:00
if ( error . message . includes ( 'mailboxes_aliasDomain_constraint' ) ) throw new BoxError ( BoxError . CONFLICT , 'Domain is in use in a mailbox, list or an alias' ) ;
2023-07-08 17:46:51 +05:30
if ( error . message . includes ( 'mailboxes_domain_constraint' ) ) throw new BoxError ( BoxError . CONFLICT , 'Domain is in use in a mailbox, list or an alias' ) ;
if ( error . message . includes ( 'apps_mailDomain_constraint' ) ) throw new BoxError ( BoxError . CONFLICT , 'Domain is in use in an app\'s mailbox section' ) ;
if ( error . message . includes ( 'locations' ) ) throw new BoxError ( BoxError . CONFLICT , 'Domain is in use in an app\'s location' ) ;
2021-08-13 17:22:28 -07:00
throw new BoxError ( BoxError . CONFLICT , error . message ) ;
}
if ( error ) throw error ;
if ( results [ 1 ] . affectedRows !== 1 ) throw new BoxError ( BoxError . NOT _FOUND , 'Domain not found' ) ;
2017-10-29 00:15:11 +02:00
2022-02-24 20:04:46 -08:00
await eventlog . add ( eventlog . ACTION _DOMAIN _REMOVE , auditSource , { domain } ) ;
2017-10-29 00:15:11 +02:00
2023-08-04 20:54:16 +05:30
safe ( mailServer . onDomainRemoved ( domain ) ) ;
2017-11-21 19:18:03 -08:00
}
2017-10-29 00:15:11 +02:00
2021-08-13 17:22:28 -07:00
async function clear ( ) {
await database . query ( 'DELETE FROM domains' ) ;
2017-11-11 22:02:34 +01:00
}
2018-01-01 19:19:07 -08:00
2018-06-25 15:12:20 -07:00
// removes all fields that are strictly private and should never be returned by API calls
2018-04-27 11:38:09 -07:00
function removePrivateFields ( domain ) {
2025-02-13 14:03:25 +01:00
const result = _ . pick ( domain , [ 'domain' , 'zoneName' , 'provider' , 'config' , 'tlsConfig' , 'fallbackCertificate' , 'wellKnown' ] ) ;
2024-04-30 09:47:48 +02:00
const out = api ( result . provider ) . removePrivateFields ( result ) ;
delete out . fallbackCertificate . key ;
return out ;
2018-04-29 11:20:12 -07:00
}
2018-06-25 15:12:20 -07:00
2024-04-30 09:47:48 +02:00
// removes all fields that are not accessible by a normal user. currently, this is same as for admin users since config tokens are removed
2018-06-25 15:12:20 -07:00
function removeRestrictedFields ( domain ) {
2024-04-30 09:47:48 +02:00
return removePrivateFields ( domain ) ;
2018-09-05 22:58:43 -07:00
}
2022-11-11 18:09:10 +01:00
async function getDomainObjectMap ( ) {
const domainObjects = await list ( ) ;
2024-04-29 13:05:07 +02:00
const domainObjectMap = { } ;
for ( const d of domainObjects ) { domainObjectMap [ d . domain ] = d ; }
2022-11-11 18:09:10 +01:00
return domainObjectMap ;
}
2025-02-17 19:01:53 +01:00
async function checkConfigs ( auditSource ) {
assert . strictEqual ( typeof auditSource , 'object' ) ;
debug ( ` checkConfig: validating domain configs ` ) ;
for ( const domainObject of await list ( ) ) {
if ( domainObject . provider === 'noop' || domainObject . provider === 'manual' || domainObject . provider === 'wildcard' ) {
await notifications . unpin ( notifications . TYPE _DOMAIN _CONFIG _CHECK _FAILED , { context : domainObject . domain } ) ;
continue ;
}
const [ error ] = await safe ( api ( domainObject . provider ) . verifyDomainConfig ( domainObject ) ) ;
if ( ! error ) {
await notifications . unpin ( notifications . TYPE _DOMAIN _CONFIG _CHECK _FAILED , { context : domainObject . domain } ) ;
continue ;
}
let errorMessage ;
if ( error . reason === BoxError . ACCESS _DENIED ) {
errorMessage = ` Access denied: ${ error . message } ` ;
} else if ( error . reason === BoxError . NOT _FOUND ) {
errorMessage = ` Zone not found: ${ error . message } ` ;
} else if ( error . reason === BoxError . EXTERNAL _ERROR ) {
errorMessage = ` Configuration error: ${ error . message } ` ;
} else {
errorMessage = ` General error: ${ error . message } ` ;
}
2026-01-12 18:35:18 +01:00
debug ( ` checkConfig: ${ domainObject . domain } is not configured properly ` , error ) ;
2025-02-17 19:01:53 +01:00
await notifications . pin ( notifications . TYPE _DOMAIN _CONFIG _CHECK _FAILED , ` Domain ${ domainObject . domain } is not configured properly ` ,
errorMessage , { context : domainObject . domain } ) ;
}
}
2026-02-14 15:43:24 +01:00
export default {
add ,
get ,
list ,
setConfig ,
setWellKnown ,
del ,
clear ,
getDomainObjectMap ,
removePrivateFields ,
removeRestrictedFields ,
checkConfigs
} ;