Compare commits

..

14 Commits

Author SHA1 Message Date
Girish Ramakrishnan 62174658cf 4.3.2 changes 2019-11-12 16:43:27 -08:00
Girish Ramakrishnan 3d26e8a666 Revert "Update cloudron-manifestformat and other modules"
This reverts commit 3d337640ef.

Only update cloudron-manifestformat
2019-11-12 14:54:16 -08:00
Girish Ramakrishnan 3d337640ef Update cloudron-manifestformat and other modules 2019-11-12 14:26:13 -08:00
Girish Ramakrishnan 985eaf8ca9 Better progress message 2019-11-11 17:09:46 -08:00
Girish Ramakrishnan e0bee13812 validate sysinfo in setup as well 2019-11-11 16:32:29 -08:00
Girish Ramakrishnan 7c6922d228 validate sysinfo configuration 2019-11-11 16:05:53 -08:00
Girish Ramakrishnan bf68c2d321 default has changed 2019-11-11 11:19:42 -08:00
Girish Ramakrishnan fd51320fb7 sysinfoConfig is now non-optional 2019-11-11 11:05:34 -08:00
Girish Ramakrishnan 815392ba38 restore: add sysinfoConfig 2019-11-11 09:49:18 -08:00
Girish Ramakrishnan f8c110f75c 4.3.1 changes 2019-11-11 09:43:19 -08:00
Girish Ramakrishnan 70f9ceb1b8 better not found message 2019-11-11 09:13:45 -08:00
Girish Ramakrishnan 2353a8b5fa list unstable apps by default 2019-11-11 08:42:00 -08:00
Girish Ramakrishnan cf1c2dc1ee Fix crash when listing mailboxes 2019-11-10 12:44:39 -08:00
Johannes Zellner 467283d5e0 Destroy all session by a user if wanted 2019-11-08 21:32:55 +01:00
12 changed files with 118 additions and 58 deletions
+8
View File
@@ -1714,3 +1714,11 @@
* Rename Accounts view to Profile
* Add search for groups and user association UI
[4.3.1]
* Make logout from all button logout from all sessions
* List unstable apps by default
* Fix crash when listing mailboxes
[4.3.2]
* Update manifestformat module
+21 -18
View File
@@ -814,32 +814,35 @@
}
},
"cloudron-manifestformat": {
"version": "2.15.0",
"resolved": "https://registry.npmjs.org/cloudron-manifestformat/-/cloudron-manifestformat-2.15.0.tgz",
"integrity": "sha512-hSL+n/ttjrjZby/tSa5YSTRUAcxfzAi9CFUSPyu3dx8OMxzHsDyTvtKHjwBtIZ0Fjz7B3THfR3kfvIgP0lULSg==",
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/cloudron-manifestformat/-/cloudron-manifestformat-3.0.0.tgz",
"integrity": "sha512-mI/Xmft1jelxjGFMhtJolOfIiFx4v1IFjpoRe2YiBSiIvISnW98N6T62bl6PemzikY2ZXDuba0zse1CvmY2LOA==",
"requires": {
"cron": "^1.0.9",
"cron": "^1.7.2",
"java-packagename-regex": "^1.0.0",
"safetydance": "0.0.15",
"semver": "^4.3.1",
"tv4": "^1.1.9",
"validator": "^3.34.0"
"safetydance": "0.7.1",
"semver": "^6.3.0",
"tv4": "^1.3.0",
"validator": "^12.0.0"
},
"dependencies": {
"safetydance": {
"version": "0.0.15",
"resolved": "https://registry.npmjs.org/safetydance/-/safetydance-0.0.15.tgz",
"integrity": "sha1-VlUnZ18F92XxxoglYjRWpcVSEMQ="
"cron": {
"version": "1.7.2",
"resolved": "https://registry.npmjs.org/cron/-/cron-1.7.2.tgz",
"integrity": "sha512-+SaJ2OfeRvfQqwXQ2kgr0Y5pzBR/lijf5OpnnaruwWnmI799JfWr2jN2ItOV9s3A/+TFOt6mxvKzQq5F0Jp6VQ==",
"requires": {
"moment-timezone": "^0.5.x"
}
},
"semver": {
"version": "4.3.6",
"resolved": "https://registry.npmjs.org/semver/-/semver-4.3.6.tgz",
"integrity": "sha1-MAvG4OhjdPe6YQaLWx7NV/xlMto="
"version": "6.3.0",
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
"integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw=="
},
"validator": {
"version": "3.43.0",
"resolved": "https://registry.npmjs.org/validator/-/validator-3.43.0.tgz",
"integrity": "sha1-lkZLmS1BloM9l6GUv0Cxn/VLrgU="
"version": "12.0.0",
"resolved": "https://registry.npmjs.org/validator/-/validator-12.0.0.tgz",
"integrity": "sha512-r5zA1cQBEOgYlesRmSEwc9LkbfNLTtji+vWyaHzRZUxCTHdsX3bd+sdHfs5tGZ2W6ILGGsxWxCNwT/h3IY/3ng=="
}
}
},
+1 -1
View File
@@ -20,7 +20,7 @@
"async": "^2.6.2",
"aws-sdk": "^2.476.0",
"body-parser": "^1.19.0",
"cloudron-manifestformat": "^2.15.0",
"cloudron-manifestformat": "^3.0.0",
"connect": "^3.7.0",
"connect-ensure-login": "^0.1.1",
"connect-lastmile": "^1.2.1",
+1 -1
View File
@@ -611,7 +611,7 @@ function download(backupConfig, backupId, format, dataLayout, progressCallback,
ps.on('progress', function (progress) {
const transferred = Math.round(progress.transferred/1024/1024), speed = Math.round(progress.speed/1024/1024);
if (!transferred && !speed) return progressCallback({ message: 'Downloading' }); // 0M@0Mbps looks wrong
if (!transferred && !speed) return progressCallback({ message: 'Downloading backup' }); // 0M@0Mbps looks wrong
progressCallback({ message: `Downloading ${transferred}M@${speed}Mbps` });
});
ps.on('error', retryCallback);
+2 -2
View File
@@ -31,7 +31,7 @@ function get(id, callback) {
database.query('SELECT ' + CLIENTS_FIELDS + ' FROM clients WHERE id = ?', [ id ], function (error, result) {
if (error) return callback(new BoxError(BoxError.DATABASE_ERROR, error));
if (result.length === 0) return callback(new BoxError(BoxError.NOT_FOUND, 'Client not found'));
if (result.length === 0) return callback(new BoxError(BoxError.NOT_FOUND, `Client not found: ${id}`));
callback(null, result[0]);
});
@@ -137,7 +137,7 @@ function del(id, callback) {
database.query('DELETE FROM clients WHERE id = ?', [ id ], function (error, result) {
if (error) return callback(new BoxError(BoxError.DATABASE_ERROR, error));
if (result.affectedRows !== 1) return callback(new BoxError(BoxError.NOT_FOUND, 'Client not found'));
if (result.affectedRows !== 1) return callback(new BoxError(BoxError.NOT_FOUND, `Client not found: ${id}`));
callback(null);
});
+1 -1
View File
@@ -286,7 +286,7 @@ function mailboxSearch(req, res, next) {
} else if (req.dn.rdns[0].attrs.domain) {
var domain = req.dn.rdns[0].attrs.domain.value.toLowerCase();
mailboxdb.listMailboxes(domain, function (error, result) {
mailboxdb.listMailboxes(domain, 1, 1000, function (error, result) {
if (error) return next(new ldap.OperationsError(error.toString()));
var results = [];
+36 -25
View File
@@ -26,6 +26,7 @@ var appstore = require('./appstore.js'),
safe = require('safetydance'),
semver = require('semver'),
settings = require('./settings.js'),
sysinfo = require('./sysinfo.js'),
superagent = require('superagent'),
users = require('./users.js'),
tld = require('tldjs'),
@@ -127,19 +128,23 @@ function setup(dnsConfig, sysinfoConfig, auditSource, callback) {
domains.add(domain, data, auditSource, function (error) {
if (error) return done(error);
callback(); // now that args are validated run the task in the background
sysinfo.testConfig(sysinfoConfig, function (error) {
if (error) return done(error);
async.series([
autoRegister.bind(null, domain),
(next) => { if (!sysinfoConfig) return next(); settings.setSysinfoConfig(sysinfoConfig, next); },
domains.prepareDashboardDomain.bind(null, domain, auditSource, (progress) => setProgress('setup', progress.message, NOOP_CALLBACK)),
cloudron.setDashboardDomain.bind(null, domain, auditSource),
mail.addDomain.bind(null, domain), // this relies on settings.mailFqdn() and settings.adminDomain()
setProgress.bind(null, 'setup', 'Done'),
eventlog.add.bind(null, eventlog.ACTION_PROVISION, auditSource, { })
], function (error) {
gProvisionStatus.setup.active = false;
gProvisionStatus.setup.errorMessage = error ? error.message : '';
callback(); // now that args are validated run the task in the background
async.series([
autoRegister.bind(null, domain),
settings.setSysinfoConfig.bind(null, sysinfoConfig),
domains.prepareDashboardDomain.bind(null, domain, auditSource, (progress) => setProgress('setup', progress.message, NOOP_CALLBACK)),
cloudron.setDashboardDomain.bind(null, domain, auditSource),
mail.addDomain.bind(null, domain), // this relies on settings.mailFqdn() and settings.adminDomain()
setProgress.bind(null, 'setup', 'Done'),
eventlog.add.bind(null, eventlog.ACTION_PROVISION, auditSource, { })
], function (error) {
gProvisionStatus.setup.active = false;
gProvisionStatus.setup.errorMessage = error ? error.message : '';
});
});
});
});
@@ -204,10 +209,11 @@ function activate(username, password, email, displayName, ip, auditSource, callb
});
}
function restore(backupConfig, backupId, version, auditSource, callback) {
function restore(backupConfig, backupId, version, sysinfoConfig, auditSource, callback) {
assert.strictEqual(typeof backupConfig, 'object');
assert.strictEqual(typeof backupId, 'string');
assert.strictEqual(typeof version, 'string');
assert.strictEqual(typeof sysinfoConfig, 'object');
assert.strictEqual(typeof auditSource, 'object');
assert.strictEqual(typeof callback, 'function');
@@ -231,21 +237,26 @@ function restore(backupConfig, backupId, version, auditSource, callback) {
backups.testConfig(backupConfig, function (error) {
if (error) return done(error);
debug(`restore: restoring from ${backupId} from provider ${backupConfig.provider} with format ${backupConfig.format}`);
sysinfo.testConfig(sysinfoConfig, function (error) {
if (error) return done(error);
callback(); // now that the fields are validated, continue task in the background
debug(`restore: restoring from ${backupId} from provider ${backupConfig.provider} with format ${backupConfig.format}`);
async.series([
setProgress.bind(null, 'restore', 'Downloading backup'),
backups.restore.bind(null, backupConfig, backupId, (progress) => setProgress('restore', progress.message, NOOP_CALLBACK)),
cloudron.setupDashboard.bind(null, auditSource, (progress) => setProgress('restore', progress.message, NOOP_CALLBACK)),
settings.setBackupConfig.bind(null, backupConfig), // update with the latest backupConfig
eventlog.add.bind(null, eventlog.ACTION_RESTORE, auditSource, { backupId }),
], function (error) {
gProvisionStatus.restore.active = false;
gProvisionStatus.restore.errorMessage = error ? error.message : '';
callback(); // now that the fields are validated, continue task in the background
if (!error) cloudron.onActivated(NOOP_CALLBACK);
async.series([
setProgress.bind(null, 'restore', 'Downloading backup'),
backups.restore.bind(null, backupConfig, backupId, (progress) => setProgress('restore', progress.message, NOOP_CALLBACK)),
settings.setSysinfoConfig.bind(null, sysinfoConfig),
cloudron.setupDashboard.bind(null, auditSource, (progress) => setProgress('restore', progress.message, NOOP_CALLBACK)),
settings.setBackupConfig.bind(null, backupConfig), // update with the latest backupConfig
eventlog.add.bind(null, eventlog.ACTION_RESTORE, auditSource, { backupId }),
], function (error) {
gProvisionStatus.restore.active = false;
gProvisionStatus.restore.errorMessage = error ? error.message : '';
if (!error) cloudron.onActivated(NOOP_CALLBACK);
});
});
});
});
+39 -3
View File
@@ -21,6 +21,7 @@ exports = module.exports = {
var apps = require('../apps.js'),
assert = require('assert'),
async = require('async'),
authcodedb = require('../authcodedb.js'),
BoxError = require('../boxerror.js'),
clients = require('../clients'),
@@ -275,10 +276,45 @@ function login(req, res) {
// -> GET /api/v1/session/logout
function logout(req, res) {
req.logout();
function done() {
req.logout();
if (req.query && req.query.redirect) res.redirect(req.query.redirect);
else res.redirect('/');
if (req.query && req.query.redirect) res.redirect(req.query.redirect);
else res.redirect('/');
}
if (!req.query.all) return done();
// find and destroy all login sessions by this user - this got rather complex quickly
req.sessionStore.list(function (error, result) {
if (error) {
console.error('Error listing sessions', error);
return done();
}
// WARNING fix this if we change the storage backend - Great stuff!
var sessionIds = result.map(function(s) { return s.replace('.json', ''); });
async.each(sessionIds, function (id, callback) {
req.sessionStore.get(id, function (error, result) {
if (error) {
console.error(`Error getting session ${id}`, error);
return callback();
}
// ignore empty or non passport sessions
if (!result || !result.passport || !result.passport.user) return callback();
// not this user
if (result.passport.user !== req.user.id) return callback();
req.sessionStore.destroy(id, function (error) {
if (error) console.error(`Unable to destroy session ${id}`, error);
callback();
});
});
}, done);
});
}
// Form to enter email address to send a password reset request mail
+4 -2
View File
@@ -58,7 +58,7 @@ function setup(req, res, next) {
// it can take sometime to setup DNS, register cloudron
req.clearTimeout();
provision.setup(dnsConfig, req.body.sysinfoConfig || null, auditSource.fromRequest(req), function (error) {
provision.setup(dnsConfig, req.body.sysinfoConfig || { provider: 'generic' }, auditSource.fromRequest(req), function (error) {
if (error) return next(BoxError.toHttpError(error));
next(new HttpSuccess(200, {}));
@@ -102,7 +102,9 @@ function restore(req, res, next) {
if (typeof req.body.backupId !== 'string') return next(new HttpError(400, 'backupId must be a string or null'));
if (typeof req.body.version !== 'string') return next(new HttpError(400, 'version must be a string'));
provision.restore(backupConfig, req.body.backupId, req.body.version, auditSource.fromRequest(req), function (error) {
if ('sysinfoConfig' in req.body && typeof req.body.sysinfoConfig !== 'object') return next(new HttpError(400, 'sysinfoConfig must be an object'));
provision.restore(backupConfig, req.body.backupId, req.body.version, req.body.sysinfoConfig || { provider: 'generic' }, auditSource.fromRequest(req), function (error) {
if (error) return next(BoxError.toHttpError(error));
next(new HttpSuccess(200, {}));
+1 -1
View File
@@ -99,7 +99,7 @@ describe('Appstore Apps API', function () {
it('can list apps', function (done) {
var scope1 = nock(settings.apiServerOrigin())
.get(`/api/v1/apps?accessToken=CLOUDRON_TOKEN&boxVersion=${constants.VERSION}&unstable=false`, () => true)
.get(`/api/v1/apps?accessToken=CLOUDRON_TOKEN&boxVersion=${constants.VERSION}&unstable=true`, () => true)
.reply(200, { apps: [] });
superagent.get(SERVER_URL + '/api/v1/appstore/apps')
+1 -1
View File
@@ -123,7 +123,7 @@ let gDefaults = (function () {
result[exports.TIME_ZONE_KEY] = 'America/Los_Angeles';
result[exports.CLOUDRON_NAME_KEY] = 'Cloudron';
result[exports.DYNAMIC_DNS_KEY] = false;
result[exports.UNSTABLE_APPS_KEY] = false;
result[exports.UNSTABLE_APPS_KEY] = true;
result[exports.LICENSE_KEY] = '';
result[exports.CLOUDRON_ID_KEY] = '';
result[exports.CLOUDRON_TOKEN_KEY] = '';
+3 -3
View File
@@ -98,18 +98,18 @@ describe('Settings', function () {
it('can get default unstable apps setting', function (done) {
settings.getUnstableAppsConfig(function (error, enabled) {
expect(error).to.be(null);
expect(enabled).to.be(false);
expect(enabled).to.be(true);
done();
});
});
it('can set unstable apps setting', function (done) {
settings.setUnstableAppsConfig(true, function (error) {
settings.setUnstableAppsConfig(false, function (error) {
expect(error).to.be(null);
settings.getUnstableAppsConfig(function (error, enabled) {
expect(error).to.be(null);
expect(enabled).to.be(true);
expect(enabled).to.be(false);
done();
});
});