2017-10-28 22:18:07 +02:00
'use strict' ;
module . exports = exports = {
add : add ,
get : get ,
getAll : getAll ,
update : update ,
del : del ,
2018-09-05 22:58:43 -07:00
isLocked : isLocked ,
2017-10-28 22:18:07 +02:00
2018-01-11 00:31:51 -08:00
fqdn : fqdn ,
2018-01-01 19:19:07 -08:00
setAdmin : setAdmin ,
2018-02-08 12:05:29 -08:00
getDnsRecords : getDnsRecords ,
upsertDnsRecords : upsertDnsRecords ,
removeDnsRecords : removeDnsRecords ,
2017-10-29 00:15:11 +02:00
2018-02-08 12:05:29 -08:00
waitForDnsRecord : waitForDnsRecord ,
2017-10-29 00:15:11 +02:00
2018-04-27 11:38:09 -07:00
removePrivateFields : removePrivateFields ,
2018-06-25 15:12:20 -07:00
removeRestrictedFields : removeRestrictedFields ,
2018-04-27 11:38:09 -07:00
2018-08-30 20:05:08 -07:00
validateHostname : validateHostname ,
2018-04-29 11:20:12 -07:00
DomainsError : DomainsError
2017-10-28 22:18:07 +02:00
} ;
var assert = require ( 'assert' ) ,
2018-01-01 19:19:07 -08:00
caas = require ( './caas.js' ) ,
config = require ( './config.js' ) ,
2018-08-30 20:05:08 -07:00
constants = require ( './constants.js' ) ,
2017-10-28 22:18:07 +02:00
DatabaseError = require ( './databaseerror.js' ) ,
2017-12-06 11:33:09 +05:30
debug = require ( 'debug' ) ( 'box:domains' ) ,
2017-10-28 22:18:07 +02:00
domaindb = require ( './domaindb.js' ) ,
2018-01-01 19:19:07 -08:00
path = require ( 'path' ) ,
2018-01-30 12:23:27 -08:00
reverseProxy = require ( './reverseproxy.js' ) ,
ReverseProxyError = reverseProxy . ReverseProxyError ,
2018-01-30 11:30:35 -08:00
safe = require ( 'safetydance' ) ,
2018-01-01 19:19:07 -08:00
shell = require ( './shell.js' ) ,
2017-10-28 23:23:58 +02:00
sysinfo = require ( './sysinfo.js' ) ,
tld = require ( 'tldjs' ) ,
2018-04-27 11:38:09 -07:00
util = require ( 'util' ) ,
_ = require ( 'underscore' ) ;
2017-10-28 22:18:07 +02:00
2018-01-01 19:19:07 -08:00
var RESTART _CMD = path . join ( _ _dirname , 'scripts/restart.sh' ) ;
var NOOP _CALLBACK = function ( error ) { if ( error ) debug ( error ) ; } ;
2018-04-29 11:20:12 -07:00
function DomainsError ( reason , errorOrMessage ) {
2017-10-28 22:18:07 +02:00
assert . strictEqual ( typeof reason , 'string' ) ;
assert ( errorOrMessage instanceof Error || typeof errorOrMessage === 'string' || typeof errorOrMessage === 'undefined' ) ;
Error . call ( this ) ;
Error . captureStackTrace ( this , this . constructor ) ;
this . name = this . constructor . name ;
this . reason = reason ;
if ( typeof errorOrMessage === 'undefined' ) {
this . message = reason ;
} else if ( typeof errorOrMessage === 'string' ) {
this . message = errorOrMessage ;
} else {
this . message = 'Internal error' ;
this . nestedError = errorOrMessage ;
}
}
2018-04-29 11:20:12 -07:00
util . inherits ( DomainsError , Error ) ;
DomainsError . NOT _FOUND = 'No such domain' ;
DomainsError . ALREADY _EXISTS = 'Domain already exists' ;
DomainsError . EXTERNAL _ERROR = 'External error' ;
DomainsError . BAD _FIELD = 'Bad Field' ;
DomainsError . STILL _BUSY = 'Still busy' ;
DomainsError . IN _USE = 'In Use' ;
DomainsError . INTERNAL _ERROR = 'Internal error' ;
DomainsError . ACCESS _DENIED = 'Access denied' ;
2018-09-06 19:58:46 -07:00
DomainsError . INVALID _PROVIDER = 'provider must be route53, gcdns, digitalocean, gandi, cloudflare, namecom, noop, wildcard, manual or caas' ;
2017-10-28 22:18:07 +02:00
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' ) ;
switch ( provider ) {
2017-11-21 19:18:03 -08:00
case 'caas' : return require ( './dns/caas.js' ) ;
case 'cloudflare' : return require ( './dns/cloudflare.js' ) ;
case 'route53' : return require ( './dns/route53.js' ) ;
case 'gcdns' : return require ( './dns/gcdns.js' ) ;
case 'digitalocean' : return require ( './dns/digitalocean.js' ) ;
2018-05-06 18:57:27 -07:00
case 'gandi' : return require ( './dns/gandi.js' ) ;
2018-05-06 22:22:42 -07:00
case 'godaddy' : return require ( './dns/godaddy.js' ) ;
2018-05-09 12:24:33 +02:00
case 'namecom' : return require ( './dns/namecom.js' ) ;
2017-11-21 19:18:03 -08:00
case 'noop' : return require ( './dns/noop.js' ) ;
case 'manual' : return require ( './dns/manual.js' ) ;
2018-09-06 20:26:24 -07:00
case 'wildcard' : return require ( './dns/wildcard.js' ) ;
2017-11-21 19:18:03 -08:00
default : return null ;
2017-10-29 00:15:11 +02:00
}
}
2018-01-09 14:46:38 -08:00
function verifyDnsConfig ( config , domain , zoneName , provider , ip , callback ) {
2017-10-29 00:15:11 +02:00
assert ( config && typeof config === 'object' ) ; // the dns config to test with
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
assert . strictEqual ( typeof ip , 'string' ) ;
assert . strictEqual ( typeof callback , 'function' ) ;
2018-01-09 14:46:38 -08:00
var backend = api ( provider ) ;
2018-04-29 11:20:12 -07:00
if ( ! backend ) return callback ( new DomainsError ( DomainsError . INVALID _PROVIDER ) ) ;
2017-10-29 00:15:11 +02:00
2018-08-22 12:16:19 +02:00
api ( provider ) . verifyDnsConfig ( config , domain , zoneName , ip , callback ) ;
2018-08-22 11:53:23 +02:00
}
2017-10-29 00:15:11 +02:00
2018-08-30 20:05:08 -07:00
function fqdn ( location , domainObject ) {
return location + ( location ? ( domainObject . config . hyphenatedSubdomains ? '-' : '.' ) : '' ) + domainObject . domain ;
}
// Hostname validation comes from RFC 1123 (section 2.1)
// Domain name validation comes from RFC 2181 (Name syntax)
// https://en.wikipedia.org/wiki/Hostname#Restrictions_on_valid_host_names
// We are validating the validity of the location-fqdn as host name (and not dns name)
function validateHostname ( location , domainObject ) {
assert . strictEqual ( typeof location , 'string' ) ;
assert . strictEqual ( typeof domainObject , 'object' ) ;
const hostname = fqdn ( location , domainObject ) ;
const RESERVED _LOCATIONS = [
constants . API _LOCATION ,
constants . SMTP _LOCATION ,
constants . IMAP _LOCATION
] ;
if ( RESERVED _LOCATIONS . indexOf ( location ) !== - 1 ) return new DomainsError ( DomainsError . BAD _FIELD , location + ' is reserved' ) ;
if ( hostname === config . adminFqdn ( ) ) return new DomainsError ( DomainsError . BAD _FIELD , location + ' is reserved' ) ;
// workaround https://github.com/oncletom/tld.js/issues/73
var tmp = hostname . replace ( '_' , '-' ) ;
if ( ! tld . isValid ( tmp ) ) return new DomainsError ( DomainsError . BAD _FIELD , 'Hostname is not a valid domain name' ) ;
if ( hostname . length > 253 ) return new DomainsError ( DomainsError . BAD _FIELD , 'Hostname length exceeds 253 characters' ) ;
if ( location ) {
// label validation
if ( location . split ( '.' ) . some ( function ( p ) { return p . length > 63 || p . length < 1 ; } ) ) return new DomainsError ( DomainsError . BAD _FIELD , 'Invalid subdomain length' ) ;
if ( location . match ( /^[A-Za-z0-9-.]+$/ ) === null ) return new DomainsError ( DomainsError . BAD _FIELD , 'Subdomain can only contain alphanumeric, hyphen and dot' ) ;
if ( /^[-.]/ . test ( location ) ) return new DomainsError ( DomainsError . BAD _FIELD , 'Subdomain cannot start or end with hyphen or dot' ) ;
}
2018-08-30 20:57:14 -07:00
if ( domainObject . config . hyphenatedSubdomains ) {
if ( location . indexOf ( '.' ) !== - 1 ) return new DomainsError ( DomainsError . BAD _FIELD , 'Subdomain cannot contain a dot' ) ;
}
2018-08-30 20:05:08 -07:00
return null ;
}
2018-08-30 21:20:49 -07:00
function add ( domain , zoneName , provider , dnsConfig , fallbackCertificate , tlsConfig , callback ) {
2017-10-28 22:18:07 +02:00
assert . strictEqual ( typeof domain , 'string' ) ;
2017-10-28 23:23:58 +02:00
assert . strictEqual ( typeof zoneName , 'string' ) ;
2018-01-09 14:46:38 -08:00
assert . strictEqual ( typeof provider , 'string' ) ;
2018-08-30 21:20:49 -07:00
assert . strictEqual ( typeof dnsConfig , 'object' ) ;
2017-11-09 02:06:36 +01:00
assert . strictEqual ( typeof fallbackCertificate , 'object' ) ;
2018-01-31 16:57:59 +01:00
assert . strictEqual ( typeof tlsConfig , 'object' ) ;
2017-10-28 22:18:07 +02:00
assert . strictEqual ( typeof callback , 'function' ) ;
2018-04-29 11:20:12 -07:00
if ( ! tld . isValid ( domain ) ) return callback ( new DomainsError ( DomainsError . BAD _FIELD , 'Invalid domain' ) ) ;
2018-06-05 21:09:07 -07:00
if ( domain . endsWith ( '.' ) ) return callback ( new DomainsError ( DomainsError . BAD _FIELD , 'Invalid domain' ) ) ;
2018-01-23 18:54:05 -08:00
if ( zoneName ) {
2018-04-29 11:20:12 -07:00
if ( ! tld . isValid ( zoneName ) ) return callback ( new DomainsError ( DomainsError . BAD _FIELD , 'Invalid zoneName' ) ) ;
2018-06-05 21:09:07 -07:00
if ( zoneName . endsWith ( '.' ) ) return callback ( new DomainsError ( DomainsError . BAD _FIELD , 'Invalid 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
2017-11-09 02:06:36 +01:00
if ( fallbackCertificate ) {
2018-02-09 10:21:06 -08:00
let error = reverseProxy . validateCertificate ( ` test. ${ domain } ` , fallbackCertificate . cert , fallbackCertificate . key ) ;
2018-04-29 11:20:12 -07:00
if ( error ) return callback ( new DomainsError ( DomainsError . BAD _FIELD , error . message ) ) ;
2017-11-09 02:06:36 +01:00
}
2018-01-31 18:37:05 -08:00
if ( tlsConfig . provider !== 'fallback' && tlsConfig . provider !== 'caas' && tlsConfig . provider . indexOf ( 'letsencrypt-' ) !== 0 ) {
2018-04-29 11:20:12 -07:00
return callback ( new DomainsError ( DomainsError . BAD _FIELD , 'tlsConfig.provider must be caas, fallback or le-*' ) ) ;
2018-01-31 18:20:11 +01:00
}
2018-08-30 21:20:49 -07:00
if ( dnsConfig . hyphenatedSubdomains && ! config . allowHyphenatedSubdomains ( ) ) return callback ( new DomainsError ( DomainsError . BAD _FIELD , 'Not allowed in this edition' ) ) ;
2017-10-28 23:23:58 +02:00
sysinfo . getPublicIp ( function ( error , ip ) {
2018-04-29 11:20:12 -07:00
if ( error ) return callback ( new DomainsError ( DomainsError . INTERNAL _ERROR , 'Error getting IP:' + error . message ) ) ;
2017-10-28 22:18:07 +02:00
2018-08-30 21:20:49 -07:00
verifyDnsConfig ( dnsConfig , domain , zoneName , provider , ip , function ( error , result ) {
2018-09-06 20:26:24 -07:00
if ( error && error . reason === DomainsError . ACCESS _DENIED ) return callback ( new DomainsError ( DomainsError . BAD _FIELD , 'Incorrect configuration. Access denied' ) ) ;
2018-04-29 11:20:12 -07:00
if ( error && error . reason === DomainsError . NOT _FOUND ) return callback ( new DomainsError ( DomainsError . BAD _FIELD , 'Zone not found' ) ) ;
2018-09-06 20:26:24 -07:00
if ( error && error . reason === DomainsError . EXTERNAL _ERROR ) return callback ( new DomainsError ( DomainsError . BAD _FIELD , 'Configuration error: ' + error . message ) ) ;
2018-04-29 11:20:12 -07:00
if ( error && error . reason === DomainsError . BAD _FIELD ) return callback ( new DomainsError ( DomainsError . BAD _FIELD , error . message ) ) ;
if ( error && error . reason === DomainsError . INVALID _PROVIDER ) return callback ( new DomainsError ( DomainsError . BAD _FIELD , error . message ) ) ;
if ( error ) return callback ( new DomainsError ( DomainsError . INTERNAL _ERROR , error ) ) ;
2017-10-28 23:23:58 +02:00
2018-01-31 16:57:59 +01:00
domaindb . add ( domain , { zoneName : zoneName , provider : provider , config : result , tlsConfig : tlsConfig } , function ( error ) {
2018-04-29 11:20:12 -07:00
if ( error && error . reason === DatabaseError . ALREADY _EXISTS ) return callback ( new DomainsError ( DomainsError . ALREADY _EXISTS ) ) ;
if ( error ) return callback ( new DomainsError ( DomainsError . INTERNAL _ERROR , error ) ) ;
2017-10-28 23:23:58 +02:00
2018-01-30 12:23:27 -08:00
reverseProxy . setFallbackCertificate ( domain , fallbackCertificate , function ( error ) {
2018-04-29 11:20:12 -07:00
if ( error ) return callback ( new DomainsError ( DomainsError . INTERNAL _ERROR , error ) ) ;
2018-01-26 19:16:43 -08:00
2017-11-09 02:06:36 +01:00
callback ( ) ;
} ) ;
2017-10-28 23:23:58 +02:00
} ) ;
} ) ;
2017-10-28 22:18:07 +02:00
} ) ;
}
2018-09-05 22:58:43 -07:00
function isLocked ( domain ) {
return domain === config . adminDomain ( ) && config . isAdminDomainLocked ( ) ;
}
2017-10-28 22:18:07 +02:00
function get ( domain , callback ) {
assert . strictEqual ( typeof domain , 'string' ) ;
assert . strictEqual ( typeof callback , 'function' ) ;
domaindb . get ( domain , function ( error , result ) {
2017-11-16 22:13:30 +01:00
// TODO try to find subdomain entries maybe based on zoneNames or so
2018-04-29 11:20:12 -07:00
if ( error && error . reason === DatabaseError . NOT _FOUND ) return callback ( new DomainsError ( DomainsError . NOT _FOUND ) ) ;
if ( error ) return callback ( new DomainsError ( DomainsError . INTERNAL _ERROR , error ) ) ;
2017-10-28 22:18:07 +02:00
2018-09-05 22:58:43 -07:00
result . locked = isLocked ( domain ) ;
2018-01-31 18:20:29 -08:00
reverseProxy . getFallbackCertificate ( domain , function ( error , bundle ) {
2018-04-29 11:20:12 -07:00
if ( error && error . reason !== ReverseProxyError . NOT _FOUND ) return callback ( new DomainsError ( DomainsError . INTERNAL _ERROR , error ) ) ;
2017-11-12 00:53:28 +01:00
2018-01-31 18:20:29 -08:00
var cert = safe . fs . readFileSync ( bundle . certFilePath , 'utf-8' ) ;
var key = safe . fs . readFileSync ( bundle . keyFilePath , 'utf-8' ) ;
2018-01-30 11:30:35 -08:00
2018-04-29 11:20:12 -07:00
if ( ! cert || ! key ) return callback ( new DomainsError ( DomainsError . INTERNAL _ERROR , 'unable to read certificates from disk' ) ) ;
2018-01-30 11:30:35 -08:00
result . fallbackCertificate = { cert : cert , key : key } ;
2017-11-12 00:53:28 +01:00
return callback ( null , result ) ;
} ) ;
2017-10-28 22:18:07 +02:00
} ) ;
}
function getAll ( callback ) {
assert . strictEqual ( typeof callback , 'function' ) ;
domaindb . getAll ( function ( error , result ) {
2018-04-29 11:20:12 -07:00
if ( error ) return callback ( new DomainsError ( DomainsError . INTERNAL _ERROR , error ) ) ;
2017-10-28 22:18:07 +02:00
2018-09-05 22:58:43 -07:00
result . forEach ( function ( r ) { r . locked = isLocked ( r . domain ) ; } ) ;
2017-10-28 22:18:07 +02:00
return callback ( null , result ) ;
} ) ;
}
2018-08-30 21:20:49 -07:00
function update ( domain , zoneName , provider , dnsConfig , fallbackCertificate , tlsConfig , callback ) {
2017-10-28 22:18:07 +02:00
assert . strictEqual ( typeof domain , 'string' ) ;
2018-05-15 13:51:00 -07:00
assert . strictEqual ( typeof zoneName , 'string' ) ;
2018-01-09 14:46:38 -08:00
assert . strictEqual ( typeof provider , 'string' ) ;
2018-08-30 21:20:49 -07:00
assert . strictEqual ( typeof dnsConfig , 'object' ) ;
2017-11-09 02:06:36 +01:00
assert . strictEqual ( typeof fallbackCertificate , 'object' ) ;
2018-01-31 16:57:59 +01:00
assert . strictEqual ( typeof tlsConfig , 'object' ) ;
2017-10-28 22:18:07 +02:00
assert . strictEqual ( typeof callback , 'function' ) ;
2017-10-28 23:23:58 +02:00
domaindb . get ( domain , function ( error , result ) {
2018-04-29 11:20:12 -07:00
if ( error && error . reason === DatabaseError . NOT _FOUND ) return callback ( new DomainsError ( DomainsError . NOT _FOUND ) ) ;
if ( error ) return callback ( new DomainsError ( DomainsError . INTERNAL _ERROR , error ) ) ;
2017-10-28 22:18:07 +02:00
2018-05-15 13:51:00 -07:00
if ( zoneName ) {
if ( ! tld . isValid ( zoneName ) ) return callback ( new DomainsError ( DomainsError . BAD _FIELD , 'Invalid zoneName' ) ) ;
} else {
zoneName = result . zoneName ;
}
2017-11-09 02:06:36 +01:00
if ( fallbackCertificate ) {
2018-02-09 10:21:06 -08:00
let error = reverseProxy . validateCertificate ( ` test. ${ domain } ` , fallbackCertificate . cert , fallbackCertificate . key ) ;
2018-04-29 11:20:12 -07:00
if ( error ) return callback ( new DomainsError ( DomainsError . BAD _FIELD , error . message ) ) ;
2017-11-09 02:06:36 +01:00
}
2018-01-31 18:37:05 -08:00
if ( tlsConfig . provider !== 'fallback' && tlsConfig . provider !== 'caas' && tlsConfig . provider . indexOf ( 'letsencrypt-' ) !== 0 ) {
2018-04-29 11:20:12 -07:00
return callback ( new DomainsError ( DomainsError . BAD _FIELD , 'tlsConfig.provider must be caas, fallback or letsencrypt-*' ) ) ;
2018-01-31 18:20:11 +01:00
}
2018-08-30 21:20:49 -07:00
if ( dnsConfig . hyphenatedSubdomains && ! config . allowHyphenatedSubdomains ( ) ) return callback ( new DomainsError ( DomainsError . BAD _FIELD , 'Not allowed in this edition' ) ) ;
2017-10-28 23:23:58 +02:00
sysinfo . getPublicIp ( function ( error , ip ) {
2018-04-29 11:20:12 -07:00
if ( error ) return callback ( new DomainsError ( DomainsError . INTERNAL _ERROR , 'Error getting IP:' + error . message ) ) ;
2017-10-28 23:23:58 +02:00
2018-08-30 21:20:49 -07:00
verifyDnsConfig ( dnsConfig , domain , zoneName , provider , ip , function ( error , result ) {
2018-04-29 11:20:12 -07:00
if ( error && error . reason === DomainsError . ACCESS _DENIED ) return callback ( new DomainsError ( DomainsError . BAD _FIELD , 'Error adding A record. Access denied' ) ) ;
if ( error && error . reason === DomainsError . NOT _FOUND ) return callback ( new DomainsError ( DomainsError . BAD _FIELD , 'Zone not found' ) ) ;
if ( error && error . reason === DomainsError . EXTERNAL _ERROR ) return callback ( new DomainsError ( DomainsError . BAD _FIELD , 'Error adding A record:' + error . message ) ) ;
if ( error && error . reason === DomainsError . BAD _FIELD ) return callback ( new DomainsError ( DomainsError . BAD _FIELD , error . message ) ) ;
if ( error && error . reason === DomainsError . INVALID _PROVIDER ) return callback ( new DomainsError ( DomainsError . BAD _FIELD , error . message ) ) ;
if ( error ) return callback ( new DomainsError ( DomainsError . INTERNAL _ERROR , error ) ) ;
2017-10-28 23:23:58 +02:00
2018-05-15 13:51:00 -07:00
domaindb . update ( domain , { zoneName : zoneName , provider : provider , config : result , tlsConfig : tlsConfig } , function ( error ) {
2018-04-29 11:20:12 -07:00
if ( error && error . reason === DatabaseError . NOT _FOUND ) return callback ( new DomainsError ( DomainsError . NOT _FOUND ) ) ;
if ( error ) return callback ( new DomainsError ( DomainsError . INTERNAL _ERROR , error ) ) ;
2017-10-28 23:23:58 +02:00
2018-01-26 22:27:32 -08:00
if ( ! fallbackCertificate ) return callback ( ) ;
2018-01-30 12:23:27 -08:00
reverseProxy . setFallbackCertificate ( domain , fallbackCertificate , function ( error ) {
2018-04-29 11:20:12 -07:00
if ( error ) return callback ( new DomainsError ( DomainsError . INTERNAL _ERROR , error ) ) ;
2018-01-30 12:23:27 -08:00
2017-11-09 02:06:36 +01:00
callback ( ) ;
} ) ;
2017-10-28 23:23:58 +02:00
} ) ;
} ) ;
} ) ;
2017-10-28 22:18:07 +02:00
} ) ;
}
function del ( domain , callback ) {
assert . strictEqual ( typeof domain , 'string' ) ;
assert . strictEqual ( typeof callback , 'function' ) ;
2018-09-05 17:12:02 -07:00
if ( domain === config . adminDomain ( ) ) return callback ( new DomainsError ( DomainsError . IN _USE ) ) ;
2017-10-28 22:18:07 +02:00
domaindb . del ( domain , function ( error ) {
2018-04-29 11:20:12 -07:00
if ( error && error . reason === DatabaseError . NOT _FOUND ) return callback ( new DomainsError ( DomainsError . NOT _FOUND ) ) ;
if ( error && error . reason === DatabaseError . IN _USE ) return callback ( new DomainsError ( DomainsError . IN _USE ) ) ;
if ( error ) return callback ( new DomainsError ( DomainsError . INTERNAL _ERROR , error ) ) ;
2017-10-28 22:18:07 +02:00
return callback ( null ) ;
} ) ;
}
2017-10-29 00:15:11 +02:00
2018-08-30 16:17:56 -07:00
// returns the 'name' that needs to be inserted into zone
function getName ( domain , subdomain , type ) {
2018-01-23 20:25:45 -08:00
// support special caas domains
if ( domain . provider === 'caas' ) return subdomain ;
if ( domain . domain === domain . zoneName ) return subdomain ;
var part = domain . domain . slice ( 0 , - domain . zoneName . length - 1 ) ;
2018-08-30 16:17:56 -07:00
if ( subdomain === '' ) {
return part ;
} else if ( type === 'TXT' ) {
return ` ${ subdomain } . ${ part } ` ;
} else {
return subdomain + ( domain . config . hyphenatedSubdomains ? '-' : '.' ) + part ;
}
2018-01-23 20:25:45 -08:00
}
2018-02-08 12:05:29 -08:00
function getDnsRecords ( subdomain , domain , type , callback ) {
2017-11-16 22:13:30 +01:00
assert . strictEqual ( typeof subdomain , 'string' ) ;
assert . strictEqual ( typeof domain , 'string' ) ;
2017-10-29 00:15:11 +02:00
assert . strictEqual ( typeof type , 'string' ) ;
assert . strictEqual ( typeof callback , 'function' ) ;
get ( domain , function ( error , result ) {
2018-04-29 11:20:12 -07:00
if ( error ) return callback ( new DomainsError ( DomainsError . INTERNAL _ERROR , error ) ) ;
2017-10-29 00:15:11 +02:00
2018-08-30 16:17:56 -07:00
api ( result . provider ) . get ( result . config , result . zoneName , getName ( result , subdomain , type ) , type , function ( error , values ) {
2017-10-29 00:15:11 +02:00
if ( error ) return callback ( error ) ;
callback ( null , values ) ;
} ) ;
} ) ;
}
2018-02-08 12:05:29 -08:00
function upsertDnsRecords ( subdomain , domain , type , values , callback ) {
2017-11-21 19:18:03 -08:00
assert . strictEqual ( typeof subdomain , 'string' ) ;
assert . strictEqual ( typeof domain , 'string' ) ;
2017-10-29 00:15:11 +02:00
assert . strictEqual ( typeof type , 'string' ) ;
assert ( util . isArray ( values ) ) ;
assert . strictEqual ( typeof callback , 'function' ) ;
2017-11-16 22:13:30 +01:00
debug ( 'upsertDNSRecord: %s on %s type %s values' , subdomain , domain , type , values ) ;
2017-10-29 00:15:11 +02:00
get ( domain , function ( error , result ) {
2018-04-29 11:20:12 -07:00
if ( error ) return callback ( new DomainsError ( DomainsError . INTERNAL _ERROR , error ) ) ;
2017-10-29 00:15:11 +02:00
2018-08-30 16:17:56 -07:00
api ( result . provider ) . upsert ( result . config , result . zoneName , getName ( result , subdomain , type ) , type , values , function ( error ) {
2017-11-21 19:18:03 -08:00
if ( error ) return callback ( error ) ;
2017-10-29 00:15:11 +02:00
2018-06-29 22:25:34 +02:00
callback ( null ) ;
2017-11-21 19:18:03 -08:00
} ) ;
2017-10-29 00:15:11 +02:00
} ) ;
2017-11-21 19:18:03 -08:00
}
2017-10-29 00:15:11 +02:00
2018-02-08 12:05:29 -08:00
function removeDnsRecords ( subdomain , domain , type , values , callback ) {
2017-11-16 22:13:30 +01:00
assert . strictEqual ( typeof subdomain , 'string' ) ;
assert . strictEqual ( typeof domain , 'string' ) ;
2017-10-29 00:15:11 +02:00
assert . strictEqual ( typeof type , 'string' ) ;
assert ( util . isArray ( values ) ) ;
assert . strictEqual ( typeof callback , 'function' ) ;
2017-11-16 22:13:30 +01:00
debug ( 'removeDNSRecord: %s on %s type %s values' , subdomain , domain , type , values ) ;
2017-10-29 00:15:11 +02:00
get ( domain , function ( error , result ) {
2018-01-10 21:25:51 -08:00
if ( error ) return callback ( error ) ;
2017-10-29 00:15:11 +02:00
2018-08-30 16:17:56 -07:00
api ( result . provider ) . del ( result . config , result . zoneName , getName ( result , subdomain , type ) , type , values , function ( error ) {
2018-04-29 11:20:12 -07:00
if ( error && error . reason !== DomainsError . NOT _FOUND ) return callback ( error ) ;
2017-10-29 00:15:11 +02:00
callback ( null ) ;
} ) ;
} ) ;
}
2018-02-08 14:19:14 -08:00
// only wait for A record
function waitForDnsRecord ( fqdn , domain , value , options , callback ) {
2017-10-29 00:15:11 +02:00
assert . strictEqual ( typeof fqdn , 'string' ) ;
2017-12-06 11:33:09 +05:30
assert . strictEqual ( typeof domain , 'string' ) ;
2018-02-08 14:19:14 -08:00
assert . strictEqual ( typeof value , 'string' ) ;
2017-10-29 00:15:11 +02:00
assert ( options && typeof options === 'object' ) ; // { interval: 5000, times: 50000 }
assert . strictEqual ( typeof callback , 'function' ) ;
get ( domain , function ( error , result ) {
2018-02-07 20:54:43 +01:00
if ( error ) return callback ( error ) ;
2018-01-10 21:37:12 -08:00
2018-02-08 14:19:14 -08:00
api ( result . provider ) . waitForDns ( fqdn , result ? result . zoneName : domain , value , options , callback ) ;
2017-10-29 00:15:11 +02:00
} ) ;
2017-11-11 22:02:34 +01:00
}
2018-01-01 19:19:07 -08:00
function setAdmin ( domain , callback ) {
assert . strictEqual ( typeof domain , 'string' ) ;
assert . strictEqual ( typeof callback , 'function' ) ;
debug ( 'setAdmin domain:%s' , domain ) ;
get ( domain , function ( error , result ) {
if ( error ) return callback ( error ) ;
var setPtrRecord = config . provider ( ) === 'caas' ? caas . setPtrRecord : function ( d , next ) { next ( ) ; } ;
setPtrRecord ( domain , function ( error ) {
2018-04-29 11:20:12 -07:00
if ( error ) return callback ( new DomainsError ( DomainsError . EXTERNAL _ERROR , 'Error setting PTR record:' + error . message ) ) ;
2018-01-01 19:19:07 -08:00
2018-01-29 14:53:03 -08:00
config . setAdminDomain ( result . domain ) ;
2018-01-10 20:40:15 -08:00
config . setAdminLocation ( 'my' ) ;
2018-08-22 12:15:46 +02:00
config . setAdminFqdn ( 'my' + ( result . config . hyphenatedSubdomains ? '-' : '.' ) + result . domain ) ;
2018-01-01 19:19:07 -08:00
callback ( ) ;
shell . sudo ( 'restart' , [ RESTART _CMD ] , NOOP _CALLBACK ) ;
} ) ;
} ) ;
}
2018-01-11 00:31:51 -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 ) {
2018-09-05 22:58:43 -07:00
var result = _ . pick ( domain , 'domain' , 'zoneName' , 'provider' , 'config' , 'tlsConfig' , 'fallbackCertificate' , 'locked' ) ;
2018-04-27 11:38:09 -07:00
if ( result . fallbackCertificate ) delete result . fallbackCertificate . key ; // do not return the 'key'. in caas, this is private
return result ;
2018-04-29 11:20:12 -07:00
}
2018-06-25 15:12:20 -07:00
// removes all fields that are not accessible by a normal user
function removeRestrictedFields ( domain ) {
2018-09-05 22:58:43 -07:00
var result = _ . pick ( domain , 'domain' , 'zoneName' , 'provider' , 'locked' ) ;
2018-08-22 17:19:18 +02:00
// always ensure config object
result . config = { hyphenatedSubdomains : ! ! domain . config . hyphenatedSubdomains } ;
2018-06-25 15:12:20 -07:00
return result ;
2018-09-05 22:58:43 -07:00
}