'use strict'; exports = module.exports = { proxy, proxyAndRestart, queueProxy, setLocation, getLocation }; const assert = require('node:assert'), AuditSource = require('../auditsource.js'), BoxError = require('../boxerror.js'), debug = require('debug')('box:routes/mailserver'), http = require('node:http'), HttpError = require('@cloudron/connect-lastmile').HttpError, HttpSuccess = require('@cloudron/connect-lastmile').HttpSuccess, mailServer = require('../mailserver.js'), safe = require('safetydance'), services = require('../services.js'); async function proxyToMailContainer(port, pathname, req, res, next) { req.clearTimeout(); const [error, addonDetails] = await safe(services.getContainerDetails('mail', 'CLOUDRON_MAIL_TOKEN')); if (error) return next(BoxError.toHttpError(error)); const searchParams = new URLSearchParams(req.url.slice(req.url.indexOf('?')+1)); searchParams.delete('access_token'); searchParams.append('access_token', addonDetails.token); const opts = { hostname: addonDetails.ip, port: 3000, path: `/${pathname}?${searchParams.toString()}`, method: req.method, headers: req.headers }; const sftpReq = http.request(opts, function (sftpRes) { res.writeHead(sftpRes.statusCode, sftpRes.headers); sftpRes.on('error', (error) => next(new HttpError(500, `mailserver error: ${error.message} ${error.code}`))); sftpRes.on('end', () => next()); sftpRes.pipe(res); }); sftpReq.on('error', (error) => next(new HttpError(424, `Unable to connect to mailserver: ${error.message} ${error.code}`))); if (!req.readable) { sftpReq.end(); } else { req.pipe(sftpReq); } } async function proxy(req, res, next) { const pathname = req.path.split('/').pop(); proxyToMailContainer(3000, pathname, req, res, function (httpError) { if (httpError) return next(httpError); // for success, the proxy already sent the response. do not proceed to connect-lastmile which will result in double headers }); } async function proxyAndRestart(req, res, next) { const pathname = req.path.split('/').pop(); proxyToMailContainer(3000, pathname, req, res, async function (httpError) { if (httpError) return next(httpError); // for success, the proxy already sent the response. do not proceed to connect-lastmile which will result in double headers await safe(mailServer.restart(), { debug }); }); } async function queueProxy(req, res, next) { proxyToMailContainer(6000, req.path.replace('/', '/queue/'), req, res, next); } async function getLocation(req, res, next) { const [error, result] = await safe(mailServer.getLocation()); if (error) return next(BoxError.toHttpError(error)); next(new HttpSuccess(200, { domain: result.domain, subdomain: result.subdomain })); } async function setLocation(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.subdomain !== 'string') return next(new HttpError(400, 'subdomain must be a string')); const [error, taskId] = await safe(mailServer.startChangeLocation(req.body.subdomain, req.body.domain, AuditSource.fromRequest(req))); if (error) return next(BoxError.toHttpError(error)); next(new HttpSuccess(202, { taskId })); }