diff --git a/src/infra_version.js b/src/infra_version.js index 729045c34..e9583262d 100644 --- a/src/infra_version.js +++ b/src/infra_version.js @@ -22,6 +22,6 @@ exports = module.exports = { 'redis': { repo: 'cloudron/redis', tag: 'cloudron/redis:3.0.4@sha256:5c60de75d078ae609da5565f32dcd91030f45907e945756cc976ff207b8c6199' }, 'mail': { repo: 'cloudron/mail', tag: 'cloudron/mail:3.3.3@sha256:b1093e6f38bebf4a9ae903ca385aea3a32e7cccae5ede7f2e01a34681e361a5f' }, 'graphite': { repo: 'cloudron/graphite', tag: 'cloudron/graphite:3.0.1@sha256:bed9f6b5d06fe2c5289e895e806cfa5b74ad62993d705be55d4554a67d128029' }, - 'sftp': { repo: 'cloudron/sftp', tag: 'cloudron/sftp:3.4.0@sha256:2fd5ed1396cc1563422c7d10c9158e0ec7cc4e3ddbe5e1bda63ac04631965a81' } + 'sftp': { repo: 'cloudron/sftp', tag: 'cloudron/sftp:3.4.0@sha256:2804a2ad5645a771c30ce56b3fbbec05f5b9d9284a5e402450a7e1c1d9a10eab' } } }; diff --git a/src/routes/filemanager.js b/src/routes/filemanager.js index 643255054..e82eedc1d 100644 --- a/src/routes/filemanager.js +++ b/src/routes/filemanager.js @@ -1,8 +1,7 @@ 'use strict'; exports = module.exports = { - proxyAppData, - proxyVolumeData + proxy, }; const assert = require('assert'), @@ -13,37 +12,38 @@ const assert = require('assert'), services = require('../services.js'), url = require('url'); -async function proxy(id, req, res, next) { - assert.strictEqual(typeof id, 'string'); +function proxy(kind) { + assert(kind === 'mail' || kind === 'volume' || kind === 'app'); - req.clearTimeout(); + return async function (req, res, next) { + req.clearTimeout(); - const [error, result] = await safe(services.getContainerDetails('sftp', 'CLOUDRON_SFTP_TOKEN')); - if (error) return next(BoxError.toHttpError(error)); + let id = null; + switch (kind) { + case 'app': id = `app-${req.params.id}`; break; + case 'volume': id = `volume-${req.params.id}`; break; + case 'mail': id = 'mail'; break; + } - let parsedUrl = url.parse(req.url, true /* parseQueryString */); - parsedUrl.query['access_token'] = result.token; + const [error, result] = await safe(services.getContainerDetails('sftp', 'CLOUDRON_SFTP_TOKEN')); + if (error) return next(BoxError.toHttpError(error)); - req.url = url.format({ pathname: `/files/${id}/${encodeURIComponent(req.params[0])}`, query: parsedUrl.query }); // params[0] already contains leading '/' + let parsedUrl = url.parse(req.url, true /* parseQueryString */); + parsedUrl.query['access_token'] = result.token; - const proxyOptions = url.parse(`https://${result.ip}:3000`); - proxyOptions.rejectUnauthorized = false; - const fileManagerProxy = middleware.proxy(proxyOptions); + req.url = url.format({ pathname: `/files/${id}/${encodeURIComponent(req.params[0])}`, query: parsedUrl.query }); // params[0] already contains leading '/' - fileManagerProxy(req, res, function (error) { - if (!error) return next(); + const proxyOptions = url.parse(`https://${result.ip}:3000`); + proxyOptions.rejectUnauthorized = false; + const fileManagerProxy = middleware.proxy(proxyOptions); - if (error.code === 'ECONNREFUSED') return next(new HttpError(424, 'Unable to connect to filemanager server')); - if (error.code === 'ECONNRESET') return next(new HttpError(424, 'Unable to query filemanager server')); + fileManagerProxy(req, res, function (error) { + if (!error) return next(); - next(new HttpError(500, error)); - }); + if (error.code === 'ECONNREFUSED') return next(new HttpError(424, 'Unable to connect to filemanager server')); + if (error.code === 'ECONNRESET') return next(new HttpError(424, 'Unable to query filemanager server')); + + next(new HttpError(500, error)); + }); + }; } - -function proxyAppData(req, res, next) { - proxy(`app-${req.params.id}`, req, res, next); -} - -function proxyVolumeData(req, res, next) { - proxy(`volume-${req.params.id}`, req, res, next); -} \ No newline at end of file diff --git a/src/server.js b/src/server.js index e41c32d84..fbc5eea11 100644 --- a/src/server.js +++ b/src/server.js @@ -240,7 +240,7 @@ function initializeExpressSync() { router.post('/api/v1/apps/:id/clone', json, token, routes.apps.load, authorizeAdmin, routes.apps.clone); router.get ('/api/v1/apps/:id/download', token, routes.apps.load, authorizeOperator, routes.apps.downloadFile); router.post('/api/v1/apps/:id/upload', json, token, multipart, routes.apps.load, authorizeOperator, routes.apps.uploadFile); - router.use ('/api/v1/apps/:id/files/*', token, routes.apps.load, authorizeOperator, routes.filemanager.proxyAppData); + router.use ('/api/v1/apps/:id/files/*', token, routes.apps.load, authorizeOperator, routes.filemanager.proxy('app')); router.get ('/api/v1/apps/:id/exec', token, routes.apps.load, authorizeOperator, routes.apps.exec); // websocket cannot do bearer authentication @@ -275,6 +275,7 @@ function initializeExpressSync() { router.post('/api/v1/mailserver/spam_custom_config', token, authorizeAdmin, routes.mailserver.proxy); router.get ('/api/v1/mailserver/solr_config', token, authorizeAdmin, routes.mailserver.proxy); router.post('/api/v1/mailserver/solr_config', token, authorizeAdmin, routes.mailserver.proxy, routes.mailserver.restart); + router.use ('/api/v1/mailserver/files/*', token, authorizeOwner, routes.filemanager.proxy('mail')); router.get ('/api/v1/mail/:domain', token, authorizeAdmin, routes.mail.getDomain); router.get ('/api/v1/mail/:domain/status', token, authorizeAdmin, routes.mail.getStatus); @@ -317,7 +318,7 @@ function initializeExpressSync() { router.get ('/api/v1/volumes/:id', token, authorizeAdmin, routes.volumes.load, routes.volumes.get); router.del ('/api/v1/volumes/:id', token, authorizeAdmin, routes.volumes.load, routes.volumes.del); router.get ('/api/v1/volumes/:id/status', token, authorizeAdmin, routes.volumes.load, routes.volumes.getStatus); - router.use ('/api/v1/volumes/:id/files/*', token, authorizeAdmin, routes.filemanager.proxyVolumeData); + router.use ('/api/v1/volumes/:id/files/*', token, authorizeAdmin, routes.filemanager.proxy('volume')); // service routes router.get ('/api/v1/services', token, authorizeAdmin, routes.services.list); diff --git a/src/sftp.js b/src/sftp.js index d0b0409da..1c06cac0f 100644 --- a/src/sftp.js +++ b/src/sftp.js @@ -13,6 +13,7 @@ const apps = require('./apps.js'), debug = require('debug')('box:sftp'), hat = require('./hat.js'), infra = require('./infra_version.js'), + path = require('path'), paths = require('./paths.js'), safe = require('safetydance'), shell = require('./shell.js'), @@ -66,6 +67,12 @@ async function rebuild(serviceConfig, options) { dataDirs.push({ hostDir: volume.hostPath, mountDir: `/mnt/${volume.id}` }); } + // mail data dir + const stat2 = safe.fs.lstatSync(paths.BOX_DATA_DIR); + if (!stat2) throw new BoxError(BoxError.FS_ERROR, `Could not stat mail data dir: ${safe.error.message}`); + const resolvedBoxDataDir = stat2.isSymbolicLink() ? safe.fs.readlinkSync(paths.BOX_DATA_DIR) : paths.BOX_DATA_DIR; + dataDirs.push({ hostDir: path.join(resolvedBoxDataDir, 'mail'), mountDir: '/mnt/maildata' }); + const mounts = dataDirs.map(v => `-v "${v.hostDir}:${v.mountDir}"`).join(' '); const cmd = `docker run --restart=always -d --name="sftp" \ --hostname sftp \