12e073e8cf
mostly because code is being autogenerated by all the AI stuff using this prefix. it's also used in the stack trace.
176 lines
8.3 KiB
JavaScript
176 lines
8.3 KiB
JavaScript
'use strict';
|
|
|
|
exports = module.exports = {
|
|
add,
|
|
get,
|
|
list,
|
|
setConfig,
|
|
setWellKnown,
|
|
del,
|
|
|
|
checkDnsRecords,
|
|
syncDnsRecords,
|
|
};
|
|
|
|
const assert = require('node:assert'),
|
|
AuditSource = require('../auditsource.js'),
|
|
BoxError = require('../boxerror.js'),
|
|
dns = require('../dns.js'),
|
|
domains = require('../domains.js'),
|
|
HttpError = require('@cloudron/connect-lastmile').HttpError,
|
|
HttpSuccess = require('@cloudron/connect-lastmile').HttpSuccess,
|
|
safe = require('safetydance');
|
|
|
|
async function add(req, res, next) {
|
|
assert.strictEqual(typeof req.body, 'object');
|
|
|
|
if (typeof req.body.domain !== 'string') return next(new HttpError(400, 'domain must be a string'));
|
|
if (typeof req.body.provider !== 'string') return next(new HttpError(400, 'provider must be a string'));
|
|
|
|
if (!req.body.config || typeof req.body.config !== 'object') return next(new HttpError(400, 'config must be an object'));
|
|
|
|
if ('zoneName' in req.body && typeof req.body.zoneName !== 'string') return next(new HttpError(400, 'zoneName must be a string'));
|
|
if ('fallbackCertificate' in req.body && typeof req.body.fallbackCertificate !== 'object') return next(new HttpError(400, 'fallbackCertificate must be a object with cert and key strings'));
|
|
if (req.body.fallbackCertificate) {
|
|
const fallbackCertificate = req.body.fallbackCertificate;
|
|
if (!fallbackCertificate.cert || typeof fallbackCertificate.cert !== 'string') return next(new HttpError(400, 'fallbackCertificate.cert must be a string'));
|
|
if (!fallbackCertificate.key || typeof fallbackCertificate.key !== 'string') return next(new HttpError(400, 'fallbackCertificate.key must be a string'));
|
|
}
|
|
|
|
if ('tlsConfig' in req.body) {
|
|
const tlsConfig = req.body.tlsConfig;
|
|
if (!tlsConfig || typeof tlsConfig !== 'object') return next(new HttpError(400, 'tlsConfig must be a object with a provider string property'));
|
|
if (!tlsConfig.provider || typeof tlsConfig.provider !== 'string') return next(new HttpError(400, 'tlsConfig.provider must be a string'));
|
|
if ('wildcard' in tlsConfig && typeof tlsConfig.wildcard !== 'boolean') return next(new HttpError(400, 'tlsConfig.wildcard must be a boolean'));
|
|
}
|
|
|
|
// some DNS providers like DigitalOcean take a really long time to verify credentials (https://github.com/expressjs/timeout/issues/26)
|
|
req.clearTimeout();
|
|
|
|
const data = {
|
|
zoneName: req.body.zoneName || '',
|
|
provider: req.body.provider,
|
|
config: req.body.config,
|
|
fallbackCertificate: req.body.fallbackCertificate || null,
|
|
tlsConfig: req.body.tlsConfig || { provider: 'letsencrypt-prod' }
|
|
};
|
|
|
|
const [error] = await safe(domains.add(req.body.domain, data, AuditSource.fromRequest(req)));
|
|
if (error) return next(BoxError.toHttpError(error));
|
|
|
|
next(new HttpSuccess(201, {}));
|
|
}
|
|
|
|
async function get(req, res, next) {
|
|
assert.strictEqual(typeof req.params.domain, 'string');
|
|
|
|
const [error, result] = await safe(domains.get(req.params.domain));
|
|
if (error) return next(BoxError.toHttpError(error));
|
|
if (!result) return next(new HttpError(404, 'Domain not found'));
|
|
|
|
next(new HttpSuccess(200, domains.removePrivateFields(result)));
|
|
}
|
|
|
|
async function list(req, res, next) {
|
|
const [error, results] = await safe(domains.list());
|
|
if (error) return next(new HttpError(500, error));
|
|
|
|
next(new HttpSuccess(200, { domains: results.map(domains.removeRestrictedFields) }));
|
|
}
|
|
|
|
async function setConfig(req, res, next) {
|
|
assert.strictEqual(typeof req.params.domain, 'string');
|
|
assert.strictEqual(typeof req.body, 'object');
|
|
|
|
if (typeof req.body.provider !== 'string') return next(new HttpError(400, 'provider must be an object'));
|
|
|
|
if (!req.body.config || typeof req.body.config !== 'object') return next(new HttpError(400, 'config must be an object'));
|
|
|
|
if ('zoneName' in req.body && typeof req.body.zoneName !== 'string') return next(new HttpError(400, 'zoneName must be a string'));
|
|
if ('fallbackCertificate' in req.body && typeof req.body.fallbackCertificate !== 'object') return next(new HttpError(400, 'fallbackCertificate must be a object with cert and key strings'));
|
|
if (req.body.fallbackCertificate) {
|
|
const fallbackCertificate = req.body.fallbackCertificate;
|
|
if (!fallbackCertificate.cert || typeof fallbackCertificate.cert !== 'string') return next(new HttpError(400, 'fallbackCertificate.cert must be a string'));
|
|
if (!fallbackCertificate.key || typeof fallbackCertificate.key !== 'string') return next(new HttpError(400, 'fallbackCertificate.key must be a string'));
|
|
}
|
|
|
|
if ('tlsConfig' in req.body) {
|
|
const tlsConfig = req.body.tlsConfig;
|
|
if (!tlsConfig || typeof tlsConfig !== 'object') return next(new HttpError(400, 'tlsConfig must be a object with a provider string property'));
|
|
if (!tlsConfig.provider || typeof tlsConfig.provider !== 'string') return next(new HttpError(400, 'tlsConfig.provider must be a string'));
|
|
if ('wildcard' in tlsConfig && typeof tlsConfig.wildcard !== 'boolean') return next(new HttpError(400, 'tlsConfig.wildcard must be a boolean'));
|
|
}
|
|
|
|
// some DNS providers like DigitalOcean take a really long time to verify credentials (https://github.com/expressjs/timeout/issues/26)
|
|
req.clearTimeout();
|
|
|
|
const data = {
|
|
zoneName: req.body.zoneName || '',
|
|
provider: req.body.provider,
|
|
config: req.body.config,
|
|
fallbackCertificate: req.body.fallbackCertificate || null,
|
|
tlsConfig: req.body.tlsConfig || { provider: 'letsencrypt-prod' }
|
|
};
|
|
|
|
const [error] = await safe(domains.setConfig(req.params.domain, data, AuditSource.fromRequest(req)));
|
|
if (error) return next(BoxError.toHttpError(error));
|
|
|
|
next(new HttpSuccess(204, {}));
|
|
}
|
|
|
|
async function setWellKnown(req, res, next) {
|
|
assert.strictEqual(typeof req.params.domain, 'string');
|
|
assert.strictEqual(typeof req.body, 'object');
|
|
|
|
if (typeof req.body.wellKnown !== 'object') return next(new HttpError(400, 'wellKnown must be an object'));
|
|
if (req.body.wellKnown) {
|
|
if (Object.keys(req.body.wellKnown).some(k => typeof req.body.wellKnown[k] !== 'string')) return next(new HttpError(400, 'wellKnown is a map of strings'));
|
|
}
|
|
|
|
const [error] = await safe(domains.setWellKnown(req.params.domain, req.body.wellKnown || null, AuditSource.fromRequest(req)));
|
|
if (error) return next(BoxError.toHttpError(error));
|
|
|
|
next(new HttpSuccess(204, {}));
|
|
}
|
|
|
|
async function del(req, res, next) {
|
|
assert.strictEqual(typeof req.params.domain, 'string');
|
|
|
|
const [error] = await safe(domains.del(req.params.domain, AuditSource.fromRequest(req)));
|
|
if (error) return next(BoxError.toHttpError(error));
|
|
|
|
next(new HttpSuccess(204));
|
|
}
|
|
|
|
async function checkDnsRecords(req, res, next) {
|
|
assert.strictEqual(typeof req.params.domain, 'string');
|
|
|
|
if (typeof req.query.subdomain !=='string') return next(new HttpError(400, 'subdomain is required'));
|
|
|
|
let [error, result] = await safe(domains.get(req.params.domain));
|
|
if (error) return next(BoxError.toHttpError(error));
|
|
if (!result) return next(new HttpError(404, 'Domain not found'));
|
|
|
|
// some DNS providers like DigitalOcean take a really long time to verify credentials (https://github.com/expressjs/timeout/issues/26)
|
|
req.clearTimeout();
|
|
|
|
[error, result] = await safe(dns.checkDnsRecords(req.query.subdomain, req.params.domain));
|
|
if (error && error.reason === BoxError.ACCESS_DENIED) return next(new HttpSuccess(200, { error: { reason: error.reason, message: error.message }}));
|
|
if (error) return next(BoxError.toHttpError(error));
|
|
|
|
next(new HttpSuccess(200, { needsOverwrite: result.needsOverwrite }));
|
|
}
|
|
|
|
async function syncDnsRecords(req, res, next) {
|
|
assert.strictEqual(typeof req.body, 'object');
|
|
|
|
if ('domain' in req.body && typeof req.body.domain !== 'string') return next(new HttpError(400, 'domain must be a string'));
|
|
if ('type' in req.body && typeof req.body.type !== 'string') return next(new HttpError(400, 'type must be a string'));
|
|
|
|
const [error, taskId] = await safe(dns.startSyncDnsRecords(req.body));
|
|
if (error && error.reason === BoxError.ACCESS_DENIED) return next(new HttpSuccess(200, { error: { reason: error.reason, message: error.message }}));
|
|
if (error) return next(BoxError.toHttpError(error));
|
|
|
|
next(new HttpSuccess(201, { taskId }));
|
|
}
|