Compare commits
14 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 62174658cf | |||
| 3d26e8a666 | |||
| 3d337640ef | |||
| 985eaf8ca9 | |||
| e0bee13812 | |||
| 7c6922d228 | |||
| bf68c2d321 | |||
| fd51320fb7 | |||
| 815392ba38 | |||
| f8c110f75c | |||
| 70f9ceb1b8 | |||
| 2353a8b5fa | |||
| cf1c2dc1ee | |||
| 467283d5e0 |
@@ -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
|
||||
|
||||
|
||||
Generated
+21
-18
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
|
||||
|
||||
@@ -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, {}));
|
||||
|
||||
@@ -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
@@ -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] = '';
|
||||
|
||||
@@ -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();
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user