automate wellknown setup

the main reason this is under app and not domain is because it let's
the user know that an app has to be installed for the whole thing to work.

part of #703
This commit is contained in:
Girish Ramakrishnan
2020-12-22 17:19:26 -08:00
parent a8436f8784
commit 8a17e13ec4
10 changed files with 119 additions and 6 deletions
+4 -1
View File
@@ -41,7 +41,7 @@ var APPS_FIELDS_PREFIXED = [ 'apps.id', 'apps.appStoreId', 'apps.installationSta
'apps.health', 'apps.containerId', 'apps.manifestJson', 'apps.accessRestrictionJson', 'apps.memoryLimit', 'apps.cpuShares',
'apps.label', 'apps.tagsJson', 'apps.taskId', 'apps.reverseProxyConfigJson', 'apps.servicesConfigJson',
'apps.sso', 'apps.debugModeJson', 'apps.enableBackup', 'apps.proxyAuth', 'apps.containerIp',
'apps.creationTime', 'apps.updateTime', 'apps.mailboxName', 'apps.mailboxDomain', 'apps.enableAutomaticUpdate',
'apps.creationTime', 'apps.updateTime', 'apps.mailboxName', 'apps.mailboxDomain', 'apps.enableAutomaticUpdate', 'apps.wellKnownJson',
'apps.dataDir', 'apps.ts', 'apps.healthTime' ].join(',');
var PORT_BINDINGS_FIELDS = [ 'hostPort', 'type', 'environmentVariable', 'appId' ].join(',');
@@ -118,6 +118,9 @@ function postProcess(result) {
result.mounts = volumeIds[0] === null ? [] : volumeIds.map((v, idx) => { return { volumeId: v, readOnly: !!volumeReadOnlys[idx] }; }); // NOTE: volumeIds is [null] when volumes of an app is empty
result.wellKnown = safe.JSON.parse(result.wellKnownJson);
delete result.wellKnownJson;
result.error = safe.JSON.parse(result.errorJson);
delete result.errorJson;
+18 -1
View File
@@ -20,6 +20,7 @@ exports = module.exports = {
setMemoryLimit,
setCpuShares,
setMounts,
setWellKnown,
setAutomaticBackup,
setAutomaticUpdate,
setReverseProxyConfig,
@@ -405,7 +406,7 @@ function removeInternalFields(app) {
'location', 'domain', 'fqdn', 'mailboxName', 'mailboxDomain',
'accessRestriction', 'manifest', 'portBindings', 'iconUrl', 'memoryLimit', 'cpuShares',
'sso', 'debugMode', 'reverseProxyConfig', 'enableBackup', 'creationTime', 'updateTime', 'ts', 'tags',
'label', 'alternateDomains', 'env', 'enableAutomaticUpdate', 'dataDir', 'mounts');
'label', 'alternateDomains', 'env', 'enableAutomaticUpdate', 'dataDir', 'mounts', 'wellKnown');
}
// non-admins can only see these
@@ -982,6 +983,22 @@ function setMounts(app, mounts, auditSource, callback) {
});
}
function setWellKnown(app, wellKnown, auditSource, callback) {
assert.strictEqual(typeof app, 'object');
assert.strictEqual(typeof wellKnown, 'object');
assert.strictEqual(typeof auditSource, 'object');
assert.strictEqual(typeof callback, 'function');
const appId = app.id;
appdb.update(appId, { wellKnown }, function (error) {
if (error) return callback(error);
eventlog.add(eventlog.ACTION_APP_CONFIGURE, auditSource, { appId, app, wellKnown });
callback();
});
}
function setEnvironment(app, env, auditSource, callback) {
assert.strictEqual(typeof app, 'object');
assert.strictEqual(typeof env, 'object');
+3 -3
View File
@@ -162,9 +162,9 @@ server {
}
# user defined .well-known resources
location ~ ^/.well-known/(.*)$ {
root /home/yellowtent/boxdata/well-known/$host;
try_files /$1 @wellknown-upstream;
location /.well-known/ {
error_page 404 = @wellknown-upstream;
proxy_pass http://127.0.0.1:3000/well-known-handler/;
}
<% if (proxyAuth.enabled) { %>
+18
View File
@@ -32,6 +32,7 @@ exports = module.exports = {
setLocation,
setDataDir,
setMounts,
setWellKnown,
stop,
start,
@@ -44,6 +45,7 @@ exports = module.exports = {
uploadFile,
downloadFile,
load
};
@@ -795,3 +797,19 @@ function setMounts(req, res, next) {
next(new HttpSuccess(202, { taskId: result.taskId }));
});
}
function setWellKnown(req, res, next) {
assert.strictEqual(typeof req.body, 'object');
assert.strictEqual(typeof req.resource, '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'));
}
apps.setWellKnown(req.resource, req.body.wellKnown, auditSource.fromRequest(req), function (error, result) {
if (error) return next(BoxError.toHttpError(error));
next(new HttpSuccess(200, {}));
});
}
+2 -1
View File
@@ -25,5 +25,6 @@ exports = module.exports = {
tasks: require('./tasks.js'),
tokens: require('./tokens.js'),
users: require('./users.js'),
volumes: require('./volumes.js')
volumes: require('./volumes.js'),
wellknown: require('./wellknown.js')
};
+21
View File
@@ -0,0 +1,21 @@
'use strict';
exports = module.exports = {
get
};
const apps = require('../apps.js'),
HttpError = require('connect-lastmile').HttpError;
function get(req, res, next) {
const host = req.headers['host'];
apps.getByFqdn(host, function (error, app) {
if (error) return next(new HttpError(404, error.message));
const location = req.params[0];
if (!app.wellKnown || !(location in app.wellKnown)) return next(new HttpError(404, 'No custom well-known config'));
res.status(200).send(app.wellKnown[location]);
});
}
+5
View File
@@ -217,6 +217,7 @@ function initializeExpressSync() {
router.post('/api/v1/apps/:id/configure/data_dir', json, token, authorizeAdmin, routes.apps.load, routes.apps.setDataDir);
router.post('/api/v1/apps/:id/configure/location', json, token, authorizeAdmin, routes.apps.load, routes.apps.setLocation);
router.post('/api/v1/apps/:id/configure/mounts', json, token, authorizeAdmin, routes.apps.load, routes.apps.setMounts);
router.post('/api/v1/apps/:id/well_known', json, token, authorizeAdmin, routes.apps.load, routes.apps.setWellKnown);
router.post('/api/v1/apps/:id/repair', json, token, authorizeAdmin, routes.apps.load, routes.apps.repair);
router.post('/api/v1/apps/:id/update', json, token, authorizeAdmin, routes.apps.load, routes.apps.update);
router.post('/api/v1/apps/:id/restore', json, token, authorizeAdmin, routes.apps.load, routes.apps.restore);
@@ -234,6 +235,7 @@ function initializeExpressSync() {
router.post('/api/v1/apps/:id/upload', json, token, authorizeAdmin, multipart, routes.apps.load, routes.apps.uploadFile);
router.use ('/api/v1/apps/:id/files/*', token, authorizeAdmin, routes.filemanager.proxy);
router.get ('/api/v1/apps/:id/exec', token, authorizeAdmin, routes.apps.load, routes.apps.exec);
// websocket cannot do bearer authentication
router.get ('/api/v1/apps/:id/execws', routes.accesscontrol.websocketAuth.bind(null, users.ROLE_ADMIN), routes.apps.load, routes.apps.execWebSocket);
@@ -318,6 +320,9 @@ function initializeExpressSync() {
router.get ('/api/v1/services/:service/logstream', token, authorizeAdmin, routes.services.getLogStream);
router.post('/api/v1/services/:service/restart', json, token, authorizeAdmin, routes.services.restart);
// well known
router.get ('/well-known-handler/*', routes.wellknown.get);
// disable server socket "idle" timeout. we use the timeout middleware to handle timeouts on a route level
// we rely on nginx for timeouts on the TCP level (see client_header_timeout)
httpServer.setTimeout(0);