Revert "Add no-use-before-define linter rule"
This reverts commit fdcc5d68a2.
Unfortunately, this requires us to move exports to the bottom.
This in turn causes circular dep issues and also access of
exports.GLOBAL_VAR in the global context
This commit is contained in:
@@ -14,8 +14,7 @@ module.exports = [
|
||||
},
|
||||
rules: {
|
||||
semi: "error",
|
||||
"prefer-const": "error",
|
||||
"no-use-before-define": "error",
|
||||
"prefer-const": "error"
|
||||
}
|
||||
}
|
||||
];
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
'use strict';
|
||||
|
||||
exports = module.exports = {
|
||||
run
|
||||
};
|
||||
|
||||
const apps = require('./apps.js'),
|
||||
assert = require('node:assert'),
|
||||
AuditSource = require('./auditsource.js'),
|
||||
@@ -11,10 +15,6 @@ const apps = require('./apps.js'),
|
||||
safe = require('safetydance'),
|
||||
superagent = require('@cloudron/superagent');
|
||||
|
||||
exports = module.exports = {
|
||||
run
|
||||
};
|
||||
|
||||
const UNHEALTHY_THRESHOLD = 20 * 60 * 1000; // 20 minutes
|
||||
|
||||
const OOM_EVENT_LIMIT = 60 * 60 * 1000; // will only raise 1 oom event every hour
|
||||
|
||||
@@ -1,5 +1,16 @@
|
||||
'use strict';
|
||||
|
||||
exports = module.exports = {
|
||||
download,
|
||||
upload,
|
||||
verify,
|
||||
getFileExtension,
|
||||
copy,
|
||||
|
||||
_saveFsMetadata: saveFsMetadata,
|
||||
_restoreFsMetadata: restoreFsMetadata
|
||||
};
|
||||
|
||||
const assert = require('node:assert'),
|
||||
async = require('async'),
|
||||
backupSites = require('../backupsites.js'),
|
||||
@@ -372,13 +383,3 @@ async function verify(backupSite, remotePath, integrityMap, progressCallback) {
|
||||
};
|
||||
}
|
||||
|
||||
exports = module.exports = {
|
||||
download,
|
||||
upload,
|
||||
verify,
|
||||
getFileExtension,
|
||||
copy,
|
||||
|
||||
_saveFsMetadata: saveFsMetadata,
|
||||
_restoreFsMetadata: restoreFsMetadata
|
||||
};
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
'use strict';
|
||||
|
||||
exports = module.exports = {
|
||||
check
|
||||
};
|
||||
|
||||
const backups = require('./backups.js'),
|
||||
backupFormats = require('./backupformats.js'),
|
||||
backupSites = require('./backupsites.js'),
|
||||
@@ -32,6 +36,3 @@ async function check(backupId, progressCallback) {
|
||||
};
|
||||
}
|
||||
|
||||
exports = module.exports = {
|
||||
check
|
||||
};
|
||||
|
||||
@@ -1,5 +1,33 @@
|
||||
'use strict';
|
||||
|
||||
exports = module.exports = {
|
||||
get,
|
||||
getByIdentifierAndStatePaged,
|
||||
getLatestInTargetByIdentifier, // brutal function name
|
||||
add,
|
||||
update,
|
||||
setState,
|
||||
list,
|
||||
listBySiteId,
|
||||
listByTypePaged,
|
||||
del,
|
||||
|
||||
removePrivateFields,
|
||||
|
||||
startIntegrityCheck,
|
||||
|
||||
BACKUP_IDENTIFIER_BOX: 'box',
|
||||
BACKUP_IDENTIFIER_MAIL: 'mail',
|
||||
|
||||
BACKUP_TYPE_APP: 'app',
|
||||
BACKUP_TYPE_BOX: 'box',
|
||||
BACKUP_TYPE_MAIL: 'mail',
|
||||
|
||||
BACKUP_STATE_NORMAL: 'normal', // should rename to created to avoid listing in UI?
|
||||
BACKUP_STATE_CREATING: 'creating',
|
||||
BACKUP_STATE_ERROR: 'error',
|
||||
};
|
||||
|
||||
const assert = require('node:assert'),
|
||||
BoxError = require('./boxerror.js'),
|
||||
database = require('./database.js'),
|
||||
@@ -195,30 +223,3 @@ async function startIntegrityCheck(backup) {
|
||||
return taskId;
|
||||
}
|
||||
|
||||
exports = module.exports = {
|
||||
get,
|
||||
getByIdentifierAndStatePaged,
|
||||
getLatestInTargetByIdentifier, // brutal function name
|
||||
add,
|
||||
update,
|
||||
setState,
|
||||
list,
|
||||
listBySiteId,
|
||||
listByTypePaged,
|
||||
del,
|
||||
|
||||
removePrivateFields,
|
||||
|
||||
startIntegrityCheck,
|
||||
|
||||
BACKUP_IDENTIFIER_BOX: 'box',
|
||||
BACKUP_IDENTIFIER_MAIL: 'mail',
|
||||
|
||||
BACKUP_TYPE_APP: 'app',
|
||||
BACKUP_TYPE_BOX: 'box',
|
||||
BACKUP_TYPE_MAIL: 'mail',
|
||||
|
||||
BACKUP_STATE_NORMAL: 'normal', // should rename to created to avoid listing in UI?
|
||||
BACKUP_STATE_CREATING: 'creating',
|
||||
BACKUP_STATE_ERROR: 'error',
|
||||
};
|
||||
|
||||
@@ -1,5 +1,19 @@
|
||||
'use strict';
|
||||
|
||||
exports = module.exports = {
|
||||
fullBackup,
|
||||
appBackup,
|
||||
|
||||
restore,
|
||||
|
||||
downloadApp,
|
||||
backupApp,
|
||||
|
||||
downloadMail,
|
||||
|
||||
upload,
|
||||
};
|
||||
|
||||
const apps = require('./apps.js'),
|
||||
assert = require('node:assert'),
|
||||
backupFormats = require('./backupformats.js'),
|
||||
@@ -557,16 +571,3 @@ async function appBackup(appId, backupSiteId, options, progressCallback) {
|
||||
return backupId;
|
||||
}
|
||||
|
||||
exports = module.exports = {
|
||||
fullBackup,
|
||||
appBackup,
|
||||
|
||||
restore,
|
||||
|
||||
downloadApp,
|
||||
backupApp,
|
||||
|
||||
downloadMail,
|
||||
|
||||
upload,
|
||||
};
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
'use strict';
|
||||
|
||||
const assert = require('node:assert'),
|
||||
fs = require('node:fs'),
|
||||
path = require('node:path');
|
||||
|
||||
exports = module.exports = {
|
||||
getChanges
|
||||
};
|
||||
|
||||
const assert = require('node:assert'),
|
||||
fs = require('node:fs'),
|
||||
path = require('node:path');
|
||||
|
||||
function getChanges(version) {
|
||||
assert.strictEqual(typeof version, 'string');
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
'use strict';
|
||||
|
||||
module.exports = exports = {
|
||||
exports = module.exports = {
|
||||
fqdn,
|
||||
getName,
|
||||
|
||||
|
||||
@@ -1,5 +1,15 @@
|
||||
'use strict';
|
||||
|
||||
exports = module.exports = {
|
||||
removePrivateFields,
|
||||
injectPrivateFields,
|
||||
upsert,
|
||||
get,
|
||||
del,
|
||||
wait,
|
||||
verifyDomainConfig
|
||||
};
|
||||
|
||||
const assert = require('node:assert'),
|
||||
BoxError = require('../boxerror.js'),
|
||||
constants = require('../constants.js'),
|
||||
@@ -246,12 +256,3 @@ async function verifyDomainConfig(domainObject) {
|
||||
return credentials;
|
||||
}
|
||||
|
||||
exports = module.exports = {
|
||||
removePrivateFields,
|
||||
injectPrivateFields,
|
||||
upsert,
|
||||
get,
|
||||
del,
|
||||
wait,
|
||||
verifyDomainConfig
|
||||
};
|
||||
|
||||
@@ -1,5 +1,15 @@
|
||||
'use strict';
|
||||
|
||||
exports = module.exports = {
|
||||
removePrivateFields,
|
||||
injectPrivateFields,
|
||||
upsert,
|
||||
get,
|
||||
del,
|
||||
wait,
|
||||
verifyDomainConfig
|
||||
};
|
||||
|
||||
const assert = require('node:assert'),
|
||||
BoxError = require('../boxerror.js'),
|
||||
constants = require('../constants.js'),
|
||||
@@ -282,12 +292,3 @@ async function verifyDomainConfig(domainObject) {
|
||||
return sanitizedConfig;
|
||||
}
|
||||
|
||||
exports = module.exports = {
|
||||
removePrivateFields,
|
||||
injectPrivateFields,
|
||||
upsert,
|
||||
get,
|
||||
del,
|
||||
wait,
|
||||
verifyDomainConfig
|
||||
};
|
||||
|
||||
@@ -1,5 +1,15 @@
|
||||
'use strict';
|
||||
|
||||
exports = module.exports = {
|
||||
removePrivateFields,
|
||||
injectPrivateFields,
|
||||
upsert,
|
||||
get,
|
||||
del,
|
||||
wait,
|
||||
verifyDomainConfig
|
||||
};
|
||||
|
||||
const assert = require('node:assert'),
|
||||
constants = require('../constants.js'),
|
||||
BoxError = require('../boxerror.js'),
|
||||
@@ -157,12 +167,3 @@ async function verifyDomainConfig(domainObject) {
|
||||
return credentials;
|
||||
}
|
||||
|
||||
exports = module.exports = {
|
||||
removePrivateFields,
|
||||
injectPrivateFields,
|
||||
upsert,
|
||||
get,
|
||||
del,
|
||||
wait,
|
||||
verifyDomainConfig
|
||||
};
|
||||
|
||||
@@ -1,5 +1,15 @@
|
||||
'use strict';
|
||||
|
||||
exports = module.exports = {
|
||||
removePrivateFields,
|
||||
injectPrivateFields,
|
||||
upsert,
|
||||
get,
|
||||
del,
|
||||
wait,
|
||||
verifyDomainConfig
|
||||
};
|
||||
|
||||
const assert = require('node:assert'),
|
||||
BoxError = require('../boxerror.js'),
|
||||
constants = require('../constants.js'),
|
||||
@@ -243,12 +253,3 @@ async function verifyDomainConfig(domainObject) {
|
||||
return credentials;
|
||||
}
|
||||
|
||||
exports = module.exports = {
|
||||
removePrivateFields,
|
||||
injectPrivateFields,
|
||||
upsert,
|
||||
get,
|
||||
del,
|
||||
wait,
|
||||
verifyDomainConfig
|
||||
};
|
||||
|
||||
@@ -1,5 +1,15 @@
|
||||
'use strict';
|
||||
|
||||
exports = module.exports = {
|
||||
removePrivateFields,
|
||||
injectPrivateFields,
|
||||
upsert,
|
||||
get,
|
||||
del,
|
||||
wait,
|
||||
verifyDomainConfig
|
||||
};
|
||||
|
||||
const assert = require('node:assert'),
|
||||
BoxError = require('../boxerror.js'),
|
||||
constants = require('../constants.js'),
|
||||
@@ -255,12 +265,3 @@ async function verifyDomainConfig(domainObject) {
|
||||
return credentials;
|
||||
}
|
||||
|
||||
exports = module.exports = {
|
||||
removePrivateFields,
|
||||
injectPrivateFields,
|
||||
upsert,
|
||||
get,
|
||||
del,
|
||||
wait,
|
||||
verifyDomainConfig
|
||||
};
|
||||
|
||||
@@ -1,5 +1,15 @@
|
||||
'use strict';
|
||||
|
||||
exports = module.exports = {
|
||||
removePrivateFields,
|
||||
injectPrivateFields,
|
||||
upsert,
|
||||
get,
|
||||
del,
|
||||
wait,
|
||||
verifyDomainConfig
|
||||
};
|
||||
|
||||
const assert = require('node:assert'),
|
||||
BoxError = require('../boxerror.js'),
|
||||
constants = require('../constants.js'),
|
||||
@@ -162,12 +172,3 @@ async function verifyDomainConfig(domainObject) {
|
||||
return credentials;
|
||||
}
|
||||
|
||||
exports = module.exports = {
|
||||
removePrivateFields,
|
||||
injectPrivateFields,
|
||||
upsert,
|
||||
get,
|
||||
del,
|
||||
wait,
|
||||
verifyDomainConfig
|
||||
};
|
||||
|
||||
@@ -1,5 +1,15 @@
|
||||
'use strict';
|
||||
|
||||
exports = module.exports = {
|
||||
removePrivateFields,
|
||||
injectPrivateFields,
|
||||
upsert,
|
||||
get,
|
||||
del,
|
||||
wait,
|
||||
verifyDomainConfig
|
||||
};
|
||||
|
||||
const assert = require('node:assert'),
|
||||
BoxError = require('../boxerror.js'),
|
||||
constants = require('../constants.js'),
|
||||
@@ -183,12 +193,3 @@ async function verifyDomainConfig(domainObject) {
|
||||
return credentials;
|
||||
}
|
||||
|
||||
exports = module.exports = {
|
||||
removePrivateFields,
|
||||
injectPrivateFields,
|
||||
upsert,
|
||||
get,
|
||||
del,
|
||||
wait,
|
||||
verifyDomainConfig
|
||||
};
|
||||
|
||||
@@ -1,5 +1,15 @@
|
||||
'use strict';
|
||||
|
||||
exports = module.exports = {
|
||||
removePrivateFields,
|
||||
injectPrivateFields,
|
||||
upsert,
|
||||
get,
|
||||
del,
|
||||
wait,
|
||||
verifyDomainConfig
|
||||
};
|
||||
|
||||
const assert = require('node:assert'),
|
||||
BoxError = require('../boxerror.js'),
|
||||
constants = require('../constants.js'),
|
||||
@@ -183,12 +193,3 @@ async function verifyDomainConfig(domainObject) {
|
||||
return credentials;
|
||||
}
|
||||
|
||||
exports = module.exports = {
|
||||
removePrivateFields,
|
||||
injectPrivateFields,
|
||||
upsert,
|
||||
get,
|
||||
del,
|
||||
wait,
|
||||
verifyDomainConfig
|
||||
};
|
||||
|
||||
@@ -1,5 +1,15 @@
|
||||
'use strict';
|
||||
|
||||
exports = module.exports = {
|
||||
removePrivateFields,
|
||||
injectPrivateFields,
|
||||
upsert,
|
||||
get,
|
||||
del,
|
||||
wait,
|
||||
verifyDomainConfig
|
||||
};
|
||||
|
||||
const assert = require('node:assert'),
|
||||
BoxError = require('../boxerror.js'),
|
||||
constants = require('../constants.js'),
|
||||
@@ -249,12 +259,3 @@ async function verifyDomainConfig(domainObject) {
|
||||
return credentials;
|
||||
}
|
||||
|
||||
exports = module.exports = {
|
||||
removePrivateFields,
|
||||
injectPrivateFields,
|
||||
upsert,
|
||||
get,
|
||||
del,
|
||||
wait,
|
||||
verifyDomainConfig
|
||||
};
|
||||
|
||||
@@ -1,5 +1,15 @@
|
||||
'use strict';
|
||||
|
||||
exports = module.exports = {
|
||||
removePrivateFields,
|
||||
injectPrivateFields,
|
||||
upsert,
|
||||
get,
|
||||
del,
|
||||
wait,
|
||||
verifyDomainConfig
|
||||
};
|
||||
|
||||
const { ApiClient, Language } = require('domrobot-client'),
|
||||
assert = require('node:assert'),
|
||||
BoxError = require('../boxerror.js'),
|
||||
@@ -208,12 +218,3 @@ async function verifyDomainConfig(domainObject) {
|
||||
return credentials;
|
||||
}
|
||||
|
||||
exports = module.exports = {
|
||||
removePrivateFields,
|
||||
injectPrivateFields,
|
||||
upsert,
|
||||
get,
|
||||
del,
|
||||
wait,
|
||||
verifyDomainConfig
|
||||
};
|
||||
|
||||
@@ -1,5 +1,15 @@
|
||||
'use strict';
|
||||
|
||||
exports = module.exports = {
|
||||
removePrivateFields,
|
||||
injectPrivateFields,
|
||||
upsert,
|
||||
get,
|
||||
del,
|
||||
wait,
|
||||
verifyDomainConfig
|
||||
};
|
||||
|
||||
const assert = require('node:assert'),
|
||||
constants = require('../constants.js'),
|
||||
BoxError = require('../boxerror.js'),
|
||||
@@ -258,12 +268,3 @@ async function verifyDomainConfig(domainObject) {
|
||||
return credentials;
|
||||
}
|
||||
|
||||
exports = module.exports = {
|
||||
removePrivateFields,
|
||||
injectPrivateFields,
|
||||
upsert,
|
||||
get,
|
||||
del,
|
||||
wait,
|
||||
verifyDomainConfig
|
||||
};
|
||||
|
||||
@@ -1,5 +1,15 @@
|
||||
'use strict';
|
||||
|
||||
exports = module.exports = {
|
||||
removePrivateFields,
|
||||
injectPrivateFields,
|
||||
upsert,
|
||||
get,
|
||||
del,
|
||||
verifyDomainConfig,
|
||||
wait
|
||||
};
|
||||
|
||||
const assert = require('node:assert'),
|
||||
BoxError = require('../boxerror.js'),
|
||||
constants = require('../constants.js'),
|
||||
@@ -275,12 +285,3 @@ async function verifyDomainConfig(domainObject) {
|
||||
return credentials;
|
||||
}
|
||||
|
||||
exports = module.exports = {
|
||||
removePrivateFields,
|
||||
injectPrivateFields,
|
||||
upsert,
|
||||
get,
|
||||
del,
|
||||
verifyDomainConfig,
|
||||
wait
|
||||
};
|
||||
|
||||
@@ -1,5 +1,15 @@
|
||||
'use strict';
|
||||
|
||||
exports = module.exports = {
|
||||
removePrivateFields,
|
||||
injectPrivateFields,
|
||||
upsert,
|
||||
get,
|
||||
del,
|
||||
wait,
|
||||
verifyDomainConfig
|
||||
};
|
||||
|
||||
const assert = require('node:assert'),
|
||||
BoxError = require('../boxerror.js'),
|
||||
constants = require('../constants.js'),
|
||||
@@ -241,12 +251,3 @@ async function verifyDomainConfig(domainObject) {
|
||||
return credentials;
|
||||
}
|
||||
|
||||
exports = module.exports = {
|
||||
removePrivateFields,
|
||||
injectPrivateFields,
|
||||
upsert,
|
||||
get,
|
||||
del,
|
||||
wait,
|
||||
verifyDomainConfig
|
||||
};
|
||||
|
||||
@@ -1,5 +1,15 @@
|
||||
'use strict';
|
||||
|
||||
exports = module.exports = {
|
||||
removePrivateFields,
|
||||
injectPrivateFields,
|
||||
upsert,
|
||||
get,
|
||||
del,
|
||||
wait,
|
||||
verifyDomainConfig
|
||||
};
|
||||
|
||||
const assert = require('node:assert'),
|
||||
BoxError = require('../boxerror.js'),
|
||||
constants = require('../constants.js'),
|
||||
@@ -253,12 +263,3 @@ async function verifyDomainConfig(domainObject) {
|
||||
return credentials;
|
||||
}
|
||||
|
||||
exports = module.exports = {
|
||||
removePrivateFields,
|
||||
injectPrivateFields,
|
||||
upsert,
|
||||
get,
|
||||
del,
|
||||
wait,
|
||||
verifyDomainConfig
|
||||
};
|
||||
|
||||
@@ -1,5 +1,15 @@
|
||||
'use strict';
|
||||
|
||||
exports = module.exports = {
|
||||
removePrivateFields,
|
||||
injectPrivateFields,
|
||||
upsert,
|
||||
get,
|
||||
del,
|
||||
wait,
|
||||
verifyDomainConfig
|
||||
};
|
||||
|
||||
const assert = require('node:assert'),
|
||||
BoxError = require('../boxerror.js'),
|
||||
constants = require('../constants.js'),
|
||||
@@ -225,12 +235,3 @@ async function verifyDomainConfig(domainObject) {
|
||||
return credentials;
|
||||
}
|
||||
|
||||
exports = module.exports = {
|
||||
removePrivateFields,
|
||||
injectPrivateFields,
|
||||
upsert,
|
||||
get,
|
||||
del,
|
||||
wait,
|
||||
verifyDomainConfig
|
||||
};
|
||||
|
||||
@@ -1,5 +1,15 @@
|
||||
'use strict';
|
||||
|
||||
exports = module.exports = {
|
||||
removePrivateFields,
|
||||
injectPrivateFields,
|
||||
upsert,
|
||||
get,
|
||||
del,
|
||||
wait,
|
||||
verifyDomainConfig
|
||||
};
|
||||
|
||||
const assert = require('node:assert'),
|
||||
BoxError = require('../boxerror.js'),
|
||||
constants = require('../constants.js'),
|
||||
@@ -217,12 +227,3 @@ async function verifyDomainConfig(domainObject) {
|
||||
return credentials;
|
||||
}
|
||||
|
||||
exports = module.exports = {
|
||||
removePrivateFields,
|
||||
injectPrivateFields,
|
||||
upsert,
|
||||
get,
|
||||
del,
|
||||
wait,
|
||||
verifyDomainConfig
|
||||
};
|
||||
|
||||
@@ -1,5 +1,15 @@
|
||||
'use strict';
|
||||
|
||||
exports = module.exports = {
|
||||
removePrivateFields,
|
||||
injectPrivateFields,
|
||||
upsert,
|
||||
get,
|
||||
del,
|
||||
wait,
|
||||
verifyDomainConfig,
|
||||
};
|
||||
|
||||
const assert = require('node:assert'),
|
||||
BoxError = require('../boxerror.js'),
|
||||
{ ConfiguredRetryStrategy } = require('@smithy/util-retry'),
|
||||
@@ -261,12 +271,3 @@ async function verifyDomainConfig(domainObject) {
|
||||
return credentials;
|
||||
}
|
||||
|
||||
exports = module.exports = {
|
||||
removePrivateFields,
|
||||
injectPrivateFields,
|
||||
upsert,
|
||||
get,
|
||||
del,
|
||||
wait,
|
||||
verifyDomainConfig,
|
||||
};
|
||||
|
||||
@@ -1,5 +1,15 @@
|
||||
'use strict';
|
||||
|
||||
exports = module.exports = {
|
||||
removePrivateFields,
|
||||
injectPrivateFields,
|
||||
upsert,
|
||||
get,
|
||||
del,
|
||||
wait,
|
||||
verifyDomainConfig
|
||||
};
|
||||
|
||||
const assert = require('node:assert'),
|
||||
constants = require('../constants.js'),
|
||||
BoxError = require('../boxerror.js'),
|
||||
@@ -228,12 +238,3 @@ async function verifyDomainConfig(domainObject) {
|
||||
return credentials;
|
||||
}
|
||||
|
||||
exports = module.exports = {
|
||||
removePrivateFields,
|
||||
injectPrivateFields,
|
||||
upsert,
|
||||
get,
|
||||
del,
|
||||
wait,
|
||||
verifyDomainConfig
|
||||
};
|
||||
|
||||
@@ -1,5 +1,15 @@
|
||||
'use strict';
|
||||
|
||||
exports = module.exports = {
|
||||
removePrivateFields,
|
||||
|
||||
list,
|
||||
add,
|
||||
get,
|
||||
del,
|
||||
update,
|
||||
};
|
||||
|
||||
const assert = require('node:assert'),
|
||||
BoxError = require('./boxerror.js'),
|
||||
constants = require('./constants.js'),
|
||||
@@ -111,12 +121,3 @@ async function del(registry, auditSource) {
|
||||
await eventlog.add(eventlog.ACTION_REGISTRY_DEL, auditSource, { registry: removePrivateFields(registry) });
|
||||
}
|
||||
|
||||
exports = module.exports = {
|
||||
removePrivateFields,
|
||||
|
||||
list,
|
||||
add,
|
||||
get,
|
||||
del,
|
||||
update,
|
||||
};
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
'use strict';
|
||||
|
||||
module.exports = exports = {
|
||||
exports = module.exports = {
|
||||
add,
|
||||
get,
|
||||
list,
|
||||
|
||||
@@ -1,5 +1,21 @@
|
||||
'use strict';
|
||||
|
||||
exports = module.exports = {
|
||||
getConfig,
|
||||
setConfig,
|
||||
|
||||
verifyPassword,
|
||||
maybeCreateUser,
|
||||
|
||||
supports2FA,
|
||||
|
||||
startSyncer,
|
||||
|
||||
removePrivateFields,
|
||||
|
||||
sync
|
||||
};
|
||||
|
||||
const assert = require('node:assert'),
|
||||
AuditSource = require('./auditsource.js'),
|
||||
BoxError = require('./boxerror.js'),
|
||||
@@ -523,18 +539,3 @@ async function sync(progressCallback) {
|
||||
debug('sync: done');
|
||||
}
|
||||
|
||||
exports = module.exports = {
|
||||
getConfig,
|
||||
setConfig,
|
||||
|
||||
verifyPassword,
|
||||
maybeCreateUser,
|
||||
|
||||
supports2FA,
|
||||
|
||||
startSyncer,
|
||||
|
||||
removePrivateFields,
|
||||
|
||||
sync
|
||||
};
|
||||
|
||||
@@ -1,5 +1,10 @@
|
||||
'use strict';
|
||||
|
||||
exports = module.exports = {
|
||||
cleanupTokens,
|
||||
cleanupDockerVolumes
|
||||
};
|
||||
|
||||
const assert = require('node:assert'),
|
||||
BoxError = require('./boxerror.js'),
|
||||
debug = require('debug')('box:janitor'),
|
||||
@@ -7,11 +12,6 @@ const assert = require('node:assert'),
|
||||
safe = require('safetydance'),
|
||||
tokens = require('./tokens.js');
|
||||
|
||||
exports = module.exports = {
|
||||
cleanupTokens,
|
||||
cleanupDockerVolumes
|
||||
};
|
||||
|
||||
const gConnection = new Docker({ socketPath: '/var/run/docker.sock' });
|
||||
|
||||
async function cleanupTokens() {
|
||||
|
||||
130
src/mail.js
130
src/mail.js
@@ -1,5 +1,65 @@
|
||||
'use strict';
|
||||
|
||||
exports = module.exports = {
|
||||
getStatus,
|
||||
checkConfiguration,
|
||||
|
||||
listDomains,
|
||||
|
||||
getDomain,
|
||||
clearDomains,
|
||||
|
||||
removePrivateFields,
|
||||
|
||||
setDnsRecords,
|
||||
upsertDnsRecords,
|
||||
|
||||
validateName,
|
||||
validateDisplayName,
|
||||
|
||||
setMailFromValidation,
|
||||
setCatchAllAddress,
|
||||
setMailRelay,
|
||||
setMailEnabled,
|
||||
setBanner,
|
||||
|
||||
sendTestMail,
|
||||
|
||||
getMailboxCount,
|
||||
listMailboxes,
|
||||
listAllMailboxes,
|
||||
getMailbox,
|
||||
addMailbox,
|
||||
updateMailbox,
|
||||
delMailbox,
|
||||
|
||||
getAlias,
|
||||
getAliases,
|
||||
setAliases,
|
||||
searchAlias,
|
||||
|
||||
getListCount,
|
||||
getLists,
|
||||
getList,
|
||||
addList,
|
||||
updateList,
|
||||
delList,
|
||||
resolveList,
|
||||
|
||||
checkStatus,
|
||||
|
||||
OWNERTYPE_USER: 'user',
|
||||
OWNERTYPE_GROUP: 'group',
|
||||
OWNERTYPE_APP: 'app',
|
||||
|
||||
TYPE_MAILBOX: 'mailbox',
|
||||
TYPE_LIST: 'list',
|
||||
TYPE_ALIAS: 'alias',
|
||||
|
||||
_delByDomain: delByDomain,
|
||||
_updateDomain: updateDomain
|
||||
};
|
||||
|
||||
const assert = require('node:assert'),
|
||||
BoxError = require('./boxerror.js'),
|
||||
constants = require('./constants.js'),
|
||||
@@ -27,8 +87,6 @@ const assert = require('node:assert'),
|
||||
const DNS_OPTIONS = { timeout: 20000, tries: 4 };
|
||||
const REMOVE_MAILBOX_CMD = path.join(__dirname, 'scripts/rmmailbox.sh');
|
||||
|
||||
const OWNERTYPES = [ exports.OWNERTYPE_USER, exports.OWNERTYPE_GROUP, exports.OWNERTYPE_APP ];
|
||||
|
||||
// if you add a field here, listMailboxes has to be updated
|
||||
const MAILBOX_FIELDS = [ 'name', 'type', 'ownerId', 'ownerType', 'aliasName', 'aliasDomain', 'creationTime', 'membersJson', 'membersOnly', 'domain', 'active', 'enablePop3', 'storageQuota', 'messagesQuota' ].join(',');
|
||||
const MAILDB_FIELDS = [ 'domain', 'enabled', 'mailFromValidation', 'catchAllJson', 'relayJson', 'dkimKeyJson', 'dkimSelector', 'bannerJson' ].join(',');
|
||||
@@ -111,6 +169,11 @@ function validateDisplayName(name) {
|
||||
return null;
|
||||
}
|
||||
|
||||
function validateOwnerType(type) {
|
||||
const OWNERTYPES = [ exports.OWNERTYPE_USER, exports.OWNERTYPE_GROUP, exports.OWNERTYPE_APP ];
|
||||
return OWNERTYPES.includes(type);
|
||||
}
|
||||
|
||||
async function getDomain(domain) {
|
||||
assert.strictEqual(typeof domain, 'string');
|
||||
|
||||
@@ -862,7 +925,7 @@ async function addMailbox(name, domain, data, auditSource) {
|
||||
let error = validateName(name);
|
||||
if (error) throw error;
|
||||
|
||||
if (!OWNERTYPES.includes(ownerType)) throw new BoxError(BoxError.BAD_FIELD, 'bad owner type');
|
||||
if (!validateOwnerType(ownerType)) throw new BoxError(BoxError.BAD_FIELD, 'bad owner type');
|
||||
|
||||
[error] = await safe(database.query('INSERT INTO mailboxes (name, type, domain, ownerId, ownerType, active, storageQuota, messagesQuota, enablePop3) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)',
|
||||
[ name, exports.TYPE_MAILBOX, domain, ownerId, ownerType, active, storageQuota, messagesQuota, enablePop3 ]));
|
||||
@@ -888,7 +951,7 @@ async function updateMailbox(name, domain, data, auditSource) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (k === 'ownerType' && !OWNERTYPES.includes(data[k])) throw new BoxError(BoxError.BAD_FIELD, 'bad owner type');
|
||||
if (k === 'ownerType' && !validateOwnerType(data[k])) throw new BoxError(BoxError.BAD_FIELD, 'bad owner type');
|
||||
|
||||
fields.push(k + ' = ?');
|
||||
args.push(data[k]);
|
||||
@@ -1177,62 +1240,3 @@ async function checkStatus() {
|
||||
}
|
||||
}
|
||||
|
||||
exports = module.exports = {
|
||||
getStatus,
|
||||
checkConfiguration,
|
||||
|
||||
listDomains,
|
||||
|
||||
getDomain,
|
||||
clearDomains,
|
||||
|
||||
removePrivateFields,
|
||||
|
||||
setDnsRecords,
|
||||
upsertDnsRecords,
|
||||
|
||||
validateName,
|
||||
validateDisplayName,
|
||||
|
||||
setMailFromValidation,
|
||||
setCatchAllAddress,
|
||||
setMailRelay,
|
||||
setMailEnabled,
|
||||
setBanner,
|
||||
|
||||
sendTestMail,
|
||||
|
||||
getMailboxCount,
|
||||
listMailboxes,
|
||||
listAllMailboxes,
|
||||
getMailbox,
|
||||
addMailbox,
|
||||
updateMailbox,
|
||||
delMailbox,
|
||||
|
||||
getAlias,
|
||||
getAliases,
|
||||
setAliases,
|
||||
searchAlias,
|
||||
|
||||
getListCount,
|
||||
getLists,
|
||||
getList,
|
||||
addList,
|
||||
updateList,
|
||||
delList,
|
||||
resolveList,
|
||||
|
||||
checkStatus,
|
||||
|
||||
OWNERTYPE_USER: 'user',
|
||||
OWNERTYPE_GROUP: 'group',
|
||||
OWNERTYPE_APP: 'app',
|
||||
|
||||
TYPE_MAILBOX: 'mailbox',
|
||||
TYPE_LIST: 'list',
|
||||
TYPE_ALIAS: 'alias',
|
||||
|
||||
_delByDomain: delByDomain,
|
||||
_updateDomain: updateDomain
|
||||
};
|
||||
|
||||
@@ -200,6 +200,13 @@ async function configureMail(mailFqdn, mailDomain, serviceConfig) {
|
||||
await shell.bash(runCmd, { encoding: 'utf8' });
|
||||
}
|
||||
|
||||
async function getLocation() {
|
||||
const subdomain = await settings.get(settings.MAIL_SUBDOMAIN_KEY);
|
||||
const domain = await settings.get(settings.MAIL_DOMAIN_KEY);
|
||||
|
||||
return new Location(subdomain, domain, Location.TYPE_MAIL);
|
||||
}
|
||||
|
||||
async function restart() {
|
||||
if (constants.TEST && !process.env.TEST_CREATE_INFRA) return;
|
||||
|
||||
@@ -265,13 +272,6 @@ async function checkCertificate() {
|
||||
await restartIfActivated();
|
||||
}
|
||||
|
||||
async function getLocation() {
|
||||
const subdomain = await settings.get(settings.MAIL_SUBDOMAIN_KEY);
|
||||
const domain = await settings.get(settings.MAIL_DOMAIN_KEY);
|
||||
|
||||
return new Location(subdomain, domain, Location.TYPE_MAIL);
|
||||
}
|
||||
|
||||
async function changeLocation(auditSource, progressCallback) {
|
||||
assert.strictEqual(typeof auditSource, 'object');
|
||||
assert.strictEqual(typeof progressCallback, 'function');
|
||||
@@ -351,3 +351,4 @@ async function getMailAuth() {
|
||||
relayToken
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,16 @@
|
||||
'use strict';
|
||||
|
||||
exports = module.exports = {
|
||||
add,
|
||||
get,
|
||||
update,
|
||||
del,
|
||||
list,
|
||||
load,
|
||||
remount,
|
||||
getStatus
|
||||
};
|
||||
|
||||
const assert = require('node:assert'),
|
||||
AuditSource = require('../auditsource.js'),
|
||||
BoxError = require('../boxerror.js'),
|
||||
@@ -84,13 +95,3 @@ async function getStatus(req, res, next) {
|
||||
next(new HttpSuccess(200, status));
|
||||
}
|
||||
|
||||
exports = module.exports = {
|
||||
add,
|
||||
get,
|
||||
update,
|
||||
del,
|
||||
list,
|
||||
load,
|
||||
remount,
|
||||
getStatus
|
||||
};
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
'use strict';
|
||||
|
||||
exports = module.exports = shell;
|
||||
|
||||
const assert = require('node:assert'),
|
||||
BoxError = require('./boxerror.js'),
|
||||
child_process = require('node:child_process'),
|
||||
@@ -8,8 +10,6 @@ const assert = require('node:assert'),
|
||||
safe = require('safetydance'),
|
||||
_ = require('./underscore.js');
|
||||
|
||||
exports = module.exports = shell;
|
||||
|
||||
function shell(tag) {
|
||||
assert.strictEqual(typeof tag, 'string');
|
||||
|
||||
|
||||
@@ -1,5 +1,30 @@
|
||||
'use strict';
|
||||
|
||||
exports = module.exports = {
|
||||
setup,
|
||||
teardown,
|
||||
cleanup,
|
||||
|
||||
verifyConfig,
|
||||
removePrivateFields,
|
||||
injectPrivateFields,
|
||||
|
||||
getAvailableSize,
|
||||
getStatus,
|
||||
|
||||
upload,
|
||||
download,
|
||||
|
||||
copy,
|
||||
copyDir,
|
||||
|
||||
exists,
|
||||
listDir,
|
||||
|
||||
remove,
|
||||
removeDir,
|
||||
};
|
||||
|
||||
const assert = require('node:assert'),
|
||||
BoxError = require('../boxerror.js'),
|
||||
debug = require('debug')('box:storage/filesystem'),
|
||||
@@ -394,27 +419,3 @@ function injectPrivateFields(newConfig, currentConfig) {
|
||||
if (currentConfig._managedMountPath) newConfig._managedMountPath = currentConfig._managedMountPath;
|
||||
}
|
||||
|
||||
exports = module.exports = {
|
||||
setup,
|
||||
teardown,
|
||||
cleanup,
|
||||
|
||||
verifyConfig,
|
||||
removePrivateFields,
|
||||
injectPrivateFields,
|
||||
|
||||
getAvailableSize,
|
||||
getStatus,
|
||||
|
||||
upload,
|
||||
download,
|
||||
|
||||
copy,
|
||||
copyDir,
|
||||
|
||||
exists,
|
||||
listDir,
|
||||
|
||||
remove,
|
||||
removeDir,
|
||||
};
|
||||
|
||||
@@ -1,5 +1,30 @@
|
||||
'use strict';
|
||||
|
||||
exports = module.exports = {
|
||||
getAvailableSize,
|
||||
getStatus,
|
||||
|
||||
upload,
|
||||
exists,
|
||||
download,
|
||||
|
||||
copy,
|
||||
copyDir,
|
||||
|
||||
listDir,
|
||||
|
||||
remove,
|
||||
removeDir,
|
||||
|
||||
setup,
|
||||
teardown,
|
||||
cleanup,
|
||||
|
||||
verifyConfig,
|
||||
removePrivateFields,
|
||||
injectPrivateFields,
|
||||
};
|
||||
|
||||
const assert = require('node:assert'),
|
||||
async = require('async'),
|
||||
BoxError = require('../boxerror.js'),
|
||||
@@ -258,27 +283,3 @@ function injectPrivateFields(newConfig, currentConfig) {
|
||||
if (!Object.hasOwn(newConfig.credentials, 'private_key') && currentConfig.credentials) newConfig.credentials.private_key = currentConfig.credentials.private_key;
|
||||
}
|
||||
|
||||
exports = module.exports = {
|
||||
getAvailableSize,
|
||||
getStatus,
|
||||
|
||||
upload,
|
||||
exists,
|
||||
download,
|
||||
|
||||
copy,
|
||||
copyDir,
|
||||
|
||||
listDir,
|
||||
|
||||
remove,
|
||||
removeDir,
|
||||
|
||||
setup,
|
||||
teardown,
|
||||
cleanup,
|
||||
|
||||
verifyConfig,
|
||||
removePrivateFields,
|
||||
injectPrivateFields,
|
||||
};
|
||||
|
||||
@@ -1,5 +1,32 @@
|
||||
'use strict';
|
||||
|
||||
exports = module.exports = {
|
||||
setup,
|
||||
teardown,
|
||||
cleanup,
|
||||
|
||||
verifyConfig,
|
||||
removePrivateFields,
|
||||
injectPrivateFields,
|
||||
|
||||
getAvailableSize,
|
||||
getStatus,
|
||||
|
||||
upload,
|
||||
exists,
|
||||
download,
|
||||
copy,
|
||||
copyDir,
|
||||
|
||||
listDir,
|
||||
|
||||
remove,
|
||||
removeDir,
|
||||
|
||||
// Used to mock AWS
|
||||
_chunk: chunk
|
||||
};
|
||||
|
||||
const assert = require('node:assert'),
|
||||
async = require('async'),
|
||||
BoxError = require('../boxerror.js'),
|
||||
@@ -662,29 +689,3 @@ function injectPrivateFields(newConfig, currentConfig) {
|
||||
newConfig._provider = currentConfig._provider;
|
||||
}
|
||||
|
||||
exports = module.exports = {
|
||||
setup,
|
||||
teardown,
|
||||
cleanup,
|
||||
|
||||
verifyConfig,
|
||||
removePrivateFields,
|
||||
injectPrivateFields,
|
||||
|
||||
getAvailableSize,
|
||||
getStatus,
|
||||
|
||||
upload,
|
||||
exists,
|
||||
download,
|
||||
copy,
|
||||
copyDir,
|
||||
|
||||
listDir,
|
||||
|
||||
remove,
|
||||
removeDir,
|
||||
|
||||
// Used to mock AWS
|
||||
_chunk: chunk
|
||||
};
|
||||
|
||||
@@ -1,5 +1,10 @@
|
||||
'use strict';
|
||||
|
||||
exports = module.exports = {
|
||||
sync,
|
||||
finalize
|
||||
};
|
||||
|
||||
const assert = require('node:assert'),
|
||||
BoxError = require('./boxerror.js'),
|
||||
DataLayout = require('./datalayout.js'),
|
||||
@@ -10,11 +15,6 @@ const assert = require('node:assert'),
|
||||
safe = require('safetydance'),
|
||||
util = require('node:util');
|
||||
|
||||
exports = module.exports = {
|
||||
sync,
|
||||
finalize
|
||||
};
|
||||
|
||||
function readCache(cacheFile) {
|
||||
assert.strictEqual(typeof cacheFile, 'string');
|
||||
|
||||
|
||||
97
src/tasks.js
97
src/tasks.js
@@ -1,5 +1,54 @@
|
||||
'use strict';
|
||||
|
||||
exports = module.exports = {
|
||||
get,
|
||||
add,
|
||||
update,
|
||||
setCompleted,
|
||||
setCompletedByType,
|
||||
list,
|
||||
|
||||
getLogs,
|
||||
|
||||
startTask,
|
||||
stopTask,
|
||||
stopAllTasks,
|
||||
|
||||
removePrivateFields,
|
||||
|
||||
_del: del,
|
||||
|
||||
// task types. if you add a task here, fill up the function table in taskworker and dashboard constants.js
|
||||
// '_' prefix is removed for lookup
|
||||
TASK_APP: 'app',
|
||||
|
||||
// "prefix" allows us to locate the tasks of a specific app or backup site
|
||||
TASK_APP_BACKUP_PREFIX: 'appBackup_',
|
||||
TASK_FULL_BACKUP_PREFIX: 'backup_', // full backup
|
||||
TASK_CLEAN_BACKUPS_PREFIX: 'cleanBackups_',
|
||||
|
||||
TASK_BOX_UPDATE: 'boxUpdate',
|
||||
TASK_CHECK_CERTS: 'checkCerts',
|
||||
TASK_SYNC_DYNDNS: 'syncDyndns',
|
||||
TASK_PREPARE_DASHBOARD_LOCATION: 'prepareDashboardLocation',
|
||||
TASK_SYNC_EXTERNAL_LDAP: 'syncExternalLdap',
|
||||
TASK_CHANGE_MAIL_LOCATION: 'changeMailLocation',
|
||||
TASK_SYNC_DNS_RECORDS: 'syncDnsRecords',
|
||||
|
||||
TASK_CHECK_BACKUP_INTEGRITY: 'checkBackupIntegrity',
|
||||
|
||||
// error codes
|
||||
ESTOPPED: 'stopped',
|
||||
ECRASHED: 'crashed',
|
||||
ETIMEOUT: 'timeout',
|
||||
|
||||
// testing
|
||||
_TASK_IDENTITY: 'identity',
|
||||
_TASK_CRASH: 'crash',
|
||||
_TASK_ERROR: 'error',
|
||||
_TASK_SLEEP: 'sleep'
|
||||
};
|
||||
|
||||
const assert = require('node:assert'),
|
||||
BoxError = require('./boxerror.js'),
|
||||
database = require('./database.js'),
|
||||
@@ -243,51 +292,3 @@ async function del(id) {
|
||||
if (result.affectedRows !== 1) throw new BoxError(BoxError.NOT_FOUND, 'Task not found');
|
||||
}
|
||||
|
||||
exports = module.exports = {
|
||||
get,
|
||||
add,
|
||||
update,
|
||||
setCompleted,
|
||||
setCompletedByType,
|
||||
list,
|
||||
|
||||
getLogs,
|
||||
|
||||
startTask,
|
||||
stopTask,
|
||||
stopAllTasks,
|
||||
|
||||
removePrivateFields,
|
||||
|
||||
_del: del,
|
||||
|
||||
// task types. if you add a task here, fill up the function table in taskworker and dashboard constants.js
|
||||
// '_' prefix is removed for lookup
|
||||
TASK_APP: 'app',
|
||||
|
||||
// "prefix" allows us to locate the tasks of a specific app or backup site
|
||||
TASK_APP_BACKUP_PREFIX: 'appBackup_',
|
||||
TASK_FULL_BACKUP_PREFIX: 'backup_', // full backup
|
||||
TASK_CLEAN_BACKUPS_PREFIX: 'cleanBackups_',
|
||||
|
||||
TASK_BOX_UPDATE: 'boxUpdate',
|
||||
TASK_CHECK_CERTS: 'checkCerts',
|
||||
TASK_SYNC_DYNDNS: 'syncDyndns',
|
||||
TASK_PREPARE_DASHBOARD_LOCATION: 'prepareDashboardLocation',
|
||||
TASK_SYNC_EXTERNAL_LDAP: 'syncExternalLdap',
|
||||
TASK_CHANGE_MAIL_LOCATION: 'changeMailLocation',
|
||||
TASK_SYNC_DNS_RECORDS: 'syncDnsRecords',
|
||||
|
||||
TASK_CHECK_BACKUP_INTEGRITY: 'checkBackupIntegrity',
|
||||
|
||||
// error codes
|
||||
ESTOPPED: 'stopped',
|
||||
ECRASHED: 'crashed',
|
||||
ETIMEOUT: 'timeout',
|
||||
|
||||
// testing
|
||||
_TASK_IDENTITY: 'identity',
|
||||
_TASK_CRASH: 'crash',
|
||||
_TASK_ERROR: 'error',
|
||||
_TASK_SLEEP: 'sleep'
|
||||
};
|
||||
|
||||
405
src/users.js
405
src/users.js
@@ -68,14 +68,6 @@ exports = module.exports = {
|
||||
compareRoles,
|
||||
};
|
||||
|
||||
const ORDERED_ROLES = [ exports.ROLE_USER, exports.ROLE_USER_MANAGER, exports.ROLE_MAIL_MANAGER, exports.ROLE_ADMIN, exports.ROLE_OWNER ];
|
||||
|
||||
// the avatar and backgroundImage fields are special and not added here to reduce response sizes
|
||||
const USERS_FIELDS = [ 'id', 'username', 'email', 'fallbackEmail', 'password', 'salt', 'creationTime', 'inviteToken', 'resetToken', 'displayName', 'language',
|
||||
'twoFactorAuthenticationEnabled', 'twoFactorAuthenticationSecret', 'active', 'source', 'role', 'resetTokenCreationTime', 'loginLocationsJson', 'notificationConfigJson' ].join(',');
|
||||
|
||||
const DEFAULT_GHOST_LIFETIME = 6 * 60 * 60 * 1000; // 6 hours
|
||||
|
||||
const appPasswords = require('./apppasswords.js'),
|
||||
assert = require('node:assert'),
|
||||
BoxError = require('./boxerror.js'),
|
||||
@@ -105,6 +97,12 @@ const appPasswords = require('./apppasswords.js'),
|
||||
validator = require('./validator.js'),
|
||||
_ = require('./underscore.js');
|
||||
|
||||
// the avatar and backgroundImage fields are special and not added here to reduce response sizes
|
||||
const USERS_FIELDS = [ 'id', 'username', 'email', 'fallbackEmail', 'password', 'salt', 'creationTime', 'inviteToken', 'resetToken', 'displayName', 'language',
|
||||
'twoFactorAuthenticationEnabled', 'twoFactorAuthenticationSecret', 'active', 'source', 'role', 'resetTokenCreationTime', 'loginLocationsJson', 'notificationConfigJson' ].join(',');
|
||||
|
||||
const DEFAULT_GHOST_LIFETIME = 6 * 60 * 60 * 1000; // 6 hours
|
||||
|
||||
const CRYPTO_SALT_SIZE = 64; // 512-bit salt
|
||||
const CRYPTO_ITERATIONS = 10000; // iterations
|
||||
const CRYPTO_KEY_LENGTH = 512; // bits
|
||||
@@ -201,6 +199,28 @@ function removePrivateFields(user) {
|
||||
return result;
|
||||
}
|
||||
|
||||
function validateRole(role) {
|
||||
assert.strictEqual(typeof role, 'string');
|
||||
|
||||
const ORDERED_ROLES = [ exports.ROLE_USER, exports.ROLE_USER_MANAGER, exports.ROLE_MAIL_MANAGER, exports.ROLE_ADMIN, exports.ROLE_OWNER ];
|
||||
|
||||
if (ORDERED_ROLES.includes(role)) return null;
|
||||
|
||||
return new BoxError(BoxError.BAD_FIELD, `Invalid role '${role}'`);
|
||||
}
|
||||
|
||||
function compareRoles(role1, role2) {
|
||||
assert.strictEqual(typeof role1, 'string');
|
||||
assert.strictEqual(typeof role2, 'string');
|
||||
|
||||
const ORDERED_ROLES = [ exports.ROLE_USER, exports.ROLE_USER_MANAGER, exports.ROLE_MAIL_MANAGER, exports.ROLE_ADMIN, exports.ROLE_OWNER ];
|
||||
|
||||
const roleInt1 = ORDERED_ROLES.indexOf(role1);
|
||||
const roleInt2 = ORDERED_ROLES.indexOf(role2);
|
||||
|
||||
return roleInt1 - roleInt2;
|
||||
}
|
||||
|
||||
async function add(email, data, auditSource) {
|
||||
assert.strictEqual(typeof email, 'string');
|
||||
assert(data && typeof data === 'object');
|
||||
@@ -290,181 +310,6 @@ async function add(email, data, auditSource) {
|
||||
return user.id;
|
||||
}
|
||||
|
||||
async function setGhost(user, password, expiresAt) {
|
||||
assert.strictEqual(typeof user, 'object');
|
||||
assert.strictEqual(typeof password, 'string');
|
||||
assert.strictEqual(typeof expiresAt, 'number');
|
||||
|
||||
if (!user.username) throw new BoxError(BoxError.BAD_STATE, 'user has no username yet');
|
||||
|
||||
expiresAt = expiresAt || (Date.now() + DEFAULT_GHOST_LIFETIME);
|
||||
|
||||
const ghostData = await settings.getJson(settings.GHOSTS_CONFIG_KEY) || {};
|
||||
ghostData[user.username] = { password, expiresAt };
|
||||
|
||||
await settings.setJson(settings.GHOSTS_CONFIG_KEY, ghostData);
|
||||
}
|
||||
|
||||
// returns true if ghost user was matched
|
||||
async function verifyGhost(username, password) {
|
||||
assert.strictEqual(typeof username, 'string');
|
||||
assert.strictEqual(typeof password, 'string');
|
||||
|
||||
const ghostData = await settings.getJson(settings.GHOSTS_CONFIG_KEY) || {};
|
||||
|
||||
// either the username is an object with { password, expiresAt } or a string with the password which will expire on first match
|
||||
if (username in ghostData) {
|
||||
if (typeof ghostData[username] === 'object') {
|
||||
if (ghostData[username].expiresAt < Date.now()) {
|
||||
debug('verifyGhost: password expired');
|
||||
delete ghostData[username];
|
||||
|
||||
await settings.setJson(settings.GHOSTS_CONFIG_KEY, ghostData);
|
||||
|
||||
return false;
|
||||
} else if (ghostData[username].password === password) {
|
||||
debug('verifyGhost: matched ghost user');
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
} else if(ghostData[username] === password) {
|
||||
debug('verifyGhost: matched ghost user');
|
||||
delete ghostData[username];
|
||||
|
||||
await settings.setJson(settings.GHOSTS_CONFIG_KEY, ghostData);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
async function verifyAppPassword(userId, password, identifier) {
|
||||
assert.strictEqual(typeof userId, 'string');
|
||||
assert.strictEqual(typeof password, 'string');
|
||||
assert.strictEqual(typeof identifier, 'string');
|
||||
|
||||
const results = await appPasswords.list(userId);
|
||||
|
||||
const hashedPasswords = results.filter(r => r.identifier === identifier).map(r => r.hashedPassword);
|
||||
const hash = crypto.createHash('sha256').update(password).digest('base64');
|
||||
|
||||
if (hashedPasswords.includes(hash)) return;
|
||||
|
||||
throw new BoxError(BoxError.INVALID_CREDENTIALS, 'Password is not valid');
|
||||
}
|
||||
|
||||
// identifier is only used to check if password is valid for a specific app
|
||||
async function verify(user, password, identifier, options) {
|
||||
assert.strictEqual(typeof user, 'object');
|
||||
assert.strictEqual(typeof password, 'string');
|
||||
assert.strictEqual(typeof identifier, 'string');
|
||||
assert.strictEqual(typeof options, 'object');
|
||||
|
||||
if (!user.active) {
|
||||
debug(`verify: ${user.username} is not active`);
|
||||
throw new BoxError(BoxError.NOT_FOUND, 'User not active');
|
||||
}
|
||||
|
||||
// for just invited users the username may be still null
|
||||
if (user.username) {
|
||||
const valid = await verifyGhost(user.username, password);
|
||||
|
||||
if (valid) {
|
||||
debug(`verify: ${user.username} authenticated via impersonation`);
|
||||
user.ghost = true;
|
||||
return user;
|
||||
}
|
||||
}
|
||||
|
||||
const [error] = await safe(verifyAppPassword(user.id, password, identifier));
|
||||
if (!error) { // matched app password
|
||||
debug(`verify: ${user.username || user.id} matched app password`);
|
||||
user.appPassword = true;
|
||||
return user;
|
||||
}
|
||||
|
||||
let localTotpCheck = true; // does 2fa need to be verified with local database 2fa creds
|
||||
if (user.source === 'ldap') {
|
||||
await externalLdap.verifyPassword(user.username, password, options);
|
||||
const externalLdapConfig = await externalLdap.getConfig();
|
||||
localTotpCheck = user.twoFactorAuthenticationEnabled && !externalLdap.supports2FA(externalLdapConfig);
|
||||
} else {
|
||||
const saltBinary = Buffer.from(user.salt, 'hex');
|
||||
const [error, derivedKey] = await safe(pbkdf2Async(password, saltBinary, CRYPTO_ITERATIONS, CRYPTO_KEY_LENGTH, CRYPTO_DIGEST));
|
||||
if (error) throw new BoxError(BoxError.CRYPTO_ERROR, error);
|
||||
|
||||
const derivedKeyHex = Buffer.from(derivedKey, 'binary').toString('hex');
|
||||
if (derivedKeyHex !== user.password) {
|
||||
debug(`verify: ${user.username || user.id} provided incorrect password`);
|
||||
throw new BoxError(BoxError.INVALID_CREDENTIALS, 'Wrong password');
|
||||
}
|
||||
|
||||
localTotpCheck = user.twoFactorAuthenticationEnabled;
|
||||
}
|
||||
|
||||
if (localTotpCheck && !options.skipTotpCheck) {
|
||||
if (!options.totpToken) throw new BoxError(BoxError.INVALID_CREDENTIALS, 'A totpToken must be provided');
|
||||
const verified = speakeasy.totp.verify({ secret: user.twoFactorAuthenticationSecret, encoding: 'base32', token: options.totpToken, window: 2 });
|
||||
if (!verified) throw new BoxError(BoxError.INVALID_CREDENTIALS, 'Invalid totpToken');
|
||||
}
|
||||
|
||||
return user;
|
||||
}
|
||||
|
||||
async function verifyWithId(id, password, identifier, options) {
|
||||
assert.strictEqual(typeof id, 'string');
|
||||
assert.strictEqual(typeof password, 'string');
|
||||
assert.strictEqual(typeof identifier, 'string');
|
||||
assert.strictEqual(typeof options, 'object');
|
||||
|
||||
const user = await get(id);
|
||||
if (!user) {
|
||||
debug(`verifyWithId: ${id} not found`);
|
||||
throw new BoxError(BoxError.NOT_FOUND, 'User not found');
|
||||
}
|
||||
|
||||
return await verify(user, password, identifier, options);
|
||||
}
|
||||
|
||||
async function verifyWithUsername(username, password, identifier, options) {
|
||||
assert.strictEqual(typeof username, 'string');
|
||||
assert.strictEqual(typeof password, 'string');
|
||||
assert.strictEqual(typeof identifier, 'string');
|
||||
assert.strictEqual(typeof options, 'object');
|
||||
|
||||
const user = await getByUsername(username.toLowerCase());
|
||||
if (user) return await verify(user, password, identifier, options);
|
||||
|
||||
const [error, newUserId] = await safe(externalLdap.maybeCreateUser(username.toLowerCase()));
|
||||
if (error && error.reason === BoxError.BAD_STATE) {
|
||||
debug(`verifyWithUsername: ${username} not found`);
|
||||
throw new BoxError(BoxError.NOT_FOUND, 'User not found'); // no external ldap or no auto create
|
||||
}
|
||||
if (error) {
|
||||
debug(`verifyWithUsername: failed to auto create user ${username}. %o`, error);
|
||||
throw new BoxError(BoxError.NOT_FOUND, 'User not found');
|
||||
}
|
||||
|
||||
return await verifyWithId(newUserId, password, identifier, options);
|
||||
}
|
||||
|
||||
async function verifyWithEmail(email, password, identifier, options) {
|
||||
assert.strictEqual(typeof email, 'string');
|
||||
assert.strictEqual(typeof password, 'string');
|
||||
assert.strictEqual(typeof identifier, 'string');
|
||||
assert.strictEqual(typeof options, 'object');
|
||||
|
||||
const user = await getByEmail(email.toLowerCase());
|
||||
if (!user) {
|
||||
debug(`verifyWithEmail: ${email} no such user`);
|
||||
throw new BoxError(BoxError.NOT_FOUND, 'User not found');
|
||||
}
|
||||
|
||||
return await verify(user, password, identifier, options);
|
||||
}
|
||||
|
||||
async function del(user, auditSource) {
|
||||
assert.strictEqual(typeof user, 'object');
|
||||
assert(auditSource && typeof auditSource === 'object');
|
||||
@@ -712,6 +557,181 @@ async function getSuperadmins() {
|
||||
return await listByRole(exports.ROLE_OWNER);
|
||||
}
|
||||
|
||||
async function setGhost(user, password, expiresAt) {
|
||||
assert.strictEqual(typeof user, 'object');
|
||||
assert.strictEqual(typeof password, 'string');
|
||||
assert.strictEqual(typeof expiresAt, 'number');
|
||||
|
||||
if (!user.username) throw new BoxError(BoxError.BAD_STATE, 'user has no username yet');
|
||||
|
||||
expiresAt = expiresAt || (Date.now() + DEFAULT_GHOST_LIFETIME);
|
||||
|
||||
const ghostData = await settings.getJson(settings.GHOSTS_CONFIG_KEY) || {};
|
||||
ghostData[user.username] = { password, expiresAt };
|
||||
|
||||
await settings.setJson(settings.GHOSTS_CONFIG_KEY, ghostData);
|
||||
}
|
||||
|
||||
// returns true if ghost user was matched
|
||||
async function verifyGhost(username, password) {
|
||||
assert.strictEqual(typeof username, 'string');
|
||||
assert.strictEqual(typeof password, 'string');
|
||||
|
||||
const ghostData = await settings.getJson(settings.GHOSTS_CONFIG_KEY) || {};
|
||||
|
||||
// either the username is an object with { password, expiresAt } or a string with the password which will expire on first match
|
||||
if (username in ghostData) {
|
||||
if (typeof ghostData[username] === 'object') {
|
||||
if (ghostData[username].expiresAt < Date.now()) {
|
||||
debug('verifyGhost: password expired');
|
||||
delete ghostData[username];
|
||||
|
||||
await settings.setJson(settings.GHOSTS_CONFIG_KEY, ghostData);
|
||||
|
||||
return false;
|
||||
} else if (ghostData[username].password === password) {
|
||||
debug('verifyGhost: matched ghost user');
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
} else if(ghostData[username] === password) {
|
||||
debug('verifyGhost: matched ghost user');
|
||||
delete ghostData[username];
|
||||
|
||||
await settings.setJson(settings.GHOSTS_CONFIG_KEY, ghostData);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
async function verifyAppPassword(userId, password, identifier) {
|
||||
assert.strictEqual(typeof userId, 'string');
|
||||
assert.strictEqual(typeof password, 'string');
|
||||
assert.strictEqual(typeof identifier, 'string');
|
||||
|
||||
const results = await appPasswords.list(userId);
|
||||
|
||||
const hashedPasswords = results.filter(r => r.identifier === identifier).map(r => r.hashedPassword);
|
||||
const hash = crypto.createHash('sha256').update(password).digest('base64');
|
||||
|
||||
if (hashedPasswords.includes(hash)) return;
|
||||
|
||||
throw new BoxError(BoxError.INVALID_CREDENTIALS, 'Password is not valid');
|
||||
}
|
||||
|
||||
// identifier is only used to check if password is valid for a specific app
|
||||
async function verify(user, password, identifier, options) {
|
||||
assert.strictEqual(typeof user, 'object');
|
||||
assert.strictEqual(typeof password, 'string');
|
||||
assert.strictEqual(typeof identifier, 'string');
|
||||
assert.strictEqual(typeof options, 'object');
|
||||
|
||||
if (!user.active) {
|
||||
debug(`verify: ${user.username} is not active`);
|
||||
throw new BoxError(BoxError.NOT_FOUND, 'User not active');
|
||||
}
|
||||
|
||||
// for just invited users the username may be still null
|
||||
if (user.username) {
|
||||
const valid = await verifyGhost(user.username, password);
|
||||
|
||||
if (valid) {
|
||||
debug(`verify: ${user.username} authenticated via impersonation`);
|
||||
user.ghost = true;
|
||||
return user;
|
||||
}
|
||||
}
|
||||
|
||||
const [error] = await safe(verifyAppPassword(user.id, password, identifier));
|
||||
if (!error) { // matched app password
|
||||
debug(`verify: ${user.username || user.id} matched app password`);
|
||||
user.appPassword = true;
|
||||
return user;
|
||||
}
|
||||
|
||||
let localTotpCheck = true; // does 2fa need to be verified with local database 2fa creds
|
||||
if (user.source === 'ldap') {
|
||||
await externalLdap.verifyPassword(user.username, password, options);
|
||||
const externalLdapConfig = await externalLdap.getConfig();
|
||||
localTotpCheck = user.twoFactorAuthenticationEnabled && !externalLdap.supports2FA(externalLdapConfig);
|
||||
} else {
|
||||
const saltBinary = Buffer.from(user.salt, 'hex');
|
||||
const [error, derivedKey] = await safe(pbkdf2Async(password, saltBinary, CRYPTO_ITERATIONS, CRYPTO_KEY_LENGTH, CRYPTO_DIGEST));
|
||||
if (error) throw new BoxError(BoxError.CRYPTO_ERROR, error);
|
||||
|
||||
const derivedKeyHex = Buffer.from(derivedKey, 'binary').toString('hex');
|
||||
if (derivedKeyHex !== user.password) {
|
||||
debug(`verify: ${user.username || user.id} provided incorrect password`);
|
||||
throw new BoxError(BoxError.INVALID_CREDENTIALS, 'Wrong password');
|
||||
}
|
||||
|
||||
localTotpCheck = user.twoFactorAuthenticationEnabled;
|
||||
}
|
||||
|
||||
if (localTotpCheck && !options.skipTotpCheck) {
|
||||
if (!options.totpToken) throw new BoxError(BoxError.INVALID_CREDENTIALS, 'A totpToken must be provided');
|
||||
const verified = speakeasy.totp.verify({ secret: user.twoFactorAuthenticationSecret, encoding: 'base32', token: options.totpToken, window: 2 });
|
||||
if (!verified) throw new BoxError(BoxError.INVALID_CREDENTIALS, 'Invalid totpToken');
|
||||
}
|
||||
|
||||
return user;
|
||||
}
|
||||
|
||||
async function verifyWithId(id, password, identifier, options) {
|
||||
assert.strictEqual(typeof id, 'string');
|
||||
assert.strictEqual(typeof password, 'string');
|
||||
assert.strictEqual(typeof identifier, 'string');
|
||||
assert.strictEqual(typeof options, 'object');
|
||||
|
||||
const user = await get(id);
|
||||
if (!user) {
|
||||
debug(`verifyWithId: ${id} not found`);
|
||||
throw new BoxError(BoxError.NOT_FOUND, 'User not found');
|
||||
}
|
||||
|
||||
return await verify(user, password, identifier, options);
|
||||
}
|
||||
|
||||
async function verifyWithUsername(username, password, identifier, options) {
|
||||
assert.strictEqual(typeof username, 'string');
|
||||
assert.strictEqual(typeof password, 'string');
|
||||
assert.strictEqual(typeof identifier, 'string');
|
||||
assert.strictEqual(typeof options, 'object');
|
||||
|
||||
const user = await getByUsername(username.toLowerCase());
|
||||
if (user) return await verify(user, password, identifier, options);
|
||||
|
||||
const [error, newUserId] = await safe(externalLdap.maybeCreateUser(username.toLowerCase()));
|
||||
if (error && error.reason === BoxError.BAD_STATE) {
|
||||
debug(`verifyWithUsername: ${username} not found`);
|
||||
throw new BoxError(BoxError.NOT_FOUND, 'User not found'); // no external ldap or no auto create
|
||||
}
|
||||
if (error) {
|
||||
debug(`verifyWithUsername: failed to auto create user ${username}. %o`, error);
|
||||
throw new BoxError(BoxError.NOT_FOUND, 'User not found');
|
||||
}
|
||||
|
||||
return await verifyWithId(newUserId, password, identifier, options);
|
||||
}
|
||||
|
||||
async function verifyWithEmail(email, password, identifier, options) {
|
||||
assert.strictEqual(typeof email, 'string');
|
||||
assert.strictEqual(typeof password, 'string');
|
||||
assert.strictEqual(typeof identifier, 'string');
|
||||
assert.strictEqual(typeof options, 'object');
|
||||
|
||||
const user = await getByEmail(email.toLowerCase());
|
||||
if (!user) {
|
||||
debug(`verifyWithEmail: ${email} no such user`);
|
||||
throw new BoxError(BoxError.NOT_FOUND, 'User not found');
|
||||
}
|
||||
|
||||
return await verify(user, password, identifier, options);
|
||||
}
|
||||
|
||||
async function getPasswordResetLink(user, auditSource) {
|
||||
assert.strictEqual(typeof user, 'object');
|
||||
assert.strictEqual(typeof auditSource, 'object');
|
||||
@@ -969,24 +989,6 @@ async function disableTwoFactorAuthentication(user, auditSource) {
|
||||
await update(user, { twoFactorAuthenticationEnabled: false, twoFactorAuthenticationSecret: '' }, auditSource);
|
||||
}
|
||||
|
||||
function validateRole(role) {
|
||||
assert.strictEqual(typeof role, 'string');
|
||||
|
||||
if (ORDERED_ROLES.indexOf(role) !== -1) return null;
|
||||
|
||||
return new BoxError(BoxError.BAD_FIELD, `Invalid role '${role}'`);
|
||||
}
|
||||
|
||||
function compareRoles(role1, role2) {
|
||||
assert.strictEqual(typeof role1, 'string');
|
||||
assert.strictEqual(typeof role2, 'string');
|
||||
|
||||
const roleInt1 = ORDERED_ROLES.indexOf(role1);
|
||||
const roleInt2 = ORDERED_ROLES.indexOf(role2);
|
||||
|
||||
return roleInt1 - roleInt2;
|
||||
}
|
||||
|
||||
async function getAvatar(user) {
|
||||
assert.strictEqual(typeof user, 'object');
|
||||
|
||||
@@ -1042,3 +1044,4 @@ function parseDisplayName(displayName) {
|
||||
const lastName = displayName.substring(idx+1);
|
||||
return { firstName, lastName, middleName };
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,21 @@
|
||||
'use strict';
|
||||
|
||||
exports = module.exports = {
|
||||
add,
|
||||
get,
|
||||
update,
|
||||
del,
|
||||
list,
|
||||
remount,
|
||||
getStatus,
|
||||
removePrivateFields,
|
||||
|
||||
mountAll,
|
||||
|
||||
// exported for testing
|
||||
_validateHostPath: validateHostPath
|
||||
};
|
||||
|
||||
const assert = require('node:assert'),
|
||||
BoxError = require('./boxerror.js'),
|
||||
crypto = require('node:crypto'),
|
||||
@@ -202,18 +218,3 @@ async function mountAll() {
|
||||
}
|
||||
}
|
||||
|
||||
exports = module.exports = {
|
||||
add,
|
||||
get,
|
||||
update,
|
||||
del,
|
||||
list,
|
||||
remount,
|
||||
getStatus,
|
||||
removePrivateFields,
|
||||
|
||||
mountAll,
|
||||
|
||||
// exported for testing
|
||||
_validateHostPath: validateHostPath
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user