Files
cloudron-box/src/test/database-test.js

1985 lines
70 KiB
JavaScript
Raw Normal View History

/* global it:false */
/* global describe:false */
/* global before:false */
/* global after:false */
'use strict';
var appdb = require('../appdb.js'),
2019-08-30 13:12:49 -07:00
apps = require('../apps.js'),
2016-04-30 10:16:27 -07:00
async = require('async'),
2016-04-04 12:41:17 -07:00
backupdb = require('../backupdb.js'),
BoxError = require('../boxerror.js'),
database = require('../database'),
2017-10-28 21:42:32 +02:00
domaindb = require('../domaindb'),
2016-04-30 10:16:27 -07:00
eventlogdb = require('../eventlogdb.js'),
expect = require('expect.js'),
2016-09-29 15:11:56 -07:00
groupdb = require('../groupdb.js'),
hat = require('../hat.js'),
2016-05-26 22:34:04 -07:00
mailboxdb = require('../mailboxdb.js'),
2018-01-20 23:40:59 -08:00
maildb = require('../maildb.js'),
2018-12-17 15:53:00 +01:00
notificationdb = require('../notificationdb.js'),
settingsdb = require('../settingsdb.js'),
taskdb = require('../taskdb.js'),
tokendb = require('../tokendb.js'),
userdb = require('../userdb.js'),
_ = require('underscore');
2016-09-29 15:11:56 -07:00
var USER_0 = {
id: 'uuid0',
username: 'uuid0',
password: 'secret',
email: 'safe@me.com',
fallbackEmail: 'safer@me.com',
2016-09-29 15:11:56 -07:00
salt: 'morton',
createdAt: 'sometime back',
modifiedAt: 'now',
resetToken: hat(256),
2018-04-25 16:50:35 +02:00
displayName: '',
twoFactorAuthenticationEnabled: false,
twoFactorAuthenticationSecret: '',
2019-08-08 05:45:56 -07:00
admin: false,
2019-08-30 10:01:09 -07:00
active: true,
2020-02-13 22:06:54 -08:00
source: '',
permissions: null
2016-09-29 15:11:56 -07:00
};
var USER_1 = {
id: 'uuid1',
username: 'uuid1',
password: 'secret',
email: 'safe2@me.com',
fallbackEmail: 'safer2@me.com',
2016-09-29 15:11:56 -07:00
salt: 'tata',
createdAt: 'sometime back',
modifiedAt: 'now',
resetToken: '',
2018-04-25 16:50:35 +02:00
displayName: 'Herbert 1',
twoFactorAuthenticationEnabled: false,
twoFactorAuthenticationSecret: '',
2019-08-08 05:45:56 -07:00
admin: false,
2019-08-30 10:01:09 -07:00
active: true,
2020-02-13 22:06:54 -08:00
source: '',
permissions: null
2016-09-29 15:11:56 -07:00
};
var USER_2 = {
id: 'uuid2',
username: 'uuid2',
password: 'secret',
email: 'safe3@me.com',
fallbackEmail: 'safer3@me.com',
2016-09-29 15:11:56 -07:00
salt: 'tata',
createdAt: 'sometime back',
modifiedAt: 'now',
resetToken: '',
2018-04-25 16:50:35 +02:00
displayName: 'Herbert 2',
twoFactorAuthenticationEnabled: false,
twoFactorAuthenticationSecret: '',
2019-08-08 05:45:56 -07:00
admin: false,
2019-08-30 10:01:09 -07:00
active: true,
2020-02-13 22:06:54 -08:00
source: '',
permissions: null
2016-09-29 15:11:56 -07:00
};
2018-01-26 18:32:13 +01:00
const DOMAIN_0 = {
domain: 'foobar.com',
zoneName: 'foobar.com',
provider: 'digitalocean',
config: { token: 'abcd' },
tlsConfig: { provider: 'fallback' }
2018-01-26 18:32:13 +01:00
};
const DOMAIN_1 = {
domain: 'foo.cloudron.io',
zoneName: 'cloudron.io',
provider: 'manual',
config: null,
tlsConfig: { provider: 'fallback' }
2018-01-26 18:32:13 +01:00
};
describe('database', function () {
before(function (done) {
async.series([
database.initialize,
database._clear
], done);
});
after(function (done) {
async.series([
database._clear,
database.uninitialize
], done);
});
2018-12-17 15:53:00 +01:00
describe('notifications', function () {
var EVENT_0 = {
id: 'event_0',
action: 'action',
source: {},
data: {}
};
var EVENT_1 = {
id: 'event_1',
action: 'action',
source: {},
data: {}
};
var EVENT_2 = {
id: 'event_2',
action: 'action',
source: {},
data: {}
};
2018-12-17 15:53:00 +01:00
var NOTIFICATION_0 = {
userId: USER_0.id,
eventId: EVENT_0.id,
title: 'title z', // titles are this way for ordering
2018-12-17 15:53:00 +01:00
message: 'some message there',
};
var NOTIFICATION_1 = {
userId: USER_0.id,
eventId: EVENT_1.id,
title: 'title y',
2018-12-17 15:53:00 +01:00
message: 'some message there',
};
var NOTIFICATION_2 = {
userId: USER_1.id,
eventId: EVENT_2.id,
title: 'title x',
2018-12-17 15:53:00 +01:00
message: 'some message there',
};
var NOTIFICATION_3 = {
userId: USER_0.id,
eventId: null,
title: 'title w',
message: 'some message there',
};
2018-12-17 15:53:00 +01:00
before(function (done) {
async.series([
userdb.add.bind(null, USER_0.id, USER_0),
userdb.add.bind(null, USER_1.id, USER_1),
eventlogdb.add.bind(null, EVENT_0.id, EVENT_0.action, EVENT_0.source, EVENT_0.data),
eventlogdb.add.bind(null, EVENT_1.id, EVENT_1.action, EVENT_1.source, EVENT_1.data),
eventlogdb.add.bind(null, EVENT_2.id, EVENT_2.action, EVENT_2.source, EVENT_2.data),
2018-12-17 15:53:00 +01:00
], done);
});
after(function (done) {
database._clear(done);
});
it('can add notification', function (done) {
notificationdb.add(NOTIFICATION_0, function (error, result) {
expect(error).to.equal(null);
expect(result).to.be.a('string');
NOTIFICATION_0.id = result;
done();
});
});
it('can add second notification', function (done) {
notificationdb.add(NOTIFICATION_1, function (error, result) {
expect(error).to.equal(null);
expect(result).to.be.a('string');
NOTIFICATION_1.id = result;
done();
});
});
it('can add third notification for another user', function (done) {
notificationdb.add(NOTIFICATION_2, function (error, result) {
expect(error).to.equal(null);
expect(result).to.be.a('string');
NOTIFICATION_2.id = result;
done();
});
});
it('can get by id', function (done) {
notificationdb.get(NOTIFICATION_0.id, function (error, result) {
expect(error).to.equal(null);
expect(result.id).to.equal(NOTIFICATION_0.id);
expect(result.title).to.equal(NOTIFICATION_0.title);
expect(result.message).to.equal(NOTIFICATION_0.message);
expect(result.acknowledged).to.equal(false);
done();
});
});
it('cannot get by non-existing id', function (done) {
notificationdb.get('nopenothere', function (error, result) {
expect(error).to.be.a(BoxError);
expect(error.reason).to.equal(BoxError.NOT_FOUND);
2018-12-17 15:53:00 +01:00
expect(result).to.not.be.ok();
done();
});
});
it('can list by user', function (done) {
notificationdb.listByUserIdPaged(USER_0.id, 1, 100, function (error, result) {
expect(error).to.equal(null);
expect(result).to.be.an('array');
expect(result.length).to.equal(2);
expect(result[0].id).to.equal(NOTIFICATION_0.id);
expect(result[0].title).to.equal(NOTIFICATION_0.title);
expect(result[0].message).to.equal(NOTIFICATION_0.message);
expect(result[0].acknowledged).to.equal(false);
done();
});
});
it('cannot update non-existing notification', function (done) {
notificationdb.update('isnotthere', { acknowledged: true }, function (error) {
expect(error).to.be.a(BoxError);
expect(error.reason).to.equal(BoxError.NOT_FOUND);
2018-12-17 15:53:00 +01:00
done();
});
});
it('update succeeds', function (done) {
2019-03-22 14:26:25 -07:00
notificationdb.update(NOTIFICATION_1.id, { acknowledged: true }, function (error) {
2018-12-17 15:53:00 +01:00
expect(error).to.equal(null);
2019-03-22 14:26:25 -07:00
notificationdb.get(NOTIFICATION_1.id, function (error, result) {
2018-12-17 15:53:00 +01:00
expect(error).to.equal(null);
expect(result.id).to.equal(NOTIFICATION_1.id);
expect(result.title).to.equal(NOTIFICATION_1.title);
expect(result.message).to.equal(NOTIFICATION_1.message);
expect(result.acknowledged).to.equal(true);
done();
});
});
});
it('deletion succeeds', function (done) {
notificationdb.del(NOTIFICATION_0.id, function (error) {
expect(error).to.equal(null);
notificationdb.get(NOTIFICATION_0.id, function (error, result) {
expect(error).to.be.a(BoxError);
expect(error.reason).to.equal(BoxError.NOT_FOUND);
2018-12-17 15:53:00 +01:00
expect(result).to.not.be.ok();
done();
});
});
});
it('deletion for non-existing notification fails', function (done) {
notificationdb.del('doesnotexts', function (error) {
expect(error).to.be.a(BoxError);
expect(error.reason).to.equal(BoxError.NOT_FOUND);
2018-12-17 15:53:00 +01:00
done();
});
});
it('can add notification without eventId', function (done) {
notificationdb.add(NOTIFICATION_3, function (error, result) {
expect(error).to.equal(null);
expect(result).to.be.a('string');
// stash for further use
NOTIFICATION_3.id = result;
done();
});
});
2018-12-17 15:53:00 +01:00
});
2017-10-28 21:42:32 +02:00
describe('domains', function () {
before(function (done) {
userdb.add(USER_0.id, USER_0, done);
});
after(function (done) {
database._clear(done);
});
2017-10-28 21:42:32 +02:00
it('can add domain', function (done) {
domaindb.add(DOMAIN_0.domain, { zoneName: DOMAIN_0.zoneName, provider: DOMAIN_0.provider, config: DOMAIN_0.config, tlsConfig: DOMAIN_0.tlsConfig }, done);
2017-10-28 21:42:32 +02:00
});
it('can add another domain', function (done) {
domaindb.add(DOMAIN_1.domain, { zoneName: DOMAIN_1.zoneName, provider: DOMAIN_1.provider, config: DOMAIN_1.config, tlsConfig: DOMAIN_1.tlsConfig }, done);
2017-10-28 21:42:32 +02:00
});
it('cannot add same domain twice', function (done) {
domaindb.add(DOMAIN_0.domain, { zoneName: DOMAIN_0.zoneName, provider: DOMAIN_0.provider, config: DOMAIN_0.config, tlsConfig: DOMAIN_0.tlsConfig }, function (error) {
2017-10-28 21:42:32 +02:00
expect(error).to.be.ok();
expect(error.reason).to.be(BoxError.ALREADY_EXISTS);
2017-10-28 21:42:32 +02:00
done();
});
});
it('can get domain', function (done) {
domaindb.get(DOMAIN_0.domain, function (error, result) {
expect(error).to.equal(null);
expect(result).to.be.an('object');
expect(result.domain).to.equal(DOMAIN_0.domain);
expect(result.zoneName).to.equal(DOMAIN_0.zoneName);
expect(result.config).to.eql(DOMAIN_0.config);
done();
});
});
it('can update domain', function (done) {
const newConfig = { provider: 'manual' };
const newTlsConfig = { provider: 'foobar' };
2017-10-28 21:42:32 +02:00
domaindb.update(DOMAIN_1.domain, { provider: DOMAIN_1.provider, config: newConfig, tlsConfig: newTlsConfig }, function (error) {
2017-10-28 21:42:32 +02:00
expect(error).to.equal(null);
domaindb.get(DOMAIN_1.domain, function (error, result) {
expect(error).to.equal(null);
expect(result).to.be.an('object');
expect(result.domain).to.equal(DOMAIN_1.domain);
expect(result.zoneName).to.equal(DOMAIN_1.zoneName);
2018-01-09 14:46:38 -08:00
expect(result.provider).to.equal(DOMAIN_1.provider);
2017-10-28 21:42:32 +02:00
expect(result.config).to.eql(newConfig);
expect(result.tlsConfig).to.eql(newTlsConfig);
2017-10-28 21:42:32 +02:00
DOMAIN_1.config = newConfig;
DOMAIN_1.tlsConfig = newTlsConfig;
2017-10-28 21:42:32 +02:00
done();
});
});
});
it('can get all domains', function (done) {
domaindb.getAll(function (error, result) {
expect(error).to.equal(null);
expect(result).to.be.an('array');
2018-01-26 18:32:13 +01:00
expect(result.length).to.equal(2);
2017-10-28 21:42:32 +02:00
// sorted by domain
2018-01-26 18:32:13 +01:00
expect(result[0].domain).to.equal(DOMAIN_1.domain);
expect(result[0].zoneName).to.equal(DOMAIN_1.zoneName);
expect(result[0].provider).to.equal(DOMAIN_1.provider);
expect(result[0].config).to.eql(DOMAIN_1.config);
expect(result[0].tlsConfig).to.eql(DOMAIN_1.tlsConfig);
2017-10-28 21:42:32 +02:00
2018-01-26 18:32:13 +01:00
expect(result[1].domain).to.equal(DOMAIN_0.domain);
expect(result[1].zoneName).to.equal(DOMAIN_0.zoneName);
expect(result[1].provider).to.equal(DOMAIN_0.provider);
expect(result[1].config).to.eql(DOMAIN_0.config);
expect(result[1].tlsConfig).to.eql(DOMAIN_0.tlsConfig);
2017-10-28 21:42:32 +02:00
done();
});
});
it('cannot delete non-existing domain', function (done) {
domaindb.del('not.exists', function (error) {
expect(error).to.be.a(BoxError);
expect(error.reason).to.equal(BoxError.NOT_FOUND);
2017-10-28 21:42:32 +02:00
done();
});
});
var APP_0 = {
id: 'appid-0',
appStoreId: 'appStoreId-0',
2019-08-30 13:12:49 -07:00
installationState: apps.ISTATE_PENDING_INSTALL,
2019-08-30 09:45:43 -07:00
error: null,
2019-09-22 22:07:14 -07:00
runState: 'running',
location: 'some-location-0',
domain: DOMAIN_0.domain,
manifest: { version: '0.1', dockerImage: 'docker/app0', healthCheckPath: '/', httpPort: 80, title: 'app0' },
httpPort: null,
containerId: null,
portBindings: { port: { hostPort: 5678, type: 'tcp' } },
health: null,
accessRestriction: null,
lastBackupId: null,
memoryLimit: 4294967296,
2020-01-28 21:30:35 -08:00
cpuShares: 1024,
sso: true,
debugMode: null,
reverseProxyConfig: {},
enableBackup: true,
rework how app mailboxes are allocated Our current setup had a mailbox allocated for an app during app install (into the mailboxes table). This has many issues: * When set to a custom mailbox location, there was no way to access this mailbox even via IMAP. Even when using app credentials, we cannot use IMAP since the ldap logic was testing on the addon type (most of our apps only use sendmail addon and thus cannot recvmail). * The mailboxes table was being used to add hidden 'app' type entries. This made it very hard for the user to understand why a mailbox conflicts. For example, if you set an app to use custom mailbox 'blog', this is hidden from all views. The solution is to let an app send email as whatever mailbox name is allocated to it (which we now track in the apps table. the default is in the db already so that REST response contains it). When not using Cloudron email, it will just send mail as that mailbox and the auth checks the "app password" in the addons table. Any replies to that mailbox will end up in the domain's mail server (not our problem). When using cloudron email, the app can send mail like above. Any responses will not end anywhere and bounce since there is no 'mailbox'. This is the expected behavior. If user wants to access this mailbox name, he can create a concrete mailbox and set himself as owner OR set this as an alias. For apps using the recvmail addon, the workflow is to actually create a mailbox at some point. Currently, we have no UI for this 'flow'. It's fine because we have only meemo using it. Intuitive much!
2018-12-06 21:08:19 -08:00
env: {},
mailboxName: 'talktome',
2019-11-14 21:43:14 -08:00
mailboxDomain: DOMAIN_0.domain,
enableAutomaticUpdate: true,
2019-09-15 21:51:38 -07:00
dataDir: null,
2019-03-22 14:26:25 -07:00
tags: [],
2019-08-26 15:28:29 -07:00
label: null,
taskId: null
};
it('cannot delete referenced domain', function (done) {
2019-07-02 20:22:17 -07:00
appdb.add(APP_0.id, APP_0.appStoreId, APP_0.manifest, APP_0.location, APP_0.domain, APP_0.portBindings, APP_0, function (error) {
expect(error).to.be(null);
domaindb.del(DOMAIN_0.domain, function (error) {
expect(error).to.be.a(BoxError);
expect(error.reason).to.equal(BoxError.CONFLICT);
appdb.del(APP_0.id, done);
});
});
});
2017-10-28 21:42:32 +02:00
it('can delete existing domain', function (done) {
domaindb.del(DOMAIN_0.domain, function (error) {
expect(error).to.be(null);
domaindb.get(DOMAIN_0.domain, function (error) {
expect(error).to.be.a(BoxError);
expect(error.reason).to.equal(BoxError.NOT_FOUND);
2017-10-28 21:42:32 +02:00
done();
});
});
});
});
2016-07-14 15:47:20 +02:00
describe('user', function () {
it('can add user', function (done) {
userdb.add(USER_0.id, USER_0, done);
});
2016-02-08 16:25:29 -08:00
it('can add another user', function (done) {
userdb.add(USER_1.id, USER_1, done);
});
it('can add another user with empty username', function (done) {
userdb.add(USER_2.id, USER_2, done);
});
it('cannot add user width same email again', function (done) {
var tmp = JSON.parse(JSON.stringify(USER_0));
tmp.id = 'somethingelse';
tmp.username = 'somethingelse';
userdb.add(tmp.id, tmp, function (error) {
expect(error).to.be.ok();
2019-10-24 14:40:26 -07:00
expect(error.reason).to.be(BoxError.ALREADY_EXISTS);
expect(error.message).to.equal('email already exists');
done();
});
});
it('cannot add user width same username again', function (done) {
var tmp = JSON.parse(JSON.stringify(USER_0));
tmp.id = 'somethingelse';
tmp.email = 'somethingelse@not.taken';
userdb.add(tmp.id, tmp, function (error) {
expect(error).to.be.ok();
2019-10-24 14:40:26 -07:00
expect(error.reason).to.be(BoxError.ALREADY_EXISTS);
expect(error.message).to.equal('username already exists');
done();
});
});
it('can get by user id', function (done) {
userdb.get(USER_0.id, function (error, user) {
expect(error).to.not.be.ok();
expect(user).to.eql(USER_0);
done();
});
});
it('can get by user name', function (done) {
userdb.getByUsername(USER_0.username, function (error, user) {
expect(error).to.not.be.ok();
expect(user).to.eql(USER_0);
done();
});
});
it('can get by email', function (done) {
userdb.getByEmail(USER_0.email, function (error, user) {
expect(error).to.not.be.ok();
expect(user).to.eql(USER_0);
done();
});
});
it('getByResetToken fails for empty resetToken', function (done) {
2020-02-04 17:05:08 +01:00
userdb.getByResetToken('', function (error, user) {
expect(error).to.be.ok();
2019-10-24 14:40:26 -07:00
expect(error.reason).to.be(BoxError.NOT_FOUND);
expect(user).to.not.be.ok();
done();
});
});
2020-02-04 17:05:08 +01:00
it('getByResetToken fails for invalid resetToken', function (done) {
userdb.getByResetToken('invalid', function (error, user) {
expect(error).to.be.ok();
2019-10-24 14:40:26 -07:00
expect(error.reason).to.be(BoxError.NOT_FOUND);
expect(user).to.not.be.ok();
done();
});
});
it('can get by resetToken', function (done) {
2020-02-04 17:05:08 +01:00
userdb.getByResetToken(USER_0.resetToken, function (error, user) {
expect(error).to.not.be.ok();
expect(user).to.eql(USER_0);
done();
});
});
it('can get all with group ids', function (done) {
userdb.getAllWithGroupIds(function (error, all) {
expect(error).to.not.be.ok();
expect(all.length).to.equal(3);
var userCopy;
userCopy = _.extend({}, USER_0);
userCopy.groupIds = [ ];
expect(all[0]).to.eql(userCopy);
userCopy = _.extend({}, USER_1);
userCopy.groupIds = [ ];
expect(all[1]).to.eql(userCopy);
userCopy = _.extend({}, USER_2);
userCopy.groupIds = [ ];
expect(all[2]).to.eql(userCopy);
done();
});
});
it('can get all with group ids paged', function (done) {
userdb.getAllWithGroupIdsPaged(null, 1, 2, function (error, all) {
expect(error).to.not.be.ok();
expect(all.length).to.equal(2);
var userCopy;
userCopy = _.extend({}, USER_0);
userCopy.groupIds = [];
expect(all[0]).to.eql(userCopy);
userCopy = _.extend({}, USER_1);
userCopy.groupIds = [];
expect(all[1]).to.eql(userCopy);
userdb.getAllWithGroupIdsPaged(null, 2, 2, function (error, all) {
expect(error).to.not.be.ok();
expect(all.length).to.equal(1);
var userCopy;
userCopy = _.extend({}, USER_2);
userCopy.groupIds = [];
expect(all[0]).to.eql(userCopy);
done();
});
});
});
it('can get all with group ids paged and search', function (done) {
userdb.getAllWithGroupIdsPaged('id1', 1, 2, function (error, all) {
expect(error).to.not.be.ok();
expect(all.length).to.equal(1);
var userCopy;
userCopy = _.extend({}, USER_1);
userCopy.groupIds = [];
expect(all[0]).to.eql(userCopy);
done();
});
});
it('can get all admins', function (done) {
userdb.getAllAdmins(function (error, all) {
expect(error).to.not.be.ok();
2016-02-08 16:25:29 -08:00
expect(all.length).to.equal(0);
done();
});
});
it('counts the users', function (done) {
userdb.count(function (error, count) {
expect(error).to.not.be.ok();
expect(count).to.equal(3);
done();
});
});
2018-01-20 10:24:11 -08:00
it('can update the user', function (done) {
2016-01-19 12:39:54 +01:00
userdb.update(USER_0.id, { email: 'some@thing.com', displayName: 'Heiter' }, function (error) {
expect(error).to.not.be.ok();
userdb.get(USER_0.id, function (error, user) {
expect(user.email).to.equal('some@thing.com');
2016-01-19 12:39:54 +01:00
expect(user.displayName).to.equal('Heiter');
done();
});
});
});
it('can update the user with already existing email', function (done) {
userdb.update(USER_0.id, { email: USER_2.email }, function (error) {
expect(error).to.be.ok();
2019-10-24 14:40:26 -07:00
expect(error.reason).to.be(BoxError.ALREADY_EXISTS);
expect(error.message).to.equal('email already exists');
done();
});
});
it('can update the user with already existing username', function (done) {
userdb.update(USER_0.id, { username: USER_2.username }, function (error) {
expect(error).to.be.ok();
2019-10-24 14:40:26 -07:00
expect(error.reason).to.be(BoxError.ALREADY_EXISTS);
expect(error.message).to.equal('username already exists');
done();
});
});
it('cannot update with null field', function () {
expect(function () {
userdb.update(USER_0.id, { email: null }, function () {});
}).to.throwError();
});
it('cannot del non-existing user', function (done) {
userdb.del(USER_0.id + USER_0.id, function (error) {
expect(error).to.be.ok();
2019-10-24 14:40:26 -07:00
expect(error.reason).to.be(BoxError.NOT_FOUND);
done();
});
});
it('can del existing user', function (done) {
userdb.del(USER_0.id, function (error) {
expect(error).to.not.be.ok();
done();
});
});
it('did remove the user', function (done) {
userdb.count(function (error, count) {
expect(count).to.equal(2);
done();
});
});
});
2020-01-31 15:28:42 -08:00
describe('appPasswords', function () {
before(function (done) {
userdb.add(USER_0.id, USER_0, done);
});
after(function (done) {
userdb.del(USER_0.id, done);
});
it('can add app password', function (done) {
userdb.addAppPassword('someid', { userId: USER_0.id, hashedPassword: 'hash', name: 'spark', identifier: 'appid' }, done);
});
it('can get app password', function (done) {
userdb.getAppPassword('someid', function (error, result) {
if (error) return done(error);
expect(result.hashedPassword).to.be('hash');
expect(result.name).to.be('spark');
expect(result.identifier).to.be('appid');
done();
});
});
it('can get app passwords', function (done) {
userdb.getAppPasswords(USER_0.id, function (error, results) {
if (error) return done(error);
expect(results.length).to.be(1);
expect(results[0].hashedPassword).to.be('hash');
expect(results[0].name).to.be('spark');
expect(results[0].identifier).to.be('appid');
done();
});
});
it('can del app password', function (done) {
userdb.delAppPassword('someid', done);
});
});
describe('token', function () {
var TOKEN_0 = {
id: 'tid-0',
2018-08-27 14:50:41 -07:00
name: 'token0',
accessToken: hat(8 * 32),
identifier: '0',
clientId: 'clientid-0',
expires: Date.now() + 60 * 60000,
2020-02-06 16:57:33 +01:00
scope: ''
};
var TOKEN_1 = {
id: 'tid-1',
2018-08-27 14:50:41 -07:00
name: 'token1',
accessToken: hat(8 * 32),
identifier: '1',
clientId: 'clientid-1',
expires: Number.MAX_SAFE_INTEGER,
2020-02-06 16:57:33 +01:00
scope: ''
};
var TOKEN_2 = {
id: 'tid-2',
2018-08-27 14:50:41 -07:00
name: 'token2',
accessToken: hat(8 * 32),
identifier: '2',
clientId: 'clientid-2',
expires: Date.now(),
2020-02-06 16:57:33 +01:00
scope: ''
};
it('add succeeds', function (done) {
tokendb.add(TOKEN_0, function (error) {
expect(error).to.be(null);
done();
});
});
it('add of same token fails', function (done) {
tokendb.add(TOKEN_0, function (error) {
expect(error).to.be.a(BoxError);
expect(error.reason).to.be(BoxError.ALREADY_EXISTS);
done();
});
});
it('get succeeds', function (done) {
tokendb.get(TOKEN_0.id, function (error, result) {
expect(error).to.be(null);
expect(result).to.be.an('object');
expect(result).to.be.eql(TOKEN_0);
done();
});
});
it('getByAccessToken succeeds', function (done) {
tokendb.getByAccessToken(TOKEN_0.accessToken, function (error, result) {
expect(error).to.be(null);
expect(result).to.be.an('object');
expect(result).to.be.eql(TOKEN_0);
done();
});
});
it('get of nonexisting token fails', function (done) {
tokendb.getByAccessToken(TOKEN_1.accessToken, function (error, result) {
expect(error).to.be.a(BoxError);
expect(error.reason).to.be(BoxError.NOT_FOUND);
expect(result).to.not.be.ok();
done();
});
});
it('getByIdentifier succeeds', function (done) {
tokendb.getByIdentifier(TOKEN_0.identifier, function (error, result) {
expect(error).to.be(null);
expect(result).to.be.an(Array);
expect(result.length).to.equal(1);
expect(result[0]).to.be.an('object');
expect(result[0]).to.be.eql(TOKEN_0);
done();
});
});
it('delete fails', function (done) {
tokendb.del(TOKEN_0.id + 'x', function (error) {
expect(error).to.be.a(BoxError);
expect(error.reason).to.be(BoxError.NOT_FOUND);
done();
});
});
it('delete succeeds', function (done) {
tokendb.del(TOKEN_0.id, function (error) {
expect(error).to.be(null);
done();
});
});
it('getByIdentifier succeeds after token deletion', function (done) {
tokendb.getByIdentifier(TOKEN_0.identifier, function (error, result) {
expect(error).to.be(null);
expect(result).to.be.an(Array);
expect(result.length).to.equal(0);
done();
});
});
it('cannot delete previously delete record', function (done) {
tokendb.del(TOKEN_0.id, function (error) {
expect(error).to.be.a(BoxError);
expect(error.reason).to.be(BoxError.NOT_FOUND);
done();
});
});
it('delExpired succeeds', function (done) {
tokendb.add(TOKEN_2, function (error) {
expect(error).to.be(null);
tokendb.delExpired(function (error, result) {
expect(error).to.not.be.ok();
expect(result).to.eql(1);
tokendb.getByAccessToken(TOKEN_2.accessToken, function (error, result) {
expect(error).to.be.a(BoxError);
expect(error.reason).to.be(BoxError.NOT_FOUND);
expect(result).to.not.be.ok();
done();
});
});
});
});
});
describe('apps', function () {
var APP_0 = {
id: 'appid-0',
appStoreId: 'appStoreId-0',
2019-08-30 13:12:49 -07:00
installationState: apps.ISTATE_PENDING_INSTALL,
2019-08-30 09:45:43 -07:00
error: null,
2019-09-22 22:07:14 -07:00
runState: 'running',
location: 'some-location-0',
2018-01-26 18:32:13 +01:00
domain: DOMAIN_0.domain,
manifest: { version: '0.1', dockerImage: 'docker/app0', healthCheckPath: '/', httpPort: 80, title: 'app0' },
httpPort: null,
containerId: null,
portBindings: { port: { hostPort: 5678, type: 'tcp' } },
health: null,
accessRestriction: null,
2016-04-19 00:10:11 -07:00
memoryLimit: 4294967296,
2020-01-28 21:30:35 -08:00
cpuShares: 256,
2017-01-19 12:51:16 -08:00
sso: true,
debugMode: null,
reverseProxyConfig: {},
enableBackup: true,
alternateDomains: [],
env: {
'CUSTOM_KEY': 'CUSTOM_VALUE'
rework how app mailboxes are allocated Our current setup had a mailbox allocated for an app during app install (into the mailboxes table). This has many issues: * When set to a custom mailbox location, there was no way to access this mailbox even via IMAP. Even when using app credentials, we cannot use IMAP since the ldap logic was testing on the addon type (most of our apps only use sendmail addon and thus cannot recvmail). * The mailboxes table was being used to add hidden 'app' type entries. This made it very hard for the user to understand why a mailbox conflicts. For example, if you set an app to use custom mailbox 'blog', this is hidden from all views. The solution is to let an app send email as whatever mailbox name is allocated to it (which we now track in the apps table. the default is in the db already so that REST response contains it). When not using Cloudron email, it will just send mail as that mailbox and the auth checks the "app password" in the addons table. Any replies to that mailbox will end up in the domain's mail server (not our problem). When using cloudron email, the app can send mail like above. Any responses will not end anywhere and bounce since there is no 'mailbox'. This is the expected behavior. If user wants to access this mailbox name, he can create a concrete mailbox and set himself as owner OR set this as an alias. For apps using the recvmail addon, the workflow is to actually create a mailbox at some point. Currently, we have no UI for this 'flow'. It's fine because we have only meemo using it. Intuitive much!
2018-12-06 21:08:19 -08:00
},
mailboxName: 'talktome',
2019-11-14 21:43:14 -08:00
mailboxDomain: DOMAIN_0.domain,
enableAutomaticUpdate: true,
2019-09-15 21:51:38 -07:00
dataDir: null,
2019-03-22 14:26:25 -07:00
tags: [],
2019-08-26 15:28:29 -07:00
label: null,
taskId: null
};
2018-01-26 18:32:13 +01:00
var APP_1 = {
id: 'appid-1',
appStoreId: 'appStoreId-1',
2019-08-30 13:12:49 -07:00
installationState: apps.ISTATE_PENDING_INSTALL, // app health tests rely on this initial state
2019-08-30 09:45:43 -07:00
error: null,
2019-09-22 22:07:14 -07:00
runState: 'running',
location: 'some-location-1',
2018-01-26 18:32:13 +01:00
domain: DOMAIN_0.domain,
manifest: { version: '0.2', dockerImage: 'docker/app1', healthCheckPath: '/', httpPort: 80, title: 'app1' },
httpPort: null,
containerId: null,
portBindings: { },
health: null,
accessRestriction: { users: [ 'foobar' ] },
2016-04-19 00:10:11 -07:00
memoryLimit: 0,
2020-01-28 21:30:35 -08:00
cpuShares: 512,
2017-01-19 12:51:16 -08:00
sso: true,
debugMode: null,
reverseProxyConfig: {},
enableBackup: true,
alternateDomains: [],
rework how app mailboxes are allocated Our current setup had a mailbox allocated for an app during app install (into the mailboxes table). This has many issues: * When set to a custom mailbox location, there was no way to access this mailbox even via IMAP. Even when using app credentials, we cannot use IMAP since the ldap logic was testing on the addon type (most of our apps only use sendmail addon and thus cannot recvmail). * The mailboxes table was being used to add hidden 'app' type entries. This made it very hard for the user to understand why a mailbox conflicts. For example, if you set an app to use custom mailbox 'blog', this is hidden from all views. The solution is to let an app send email as whatever mailbox name is allocated to it (which we now track in the apps table. the default is in the db already so that REST response contains it). When not using Cloudron email, it will just send mail as that mailbox and the auth checks the "app password" in the addons table. Any replies to that mailbox will end up in the domain's mail server (not our problem). When using cloudron email, the app can send mail like above. Any responses will not end anywhere and bounce since there is no 'mailbox'. This is the expected behavior. If user wants to access this mailbox name, he can create a concrete mailbox and set himself as owner OR set this as an alias. For apps using the recvmail addon, the workflow is to actually create a mailbox at some point. Currently, we have no UI for this 'flow'. It's fine because we have only meemo using it. Intuitive much!
2018-12-06 21:08:19 -08:00
env: {},
mailboxName: 'callme',
2019-11-14 21:43:14 -08:00
mailboxDomain: DOMAIN_0.domain,
enableAutomaticUpdate: true,
2019-09-15 21:51:38 -07:00
dataDir: null,
2019-03-22 14:26:25 -07:00
tags: [],
2019-08-26 15:28:29 -07:00
label: null,
taskId: null
};
2018-01-26 18:32:13 +01:00
before(function (done) {
async.series([
userdb.add.bind(null, USER_0.id, USER_0),
domaindb.add.bind(null, DOMAIN_0.domain, { zoneName: DOMAIN_0.zoneName, provider: DOMAIN_0.provider, config: DOMAIN_0.config, tlsConfig: DOMAIN_0.tlsConfig })
], done);
2018-01-26 18:32:13 +01:00
});
after(function (done) {
database._clear(done);
});
it('add fails due to missing arguments', function () {
expect(function () { appdb.add(APP_0.id, APP_0.manifest, APP_0.installationState, function () {}); }).to.throwError();
expect(function () { appdb.add(APP_0.id, function () {}); }).to.throwError();
});
it('exists returns false', function (done) {
appdb.exists(APP_0.id, function (error, exists) {
expect(error).to.be(null);
expect(exists).to.be(false);
done();
});
});
it('add succeeds', function (done) {
2019-07-02 20:22:17 -07:00
appdb.add(APP_0.id, APP_0.appStoreId, APP_0.manifest, APP_0.location, APP_0.domain, APP_0.portBindings, APP_0, function (error) {
expect(error).to.be(null);
done();
});
});
it('exists succeeds', function (done) {
appdb.exists(APP_0.id, function (error, exists) {
expect(error).to.be(null);
expect(exists).to.be(true);
done();
});
});
it('getPortBindings succeeds', function (done) {
appdb.getPortBindings(APP_0.id, function (error, bindings) {
expect(error).to.be(null);
expect(bindings).to.be.an(Object);
expect(bindings).to.be.eql({ port: { hostPort: '5678', type: 'tcp' } });
done();
});
});
it('add of same app fails', function (done) {
2019-07-02 20:22:17 -07:00
appdb.add(APP_0.id, APP_0.appStoreId, APP_0.manifest, APP_0.location, APP_0.domain, [], APP_0, function (error) {
expect(error).to.be.a(BoxError);
expect(error.reason).to.be(BoxError.ALREADY_EXISTS);
done();
});
});
it('get succeeds', function (done) {
appdb.get(APP_0.id, function (error, result) {
expect(error).to.be(null);
expect(result).to.be.an('object');
expect(_.omit(result, ['creationTime', 'updateTime', 'ts', 'healthTime'])).to.be.eql(APP_0);
done();
});
});
it('get of nonexisting code fails', function (done) {
appdb.get(APP_1.id, function (error, result) {
expect(error).to.be.a(BoxError);
expect(error.reason).to.be(BoxError.NOT_FOUND);
expect(result).to.not.be.ok();
done();
});
});
it('update succeeds', function (done) {
APP_0.installationState = 'some-other-status';
APP_0.location = 'some-other-location';
APP_0.manifest.version = '0.2';
2015-10-13 09:52:21 +02:00
APP_0.accessRestriction = '';
APP_0.httpPort = 1337;
APP_0.memoryLimit = 1337;
2020-01-28 21:30:35 -08:00
APP_0.cpuShares = 1024;
2015-10-13 09:52:21 +02:00
var data = {
installationState: APP_0.installationState,
location: APP_0.location,
2018-12-11 16:26:19 -08:00
domain: APP_0.domain,
2015-10-13 09:52:21 +02:00
manifest: APP_0.manifest,
accessRestriction: APP_0.accessRestriction,
httpPort: APP_0.httpPort,
2020-01-28 21:30:35 -08:00
memoryLimit: APP_0.memoryLimit,
cpuShares: APP_0.cpuShares
2015-10-13 09:52:21 +02:00
};
appdb.update(APP_0.id, data, function (error) {
expect(error).to.be(null);
appdb.get(APP_0.id, function (error, result) {
expect(error).to.be(null);
expect(result).to.be.an('object');
expect(_.omit(result, ['creationTime', 'updateTime', 'ts', 'healthTime'])).to.be.eql(APP_0);
done();
});
});
});
it('getByHttpPort succeeds', function (done) {
appdb.getByHttpPort(APP_0.httpPort, function (error, result) {
expect(error).to.be(null);
expect(result).to.be.an('object');
expect(_.omit(result, ['creationTime', 'updateTime', 'ts', 'healthTime'])).to.be.eql(APP_0);
done();
});
});
it('update of nonexisting app fails', function (done) {
appdb.update(APP_1.id, { installationState: APP_1.installationState, location: APP_1.location }, function (error) {
expect(error).to.be.a(BoxError);
expect(error.reason).to.be(BoxError.NOT_FOUND);
done();
});
});
it('add second app succeeds', function (done) {
2019-07-02 20:22:17 -07:00
appdb.add(APP_1.id, APP_1.appStoreId, APP_1.manifest, APP_1.location, APP_1.domain, [], APP_1, function (error) {
expect(error).to.be(null);
done();
});
});
it('getAll succeeds', function (done) {
rework how app mailboxes are allocated Our current setup had a mailbox allocated for an app during app install (into the mailboxes table). This has many issues: * When set to a custom mailbox location, there was no way to access this mailbox even via IMAP. Even when using app credentials, we cannot use IMAP since the ldap logic was testing on the addon type (most of our apps only use sendmail addon and thus cannot recvmail). * The mailboxes table was being used to add hidden 'app' type entries. This made it very hard for the user to understand why a mailbox conflicts. For example, if you set an app to use custom mailbox 'blog', this is hidden from all views. The solution is to let an app send email as whatever mailbox name is allocated to it (which we now track in the apps table. the default is in the db already so that REST response contains it). When not using Cloudron email, it will just send mail as that mailbox and the auth checks the "app password" in the addons table. Any replies to that mailbox will end up in the domain's mail server (not our problem). When using cloudron email, the app can send mail like above. Any responses will not end anywhere and bounce since there is no 'mailbox'. This is the expected behavior. If user wants to access this mailbox name, he can create a concrete mailbox and set himself as owner OR set this as an alias. For apps using the recvmail addon, the workflow is to actually create a mailbox at some point. Currently, we have no UI for this 'flow'. It's fine because we have only meemo using it. Intuitive much!
2018-12-06 21:08:19 -08:00
appdb.getAll(function (error, result) {
expect(error).to.be(null);
expect(result).to.be.an(Array);
expect(result.length).to.be(2);
expect(_.omit(result[0], ['creationTime', 'updateTime','ts', 'healthTime'])).to.be.eql(APP_0);
expect(_.omit(result[1], ['creationTime', 'updateTime','ts', 'healthTime'])).to.be.eql(APP_1);
done();
});
});
it('getAppStoreIds succeeds', function (done) {
appdb.getAppStoreIds(function (error, results) {
expect(error).to.be(null);
expect(results).to.be.an(Array);
expect(results.length).to.be(2);
expect(results[0].appStoreId).to.equal(APP_0.appStoreId);
expect(results[1].appStoreId).to.equal(APP_1.appStoreId);
done();
});
});
it('delete succeeds', function (done) {
appdb.del(APP_0.id, function (error) {
expect(error).to.be(null);
done();
});
});
it('getPortBindings should be empty', function (done) {
appdb.getPortBindings(APP_0.id, function (error, bindings) {
expect(error).to.be(null);
expect(bindings).to.be.an(Object);
expect(bindings).to.be.eql({ });
done();
});
});
it('cannot delete previously delete record', function (done) {
appdb.del(APP_0.id, function (error) {
expect(error).to.be.a(BoxError);
expect(error.reason).to.be(BoxError.NOT_FOUND);
done();
});
});
2019-08-30 13:12:49 -07:00
it('can set app as healthy', function (done) {
appdb.setHealth(APP_1.id, apps.HEALTH_HEALTHY, new Date(), function (error) {
expect(error).to.be(null);
2019-08-30 13:12:49 -07:00
done();
});
});
it('cannot set health of unknown app', function (done) {
2019-08-30 13:12:49 -07:00
appdb.setHealth('randomId', apps.HEALTH_HEALTHY, new Date(), function (error) {
expect(error).to.be.ok();
done();
});
});
it('return empty addon config array for invalid app', function (done) {
appdb.getAddonConfigByAppId('randomid', function (error, results) {
expect(error).to.be(null);
expect(results).to.eql([ ]);
done();
});
});
it('setAddonConfig succeeds', function (done) {
2017-03-26 19:06:36 -07:00
appdb.setAddonConfig(APP_1.id, 'addonid1', [ { name: 'ENV1', value: 'env' }, { name: 'ENV2', value: 'env2' } ], function (error) {
expect(error).to.be(null);
done();
});
});
it('setAddonConfig succeeds', function (done) {
appdb.setAddonConfig(APP_1.id, 'addonid2', [ { name: 'ENV3', value: 'env' } ], function (error) {
expect(error).to.be(null);
done();
});
});
it('getAddonConfig succeeds', function (done) {
appdb.getAddonConfig(APP_1.id, 'addonid1', function (error, results) {
expect(error).to.be(null);
2017-03-26 19:06:36 -07:00
expect(results).to.eql([ { name: 'ENV1', value: 'env' }, { name: 'ENV2', value: 'env2' } ]);
done();
});
});
it('getAddonConfigByAppId succeeds', function (done) {
appdb.getAddonConfigByAppId(APP_1.id, function (error, results) {
expect(error).to.be(null);
2017-03-26 19:06:36 -07:00
expect(results).to.eql([ { name: 'ENV1', value: 'env' }, { name: 'ENV2', value: 'env2' }, { name: 'ENV3', value: 'env' } ]);
done();
});
});
it('getAddonConfigByName succeeds', function (done) {
appdb.getAddonConfigByName(APP_1.id, 'addonid1', 'ENV2', function (error, value) {
expect(error).to.be(null);
expect(value).to.be('env2');
done();
});
});
it('getAddonConfigByName of unknown value succeeds', function (done) {
appdb.getAddonConfigByName(APP_1.id, 'addonid1', 'NOPE', function (error) {
expect(error.reason).to.be(BoxError.NOT_FOUND);
done();
});
});
it('unsetAddonConfig succeeds', function (done) {
appdb.unsetAddonConfig(APP_1.id, 'addonid1', function (error) {
expect(error).to.be(null);
done();
});
});
it('unsetAddonConfig did remove configs', function (done) {
appdb.getAddonConfigByAppId(APP_1.id, function (error, results) {
expect(error).to.be(null);
expect(results).to.eql([ { name: 'ENV3', value: 'env' }]);
done();
});
});
it('unsetAddonConfigByAppId succeeds', function (done) {
appdb.unsetAddonConfigByAppId(APP_1.id, function (error) {
expect(error).to.be(null);
done();
});
});
it('unsetAddonConfigByAppId did remove configs', function (done) {
appdb.getAddonConfigByAppId(APP_1.id, function (error, results) {
expect(error).to.be(null);
expect(results).to.eql([ ]);
done();
});
});
});
describe('tasks', function () {
let taskId;
let TASK = {
type: 'tasktype',
args: { x: 1 },
percent: 0,
message: 'starting task'
};
it('add succeeds', function (done) {
taskdb.add(TASK, function (error, id) {
expect(error).to.be(null);
expect(id).to.be.ok();
taskId = id;
done();
});
});
it('get succeeds', function (done) {
taskdb.get(taskId, function (error, task) {
expect(error).to.be(null);
expect(_.pick(task, Object.keys(TASK))).to.eql(TASK);
done();
});
});
it('update succeeds', function (done) {
TASK.percent = 34;
TASK.message = 'almost ther';
taskdb.update(taskId, { percent: TASK.percent, message: TASK.message }, function (error) {
expect(error).to.be(null);
taskdb.get(taskId, function (error, task) {
expect(_.pick(task, Object.keys(TASK))).to.eql(TASK);
done();
});
});
});
2018-12-08 20:12:23 -08:00
it('list succeeds - does not exist', function (done) {
2018-12-11 16:26:19 -08:00
taskdb.listByTypePaged('randomtask', 1, 1, function (error, tasks) {
2018-12-08 20:12:23 -08:00
expect(error).to.be(null);
expect(tasks.length).to.be(0);
done();
});
});
it('list succeeds - by type', function (done) {
2018-12-11 16:26:19 -08:00
taskdb.listByTypePaged(TASK.type, 1, 1, function (error, tasks) {
2018-12-08 20:12:23 -08:00
expect(error).to.be(null);
expect(tasks.length).to.be(1);
expect(_.pick(tasks[0], Object.keys(TASK))).to.eql(TASK);
done();
});
});
it('list succeeds - all', function (done) {
2018-12-11 16:26:19 -08:00
taskdb.listByTypePaged(null, 1, 1, function (error, tasks) {
2018-12-08 20:12:23 -08:00
expect(error).to.be(null);
expect(tasks.length).to.be(1);
expect(_.pick(tasks[0], Object.keys(TASK))).to.eql(TASK);
done();
});
});
it('del succeeds', function (done) {
taskdb.del(taskId, function (error) {
expect(error).to.be(null);
taskdb.get(taskId, function (error) {
expect(error.reason).to.be(BoxError.NOT_FOUND);
done();
});
});
});
});
describe('settings', function () {
it('can set value', function (done) {
settingsdb.set('somekey', 'somevalue', function (error) {
expect(error).to.be(null);
done();
});
});
it('can get the set value', function (done) {
settingsdb.get('somekey', function (error, value) {
expect(error).to.be(null);
expect(value).to.be('somevalue');
done();
});
});
it('can get all values', function (done) {
settingsdb.getAll(function (error, result) {
expect(error).to.be(null);
expect(result).to.be.an(Array);
expect(result[0].name).to.be('somekey');
expect(result[0].value).to.be('somevalue');
expect(result.length).to.be(1); // the value set above
done();
});
});
it('can update a value', function (done) {
settingsdb.set('somekey', 'someothervalue', function (error) {
expect(error).to.be(null);
done();
});
});
it('can get updated value', function (done) {
settingsdb.get('somekey', function (error, value) {
expect(error).to.be(null);
expect(value).to.be('someothervalue');
done();
});
});
});
2016-04-04 12:41:17 -07:00
describe('backup', function () {
it('add succeeds', function (done) {
var backup = {
id: 'backup-box',
version: '1.0.0',
type: backupdb.BACKUP_TYPE_BOX,
2017-04-18 11:57:59 +02:00
dependsOn: [ 'dep1' ],
manifest: null,
format: 'tgz'
2016-04-04 12:41:17 -07:00
};
2019-04-13 17:14:04 -07:00
backupdb.add(backup.id, backup, function (error) {
2016-04-04 12:41:17 -07:00
expect(error).to.be(null);
done();
});
});
it('get succeeds', function (done) {
backupdb.get('backup-box', function (error, result) {
expect(error).to.be(null);
expect(result.version).to.be('1.0.0');
expect(result.type).to.be(backupdb.BACKUP_TYPE_BOX);
expect(result.creationTime).to.be.a(Date);
expect(result.dependsOn).to.eql(['dep1']);
expect(result.manifest).to.eql(null);
2016-04-04 12:41:17 -07:00
done();
});
});
it('get of unknown id fails', function (done) {
backupdb.get('somerandom', function (error, result) {
expect(error).to.be.a(BoxError);
expect(error.reason).to.be(BoxError.NOT_FOUND);
2016-04-04 12:41:17 -07:00
expect(result).to.not.be.ok();
done();
});
});
it('getByTypePaged succeeds', function (done) {
backupdb.getByTypePaged(backupdb.BACKUP_TYPE_BOX, 1, 5, function (error, results) {
2016-04-04 12:41:17 -07:00
expect(error).to.be(null);
expect(results).to.be.an(Array);
expect(results.length).to.be(1);
expect(results[0].id).to.be('backup-box');
expect(results[0].version).to.be('1.0.0');
expect(results[0].dependsOn).to.eql(['dep1']);
expect(results[0].manifest).to.eql(null);
2016-04-04 12:41:17 -07:00
done();
});
});
it('delete succeeds', function (done) {
backupdb.del('backup-box', function (error, result) {
expect(error).to.be(null);
expect(result).to.not.be.ok();
backupdb.get('backup-box', function (error, result) {
expect(error).to.be.a(BoxError);
expect(error.reason).to.equal(BoxError.NOT_FOUND);
2016-04-04 12:41:17 -07:00
expect(result).to.not.be.ok();
done();
});
});
});
it('add app succeeds', function (done) {
var backup = {
id: 'app_appid_123',
2016-04-04 12:41:17 -07:00
version: '1.0.0',
type: backupdb.BACKUP_TYPE_APP,
2017-04-18 11:57:59 +02:00
dependsOn: [ ],
manifest: { foo: 'bar' },
format: 'tgz'
2016-04-04 12:41:17 -07:00
};
2019-04-13 17:14:04 -07:00
backupdb.add(backup.id, backup, function (error) {
2016-04-04 12:41:17 -07:00
expect(error).to.be(null);
done();
});
});
it('get succeeds', function (done) {
backupdb.get('app_appid_123', function (error, result) {
2016-04-04 12:41:17 -07:00
expect(error).to.be(null);
expect(result.version).to.be('1.0.0');
expect(result.type).to.be(backupdb.BACKUP_TYPE_APP);
expect(result.creationTime).to.be.a(Date);
expect(result.dependsOn).to.eql([]);
expect(result.manifest).to.eql({ foo: 'bar' });
2016-04-04 12:41:17 -07:00
done();
});
});
it('getByAppIdPaged succeeds', function (done) {
backupdb.getByAppIdPaged(1, 5, 'appid', function (error, results) {
expect(error).to.be(null);
expect(results).to.be.an(Array);
expect(results.length).to.be(1);
expect(results[0].id).to.be('app_appid_123');
2016-04-04 12:41:17 -07:00
expect(results[0].version).to.be('1.0.0');
expect(results[0].dependsOn).to.eql([]);
expect(results[0].manifest).to.eql({ foo: 'bar' });
2016-04-04 12:41:17 -07:00
done();
});
});
it('delete succeeds', function (done) {
backupdb.del('app_appid_123', function (error, result) {
2016-04-04 12:41:17 -07:00
expect(error).to.be(null);
expect(result).to.not.be.ok();
backupdb.get('app_appid_123', function (error, result) {
expect(error).to.be.a(BoxError);
expect(error.reason).to.equal(BoxError.NOT_FOUND);
2016-04-04 12:41:17 -07:00
expect(result).to.not.be.ok();
done();
});
});
});
});
2016-04-30 10:16:27 -07:00
2016-04-30 12:41:27 -07:00
describe('eventlog', function () {
2016-04-30 10:16:27 -07:00
it('add succeeds', function (done) {
eventlogdb.add('someid', 'some.event', { ip: '1.2.3.4' }, { appId: 'thatapp' }, function (error, result) {
2016-04-30 10:16:27 -07:00
expect(error).to.be(null);
expect(result).to.equal('someid');
2016-04-30 10:16:27 -07:00
done();
});
});
it('get succeeds', function (done) {
eventlogdb.get('someid', function (error, result) {
expect(error).to.be(null);
expect(result.id).to.be('someid');
expect(result.action).to.be('some.event');
expect(result.creationTime).to.be.a(Date);
2016-04-30 12:41:27 -07:00
expect(result.source).to.be.eql({ ip: '1.2.3.4' });
2016-04-30 10:16:27 -07:00
expect(result.data).to.be.eql({ appId: 'thatapp' });
done();
});
});
it('get of unknown id fails', function (done) {
eventlogdb.get('notfoundid', function (error, result) {
expect(error).to.be.a(BoxError);
expect(error.reason).to.be(BoxError.NOT_FOUND);
2016-04-30 10:16:27 -07:00
expect(result).to.not.be.ok();
done();
});
});
it('getAllPaged succeeds', function (done) {
2018-03-05 17:17:01 +01:00
eventlogdb.getAllPaged([], null, 1, 1, function (error, results) {
2016-04-30 10:16:27 -07:00
expect(error).to.be(null);
expect(results).to.be.an(Array);
expect(results.length).to.be(1);
expect(results[0].id).to.be('someid');
expect(results[0].action).to.be('some.event');
2016-04-30 12:41:27 -07:00
expect(results[0].source).to.be.eql({ ip: '1.2.3.4' });
2016-04-30 10:16:27 -07:00
expect(results[0].data).to.be.eql({ appId: 'thatapp' });
2016-11-28 16:02:59 +01:00
done();
});
});
it('getAllPaged succeeds with source search', function (done) {
2018-03-05 17:17:01 +01:00
eventlogdb.getAllPaged([], '1.2.3.4', 1, 1, function (error, results) {
2016-11-28 16:02:59 +01:00
expect(error).to.be(null);
expect(results).to.be.an(Array);
expect(results.length).to.be(1);
expect(results[0].id).to.be('someid');
expect(results[0].action).to.be('some.event');
expect(results[0].source).to.be.eql({ ip: '1.2.3.4' });
expect(results[0].data).to.be.eql({ appId: 'thatapp' });
done();
});
});
it('getAllPaged succeeds with data search', function (done) {
2018-03-05 17:17:01 +01:00
eventlogdb.getAllPaged([], 'thatapp', 1, 1, function (error, results) {
2016-11-28 16:02:59 +01:00
expect(error).to.be(null);
expect(results).to.be.an(Array);
expect(results.length).to.be(1);
expect(results[0].id).to.be('someid');
expect(results[0].action).to.be('some.event');
expect(results[0].source).to.be.eql({ ip: '1.2.3.4' });
expect(results[0].data).to.be.eql({ appId: 'thatapp' });
2016-04-30 10:16:27 -07:00
done();
});
});
2016-07-25 12:36:43 -07:00
it('upsert with no existing entry succeeds', function (done) {
eventlogdb.upsert('logineventid', 'user.login', { ip: '1.2.3.4' }, { appId: 'thatapp' }, function (error, result) {
expect(error).to.be(null);
expect(result).to.equal('logineventid');
done();
});
});
it('upsert with existing entry succeeds', function (done) {
eventlogdb.get('logineventid', function (error, result) {
expect(error).to.equal(null);
var oldCreationTime = result.creationTime;
// now wait 2sec
setTimeout(function () {
eventlogdb.upsert('logineventid_notused', 'user.login', { ip: '1.2.3.4' }, { appId: 'thatapp' }, function (error, result) {
expect(error).to.be(null);
expect(result).to.equal('logineventid');
eventlogdb.get('logineventid', function (error, result) {
expect(error).to.equal(null);
// should have changed
expect(oldCreationTime).to.not.equal(result.creationTime);
done();
});
});
}, 2000);
});
});
2019-02-05 14:45:26 +01:00
it('upsert with existing old entry succeeds', function (done) {
var yesterday = new Date();
yesterday.setDate(yesterday.getDate() - 1);
database.query('INSERT INTO eventlog (id, action, source, data, creationTime) VALUES (?, ?, ?, ?, ?)', [ 'anotherid', 'user.login2', JSON.stringify({ ip: '1.2.3.4' }), JSON.stringify({ appId: 'thatapp' }), yesterday ], function (error) {
2019-02-05 14:45:26 +01:00
expect(error).to.equal(null);
eventlogdb.upsert('anotherid_new', 'user.login2', { ip: '1.2.3.4' }, { appId: 'thatapp' }, function (error, result) {
expect(error).to.be(null);
expect(result).to.equal('anotherid_new');
done();
});
});
});
2016-07-25 12:36:43 -07:00
it('delByCreationTime succeeds', function (done) {
async.each([ 'persistent.event', 'transient.event', 'anothertransient.event', 'anotherpersistent.event' ], function (e, callback) {
eventlogdb.add('someid' + Math.random(), e, { ip: '1.2.3.4' }, { appId: 'thatapp' }, callback);
}, function (error) {
2016-07-25 12:36:43 -07:00
expect(error).to.be(null);
2019-03-22 14:26:25 -07:00
eventlogdb.delByCreationTime(new Date(Date.now() + 1000), function (error) {
2016-07-25 12:36:43 -07:00
expect(error).to.be(null);
2018-03-05 17:17:01 +01:00
eventlogdb.getAllPaged([], null, 1, 100, function (error, results) {
expect(error).to.be(null);
expect(results.length).to.be(0);
done();
});
2016-07-25 12:36:43 -07:00
});
});
});
it('delByCreationTime succeeds with notifications referencing it', function (done) {
async.each([ 'persistent.event', 'transient.event', 'anothertransient.event', 'anotherpersistent.event' ], function (e, callback) {
var eventId = 'someid' + Math.random();
eventlogdb.add(eventId, e, { ip: '1.2.3.4' }, { appId: 'thatapp' }, function (error) {
expect(error).to.be(null);
var notification = {
userId: USER_0.id,
eventId: eventId,
title: 'first one',
message: 'some message there',
};
notificationdb.add(notification, callback);
});
}, function (error) {
expect(error).to.be(null);
eventlogdb.delByCreationTime(new Date(), function (error) {
expect(error).to.be(null);
eventlogdb.getAllPaged([], null, 1, 100, function (error, results) {
expect(error).to.be(null);
expect(results.length).to.be(0);
done();
});
});
});
});
2016-04-30 10:16:27 -07:00
});
2016-05-26 22:34:04 -07:00
2016-09-29 15:11:56 -07:00
describe('groups', function () {
before(function (done) {
async.series([
database.initialize,
database._clear,
userdb.add.bind(null, USER_0.id, USER_0),
userdb.add.bind(null, USER_1.id, USER_1),
userdb.add.bind(null, USER_2.id, USER_2)
], done);
});
var GROUP_ID_1 = 'foundersid';
it('can create a group', function (done) {
2018-07-26 10:20:19 -07:00
groupdb.add(GROUP_ID_1, 'founders', function (error) {
2016-09-29 15:11:56 -07:00
expect(error).to.be(null);
done();
});
});
it('can get existing group', function (done) {
groupdb.get(GROUP_ID_1, function (error, result) {
expect(error).to.be(null);
expect(result.name).to.be('founders');
done();
});
});
it('can add member to the group', function (done) {
groupdb.addMember(GROUP_ID_1, USER_0.id, function (error) {
expect(error).to.be(null);
done();
});
});
it('cannot add invalid user to group', function (done) {
groupdb.addMember(GROUP_ID_1, 'random', function (error) {
expect(error.reason).to.be(BoxError.NOT_FOUND);
2016-09-29 15:11:56 -07:00
done();
});
});
it('can set members', function (done) {
groupdb.setMembers(GROUP_ID_1, [ USER_1.id, USER_2.id ], function (error) {
expect(error).to.be(null);
done();
});
});
it('can list users of group', function (done) {
groupdb.getMembers(GROUP_ID_1, function (error, result) {
expect(error).to.be(null);
expect(result).to.eql([ USER_1.id, USER_2.id ]);
done();
});
});
it('cannot delete non-existent member', function (done) {
groupdb.removeMember(GROUP_ID_1, 'random', function (error) {
expect(error.reason).to.be(BoxError.NOT_FOUND);
2016-09-29 15:11:56 -07:00
done();
});
});
it('can remove existing member', function (done) {
groupdb.removeMember(GROUP_ID_1, USER_1.id, function (error) {
expect(error).to.be(null);
done();
});
});
it('can getWithMembers', function (done) {
groupdb.getWithMembers(GROUP_ID_1, function (error, result) {
expect(error).to.be(null);
expect(result.name).to.be('founders');
expect(result.userIds).to.eql([ USER_2.id ]);
done();
});
});
it('can getAll', function (done) {
groupdb.getAll(function (error, result) {
expect(error).to.be(null);
expect(result.length).to.be(1);
expect(result[0].name).to.be('founders');
2016-09-29 15:11:56 -07:00
done();
});
});
it('can getAllWithMembers', function (done) {
groupdb.getAllWithMembers(function (error, result) {
expect(error).to.be(null);
expect(result.length).to.be(1);
2016-09-29 15:11:56 -07:00
expect(result[0].name).to.be('founders');
expect(result[0].userIds).to.eql([ USER_2.id ]);
2016-09-29 15:11:56 -07:00
done();
});
});
it('can set groups', function (done) {
groupdb.setMembership(USER_0.id, [ GROUP_ID_1 ], function (error) {
2016-09-29 15:11:56 -07:00
expect(error).to.be(null);
done();
});
});
it('can get groups', function (done) {
groupdb.getMembership(USER_0.id, function (error, result) {
2016-09-29 15:11:56 -07:00
expect(error).to.be(null);
expect(result).to.eql([ GROUP_ID_1 ]);
2016-09-29 15:11:56 -07:00
done();
});
});
});
describe('importFromFile', function () {
before(function (done) {
async.series([
database.initialize,
database._clear
], done);
});
it('cannot import from non-existent file', function (done) {
database.importFromFile('/does/not/exist', function (error) {
expect(error).to.be.ok();
done();
});
});
2017-11-24 15:31:03 -08:00
it('can export to file', function (done) {
2019-05-07 15:31:32 +02:00
// arch only has maria db which lacks some mysqldump options we need, this is only here to allow running the tests :-/
if (require('child_process').execSync('/usr/bin/mysqldump --version').toString().indexOf('MariaDB') !== -1) return done();
2017-11-24 15:31:03 -08:00
database.exportToFile('/tmp/box.mysqldump', function (error) {
expect(error).to.be(null);
done();
});
});
it('can import from file', function (done) {
2019-05-07 15:31:32 +02:00
// arch only has maria db which lacks some mysqldump options we need, this is only here to allow running the tests :-/
if (require('child_process').execSync('/usr/bin/mysqldump --version').toString().indexOf('MariaDB') !== -1) return done();
2017-11-24 15:31:03 -08:00
database.importFromFile('/tmp/box.mysqldump', function (error) {
expect(error).to.be(null);
done();
});
});
});
2016-05-26 22:34:04 -07:00
describe('mailboxes', function () {
before(function (done) {
2018-02-11 00:04:41 -08:00
async.series([
domaindb.add.bind(null, DOMAIN_0.domain, { zoneName: DOMAIN_0.zoneName, provider: DOMAIN_0.provider, config: DOMAIN_0.config, tlsConfig: DOMAIN_0.tlsConfig }),
maildb.add.bind(null, DOMAIN_0.domain, {})
2018-02-11 00:04:41 -08:00
], done);
2018-01-26 18:32:13 +01:00
});
2018-01-26 18:32:13 +01:00
after(function (done) {
database._clear(done);
});
2016-09-25 23:21:55 -07:00
it('add user mailbox succeeds', function (done) {
rework how app mailboxes are allocated Our current setup had a mailbox allocated for an app during app install (into the mailboxes table). This has many issues: * When set to a custom mailbox location, there was no way to access this mailbox even via IMAP. Even when using app credentials, we cannot use IMAP since the ldap logic was testing on the addon type (most of our apps only use sendmail addon and thus cannot recvmail). * The mailboxes table was being used to add hidden 'app' type entries. This made it very hard for the user to understand why a mailbox conflicts. For example, if you set an app to use custom mailbox 'blog', this is hidden from all views. The solution is to let an app send email as whatever mailbox name is allocated to it (which we now track in the apps table. the default is in the db already so that REST response contains it). When not using Cloudron email, it will just send mail as that mailbox and the auth checks the "app password" in the addons table. Any replies to that mailbox will end up in the domain's mail server (not our problem). When using cloudron email, the app can send mail like above. Any responses will not end anywhere and bounce since there is no 'mailbox'. This is the expected behavior. If user wants to access this mailbox name, he can create a concrete mailbox and set himself as owner OR set this as an alias. For apps using the recvmail addon, the workflow is to actually create a mailbox at some point. Currently, we have no UI for this 'flow'. It's fine because we have only meemo using it. Intuitive much!
2018-12-06 21:08:19 -08:00
mailboxdb.addMailbox('girish', DOMAIN_0.domain, 'uid-0', function (error) {
2016-05-26 22:34:04 -07:00
expect(error).to.be(null);
done();
});
});
it('cannot add dup entry', function (done) {
rework how app mailboxes are allocated Our current setup had a mailbox allocated for an app during app install (into the mailboxes table). This has many issues: * When set to a custom mailbox location, there was no way to access this mailbox even via IMAP. Even when using app credentials, we cannot use IMAP since the ldap logic was testing on the addon type (most of our apps only use sendmail addon and thus cannot recvmail). * The mailboxes table was being used to add hidden 'app' type entries. This made it very hard for the user to understand why a mailbox conflicts. For example, if you set an app to use custom mailbox 'blog', this is hidden from all views. The solution is to let an app send email as whatever mailbox name is allocated to it (which we now track in the apps table. the default is in the db already so that REST response contains it). When not using Cloudron email, it will just send mail as that mailbox and the auth checks the "app password" in the addons table. Any replies to that mailbox will end up in the domain's mail server (not our problem). When using cloudron email, the app can send mail like above. Any responses will not end anywhere and bounce since there is no 'mailbox'. This is the expected behavior. If user wants to access this mailbox name, he can create a concrete mailbox and set himself as owner OR set this as an alias. For apps using the recvmail addon, the workflow is to actually create a mailbox at some point. Currently, we have no UI for this 'flow'. It's fine because we have only meemo using it. Intuitive much!
2018-12-06 21:08:19 -08:00
mailboxdb.addMailbox('girish', DOMAIN_0.domain, 'uid-1', function (error) {
2019-10-24 13:34:14 -07:00
expect(error.reason).to.be(BoxError.ALREADY_EXISTS);
2016-05-26 22:34:04 -07:00
done();
});
});
2016-09-25 23:21:55 -07:00
it('add app mailbox succeeds', function (done) {
rework how app mailboxes are allocated Our current setup had a mailbox allocated for an app during app install (into the mailboxes table). This has many issues: * When set to a custom mailbox location, there was no way to access this mailbox even via IMAP. Even when using app credentials, we cannot use IMAP since the ldap logic was testing on the addon type (most of our apps only use sendmail addon and thus cannot recvmail). * The mailboxes table was being used to add hidden 'app' type entries. This made it very hard for the user to understand why a mailbox conflicts. For example, if you set an app to use custom mailbox 'blog', this is hidden from all views. The solution is to let an app send email as whatever mailbox name is allocated to it (which we now track in the apps table. the default is in the db already so that REST response contains it). When not using Cloudron email, it will just send mail as that mailbox and the auth checks the "app password" in the addons table. Any replies to that mailbox will end up in the domain's mail server (not our problem). When using cloudron email, the app can send mail like above. Any responses will not end anywhere and bounce since there is no 'mailbox'. This is the expected behavior. If user wants to access this mailbox name, he can create a concrete mailbox and set himself as owner OR set this as an alias. For apps using the recvmail addon, the workflow is to actually create a mailbox at some point. Currently, we have no UI for this 'flow'. It's fine because we have only meemo using it. Intuitive much!
2018-12-06 21:08:19 -08:00
mailboxdb.addMailbox('support', DOMAIN_0.domain, 'osticket', function (error) {
2016-09-25 23:21:55 -07:00
expect(error).to.be(null);
done();
});
});
2016-05-26 22:34:04 -07:00
it('get succeeds', function (done) {
2018-01-26 18:32:13 +01:00
mailboxdb.getMailbox('support', DOMAIN_0.domain, function (error, mailbox) {
2016-05-26 22:34:04 -07:00
expect(error).to.be(null);
2017-11-11 01:03:23 +01:00
expect(mailbox.name).to.equal('support');
expect(mailbox.ownerId).to.equal('osticket');
2018-01-26 18:32:13 +01:00
expect(mailbox.domain).to.equal(DOMAIN_0.domain);
2016-05-26 22:34:04 -07:00
expect(mailbox.creationTime).to.be.a(Date);
done();
});
});
2016-09-25 23:21:55 -07:00
it('list mailboxes succeeds', function (done) {
2019-10-22 20:47:28 -07:00
mailboxdb.listMailboxes(DOMAIN_0.domain, 1, 10, function (error, mailboxes) {
expect(error).to.be(null);
2016-09-25 23:21:55 -07:00
expect(mailboxes.length).to.be(2);
expect(mailboxes[0].name).to.be('girish');
expect(mailboxes[1].name).to.be('support');
done();
});
});
2016-09-25 23:21:55 -07:00
it('can set alias', function (done) {
2018-01-26 18:32:13 +01:00
mailboxdb.setAliasesForName('support', DOMAIN_0.domain, [ 'support2', 'help' ], function (error) {
2016-09-25 23:21:55 -07:00
expect(error).to.be(null);
done();
});
});
it('can get aliases of name', function (done) {
2018-01-26 18:32:13 +01:00
mailboxdb.getAliasesForName('support', DOMAIN_0.domain, function (error, results) {
expect(error).to.be(null);
expect(results.length).to.be(2);
expect(results[0]).to.be('help');
expect(results[1]).to.be('support2');
done();
});
});
2016-09-25 23:21:55 -07:00
it('can get alias', function (done) {
2018-01-26 18:32:13 +01:00
mailboxdb.getAlias('support2', DOMAIN_0.domain, function (error, result) {
2016-09-25 23:21:55 -07:00
expect(error).to.be(null);
expect(result.name).to.be('support2');
expect(result.aliasTarget).to.be('support');
done();
});
});
it('can list aliases', function (done) {
2019-10-22 20:47:28 -07:00
mailboxdb.listAliases(DOMAIN_0.domain, 1, 10, function (error, results) {
2016-09-25 23:21:55 -07:00
expect(error).to.be(null);
expect(results.length).to.be(2);
expect(results[0].name).to.be('help');
expect(results[0].aliasTarget).to.be('support');
expect(results[1].name).to.be('support2');
done();
});
});
it('can get by owner id', function (done) {
mailboxdb.getByOwnerId('osticket', function (error, results) {
expect(error).to.be(null);
expect(results.length).to.be(3);
expect(results[0].name).to.be('help');
expect(results[1].name).to.be('support');
expect(results[2].name).to.be('support2');
done();
});
});
2016-09-27 16:34:28 -07:00
it('cannot get non-existing group', function (done) {
2019-08-23 15:09:06 -07:00
mailboxdb.getList('random', DOMAIN_0.domain, function (error) {
2019-10-24 13:34:14 -07:00
expect(error.reason).to.be(BoxError.NOT_FOUND);
2016-09-27 16:34:28 -07:00
done();
});
});
2016-12-15 16:13:16 +01:00
it('can change name', function (done) {
2018-01-26 18:32:13 +01:00
mailboxdb.updateName('support', DOMAIN_0.domain, 'support3', DOMAIN_0.domain, function (error) {
2016-12-15 16:13:16 +01:00
expect(error).to.be(null);
2018-01-26 18:32:13 +01:00
mailboxdb.updateName('support3', DOMAIN_0.domain, 'support', DOMAIN_0.domain, done);
2016-12-15 16:13:16 +01:00
});
});
it('cannot change name to existing one', function (done) {
2018-01-26 18:32:13 +01:00
mailboxdb.updateName('support', DOMAIN_0.domain, 'support2', DOMAIN_0.domain, function (error) {
2016-12-15 16:13:16 +01:00
expect(error).to.be.ok();
2019-10-24 13:34:14 -07:00
expect(error.reason).to.eql(BoxError.ALREADY_EXISTS);
2016-12-15 16:13:16 +01:00
done();
});
});
it('unset aliases', function (done) {
2018-01-26 18:32:13 +01:00
mailboxdb.setAliasesForName('support', DOMAIN_0.domain, [], function (error) {
expect(error).to.be(null);
2018-01-26 18:32:13 +01:00
mailboxdb.getAliasesForName('support', DOMAIN_0.domain, function (error, results) {
expect(error).to.be(null);
expect(results.length).to.be(0);
done();
});
});
});
2016-05-26 22:34:04 -07:00
it('del succeeds', function (done) {
2018-01-26 18:32:13 +01:00
mailboxdb.del('girish', DOMAIN_0.domain, function (error) {
2016-05-26 22:34:04 -07:00
expect(error).to.be(null);
done();
});
});
2016-09-25 23:21:55 -07:00
it('del by ownerId succeeds', function (done) {
mailboxdb.delByOwnerId('osticket', function (error) {
expect(error).to.be(null);
mailboxdb.getByOwnerId('osticket', function (error) {
2016-09-25 23:21:55 -07:00
expect(error).to.be.ok();
2019-10-24 13:34:14 -07:00
expect(error.reason).to.be(BoxError.NOT_FOUND);
2016-09-25 23:21:55 -07:00
done();
});
});
});
2016-05-26 22:34:04 -07:00
});
2018-01-20 23:40:59 -08:00
describe('mail', function () {
const MAIL_DOMAIN_0 = {
domain: DOMAIN_0.domain,
enabled: false,
relay: { provider: 'cloudron-smtp' },
catchAll: [ ],
mailFromValidation: true,
dkimSelector: 'cloudron'
2018-01-20 23:40:59 -08:00
};
2018-01-26 18:32:13 +01:00
before(function (done) {
domaindb.add(DOMAIN_0.domain, { zoneName: DOMAIN_0.zoneName, provider: DOMAIN_0.provider, config: DOMAIN_0.config, tlsConfig: DOMAIN_0.tlsConfig }, done);
2018-01-20 23:40:59 -08:00
});
2018-01-26 18:32:13 +01:00
after(function (done) {
database._clear(done);
2018-01-20 23:40:59 -08:00
});
it('cannot add non-existing domain', function (done) {
maildb.add(MAIL_DOMAIN_0.domain + 'nope', {}, function (error) {
2018-01-20 23:40:59 -08:00
expect(error).to.be.ok();
2019-10-24 13:34:14 -07:00
expect(error.reason).to.be(BoxError.NOT_FOUND);
2018-01-26 18:32:13 +01:00
done();
});
});
it('can add domain', function (done) {
maildb.add(MAIL_DOMAIN_0.domain, {}, function (error) {
2018-01-26 18:32:13 +01:00
expect(error).to.equal(null);
done();
});
});
it('can get all domains', function (done) {
rework how app mailboxes are allocated Our current setup had a mailbox allocated for an app during app install (into the mailboxes table). This has many issues: * When set to a custom mailbox location, there was no way to access this mailbox even via IMAP. Even when using app credentials, we cannot use IMAP since the ldap logic was testing on the addon type (most of our apps only use sendmail addon and thus cannot recvmail). * The mailboxes table was being used to add hidden 'app' type entries. This made it very hard for the user to understand why a mailbox conflicts. For example, if you set an app to use custom mailbox 'blog', this is hidden from all views. The solution is to let an app send email as whatever mailbox name is allocated to it (which we now track in the apps table. the default is in the db already so that REST response contains it). When not using Cloudron email, it will just send mail as that mailbox and the auth checks the "app password" in the addons table. Any replies to that mailbox will end up in the domain's mail server (not our problem). When using cloudron email, the app can send mail like above. Any responses will not end anywhere and bounce since there is no 'mailbox'. This is the expected behavior. If user wants to access this mailbox name, he can create a concrete mailbox and set himself as owner OR set this as an alias. For apps using the recvmail addon, the workflow is to actually create a mailbox at some point. Currently, we have no UI for this 'flow'. It's fine because we have only meemo using it. Intuitive much!
2018-12-06 21:08:19 -08:00
maildb.list(function (error, result) {
2018-01-26 18:32:13 +01:00
expect(error).to.equal(null);
expect(result).to.be.an(Array);
expect(result[0]).to.be.an('object');
expect(result[0].domain).to.eql(MAIL_DOMAIN_0.domain);
2018-01-20 23:40:59 -08:00
done();
});
});
it('can get domain', function (done) {
maildb.get(MAIL_DOMAIN_0.domain, function (error, result) {
expect(error).to.equal(null);
expect(result).to.be.an('object');
expect(result).to.eql(MAIL_DOMAIN_0);
done();
});
});
});
});