Migrate codebase from CommonJS to ES Modules

- Convert all require()/module.exports to import/export across 260+ files
- Add "type": "module" to package.json to enable ESM by default
- Add migrations/package.json with "type": "commonjs" to keep db-migrate compatible
- Convert eslint.config.js to ESM with sourceType: "module"
- Replace __dirname/__filename with import.meta.dirname/import.meta.filename
- Replace require.main === module with process.argv[1] === import.meta.filename
- Remove 'use strict' directives (implicit in ESM)
- Convert dynamic require() in switch statements to static import lookup maps
  (dns.js, domains.js, backupformats.js, backupsites.js, network.js)
- Extract self-referencing exports.CONSTANT patterns into standalone const
  declarations (apps.js, services.js, locks.js, users.js, mail.js, etc.)
- Lazify SERVICES object in services.js to avoid circular dependency TDZ issues
- Add clearMailQueue() to mailer.js for ESM-safe queue clearing in tests
- Add _setMockApp() to ldapserver.js for ESM-safe test mocking
- Add _setMockResolve() wrapper to dig.js for ESM-safe DNS mocking in tests
- Convert backupupload.js to use dynamic imports so --check exits before
  loading the module graph (which requires BOX_ENV)
- Update check-install to use ESM import for infra_version.js
- Convert scripts/ (hotfix, release, remote_hotfix.js, find-unused-translations)
- All 1315 tests passing

Migration stats (AI-assisted using Cursor with Claude):
- Wall clock time: ~3-4 hours
- Assistant completions: ~80-100
- Estimated token usage: ~1-2M tokens

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Girish Ramakrishnan
2026-02-14 09:53:14 +01:00
parent e0e9f14a5e
commit 96dc79cfe6
277 changed files with 4789 additions and 3811 deletions
+11 -11
View File
@@ -1,6 +1,15 @@
'use strict';
import apps from '../apps.js';
import assert from 'node:assert';
import BoxError from '../boxerror.js';
import debugModule from 'debug';
import { HttpError } from '@cloudron/connect-lastmile';
import safe from 'safetydance';
import * as tokens from '../tokens.js';
import * as users from '../users.js';
exports = module.exports = {
const debug = debugModule('box:routes/accesscontrol');
export {
passwordAuth,
tokenAuth,
@@ -8,15 +17,6 @@ exports = module.exports = {
authorizeOperator,
};
const apps = require('../apps.js'),
assert = require('node:assert'),
BoxError = require('../boxerror.js'),
debug = require('debug')('box:routes/accesscontrol'),
HttpError = require('@cloudron/connect-lastmile').HttpError,
safe = require('safetydance'),
tokens = require('../tokens.js'),
users = require('../users.js');
async function passwordAuth(req, res, next) {
assert.strictEqual(typeof req.body, 'object');
+7 -9
View File
@@ -1,6 +1,11 @@
'use strict';
import assert from 'node:assert';
import * as applinks from '../applinks.js';
import BoxError from '../boxerror.js';
import safe from 'safetydance';
import { HttpError } from '@cloudron/connect-lastmile';
import { HttpSuccess } from '@cloudron/connect-lastmile';
exports = module.exports = {
export {
listByUser,
add,
get,
@@ -11,13 +16,6 @@ exports = module.exports = {
load
};
const assert = require('node:assert'),
applinks = require('../applinks.js'),
BoxError = require('../boxerror.js'),
safe = require('safetydance'),
HttpError = require('@cloudron/connect-lastmile').HttpError,
HttpSuccess = require('@cloudron/connect-lastmile').HttpSuccess;
async function load(req, res, next) {
assert.strictEqual(typeof req.params.id, 'string');
+7 -9
View File
@@ -1,19 +1,17 @@
'use strict';
import * as appPasswords from '../apppasswords.js';
import assert from 'node:assert';
import BoxError from '../boxerror.js';
import { HttpError } from '@cloudron/connect-lastmile';
import { HttpSuccess } from '@cloudron/connect-lastmile';
import safe from 'safetydance';
exports = module.exports = {
export {
list,
get,
del,
add
};
const appPasswords = require('../apppasswords.js'),
assert = require('node:assert'),
BoxError = require('../boxerror.js'),
HttpError = require('@cloudron/connect-lastmile').HttpError,
HttpSuccess = require('@cloudron/connect-lastmile').HttpSuccess,
safe = require('safetydance');
async function get(req, res, next) {
assert.strictEqual(typeof req.user, 'object');
assert.strictEqual(typeof req.params.id, 'string');
+19 -19
View File
@@ -1,6 +1,23 @@
'use strict';
import apps from '../apps.js';
import * as appstore from '../appstore.js';
import assert from 'node:assert';
import AuditSource from '../auditsource.js';
import * as backupSites from '../backupsites.js';
import BoxError from '../boxerror.js';
import * as community from '../community.js';
import constants from '../constants.js';
import debugModule from 'debug';
import { HttpError } from '@cloudron/connect-lastmile';
import { HttpSuccess } from '@cloudron/connect-lastmile';
import * as metrics from '../metrics.js';
import safe from 'safetydance';
import * as updater from '../updater.js';
import * as users from '../users.js';
import WebSocket from 'ws';
exports = module.exports = {
const debug = debugModule('box:routes/apps');
export {
getApp,
listByUser,
getAppIcon,
@@ -72,23 +89,6 @@ exports = module.exports = {
load
};
const apps = require('../apps.js'),
appstore = require('../appstore.js'),
assert = require('node:assert'),
AuditSource = require('../auditsource.js'),
backupSites = require('../backupsites.js'),
BoxError = require('../boxerror.js'),
community = require('../community.js'),
constants = require('../constants.js'),
debug = require('debug')('box:routes/apps'),
HttpError = require('@cloudron/connect-lastmile').HttpError,
HttpSuccess = require('@cloudron/connect-lastmile').HttpSuccess,
metrics = require('../metrics.js'),
safe = require('safetydance'),
updater = require('../updater.js'),
users = require('../users.js'),
WebSocket = require('ws');
async function load(req, res, next) {
assert.strictEqual(typeof req.params.id, 'string');
+8 -10
View File
@@ -1,6 +1,12 @@
'use strict';
import * as appstore from '../appstore.js';
import assert from 'node:assert';
import BoxError from '../boxerror.js';
import { HttpSuccess } from '@cloudron/connect-lastmile';
import safe from 'safetydance';
import * as users from '../users.js';
import * as _ from '../underscore.js';
exports = module.exports = {
export {
getApps,
getApp,
getAppVersion,
@@ -9,14 +15,6 @@ exports = module.exports = {
getSubscription
};
const appstore = require('../appstore.js'),
assert = require('node:assert'),
BoxError = require('../boxerror.js'),
HttpSuccess = require('@cloudron/connect-lastmile').HttpSuccess,
safe = require('safetydance'),
users = require('../users.js'),
_ = require('../underscore.js');
async function getApps(req, res, next) {
const [error, apps] = await safe(appstore.getApps());
if (error) return next(BoxError.toHttpError(error));
+9 -11
View File
@@ -1,6 +1,13 @@
'use strict';
import apps from '../apps.js';
import assert from 'node:assert';
import * as archives from '../archives.js';
import AuditSource from '../auditsource.js';
import BoxError from '../boxerror.js';
import { HttpError } from '@cloudron/connect-lastmile';
import { HttpSuccess } from '@cloudron/connect-lastmile';
import safe from 'safetydance';
exports = module.exports = {
export {
load,
list,
@@ -10,15 +17,6 @@ exports = module.exports = {
unarchive
};
const apps = require('../apps.js'),
assert = require('node:assert'),
archives = require('../archives.js'),
AuditSource = require('../auditsource.js'),
BoxError = require('../boxerror.js'),
HttpError = require('@cloudron/connect-lastmile').HttpError,
HttpSuccess = require('@cloudron/connect-lastmile').HttpSuccess,
safe = require('safetydance');
async function load(req, res, next) {
assert.strictEqual(typeof req.params.id, 'string');
+16 -16
View File
@@ -1,6 +1,20 @@
'use strict';
import assert from 'node:assert';
import AuditSource from '../auditsource.js';
import BoxError from '../boxerror.js';
import constants from '../constants.js';
import debugModule from 'debug';
import eventlog from '../eventlog.js';
import { HttpError } from '@cloudron/connect-lastmile';
import { HttpSuccess } from '@cloudron/connect-lastmile';
import oidcClients from '../oidcclients.js';
import safe from 'safetydance';
import speakeasy from 'speakeasy';
import * as tokens from '../tokens.js';
import * as users from '../users.js';
exports = module.exports = {
const debug = debugModule('box:routes/cloudron');
export {
login,
logout,
passwordResetRequest,
@@ -8,20 +22,6 @@ exports = module.exports = {
setupAccount,
};
const assert = require('node:assert'),
AuditSource = require('../auditsource.js'),
BoxError = require('../boxerror.js'),
constants = require('../constants.js'),
debug = require('debug')('box:routes/cloudron'),
eventlog = require('../eventlog.js'),
HttpError = require('@cloudron/connect-lastmile').HttpError,
HttpSuccess = require('@cloudron/connect-lastmile').HttpSuccess,
oidcClients = require('../oidcclients.js'),
safe = require('safetydance'),
speakeasy = require('speakeasy'),
tokens = require('../tokens.js'),
users = require('../users.js');
async function login(req, res, next) {
assert.strictEqual(typeof req.user, 'object');
+8 -10
View File
@@ -1,6 +1,12 @@
'use strict';
import assert from 'node:assert';
import AuditSource from '../auditsource.js';
import backups from '../backups.js';
import BoxError from '../boxerror.js';
import { HttpError } from '@cloudron/connect-lastmile';
import { HttpSuccess } from '@cloudron/connect-lastmile';
import safe from 'safetydance';
exports = module.exports = {
export {
load,
list,
@@ -11,14 +17,6 @@ exports = module.exports = {
stopIntegrityCheck
};
const assert = require('node:assert'),
AuditSource = require('../auditsource.js'),
backups = require('../backups.js'),
BoxError = require('../boxerror.js'),
HttpError = require('@cloudron/connect-lastmile').HttpError,
HttpSuccess = require('@cloudron/connect-lastmile').HttpSuccess,
safe = require('safetydance');
async function load(req, res, next) {
assert.strictEqual(typeof req.params.id, 'string');
+9 -11
View File
@@ -1,6 +1,13 @@
'use strict';
import assert from 'node:assert';
import AuditSource from '../auditsource.js';
import backups from '../backups.js';
import * as backupSites from '../backupsites.js';
import BoxError from '../boxerror.js';
import { HttpError } from '@cloudron/connect-lastmile';
import { HttpSuccess } from '@cloudron/connect-lastmile';
import safe from 'safetydance';
exports = module.exports = {
export {
load,
list,
@@ -25,15 +32,6 @@ exports = module.exports = {
getStatus,
};
const assert = require('node:assert'),
AuditSource = require('../auditsource.js'),
backups = require('../backups.js'),
backupSites = require('../backupsites.js'),
BoxError = require('../boxerror.js'),
HttpError = require('@cloudron/connect-lastmile').HttpError,
HttpSuccess = require('@cloudron/connect-lastmile').HttpSuccess,
safe = require('safetydance');
async function load(req, res, next) {
assert.strictEqual(typeof req.params.id, 'string');
+8 -10
View File
@@ -1,6 +1,12 @@
'use strict';
import assert from 'node:assert';
import AuditSource from '../auditsource.js';
import BoxError from '../boxerror.js';
import * as branding from '../branding.js';
import { HttpError } from '@cloudron/connect-lastmile';
import { HttpSuccess } from '@cloudron/connect-lastmile';
import safe from 'safetydance';
exports = module.exports = {
export {
getCloudronName,
setCloudronName,
getCloudronAvatar,
@@ -12,14 +18,6 @@ exports = module.exports = {
setFooter,
};
const assert = require('node:assert'),
AuditSource = require('../auditsource.js'),
BoxError = require('../boxerror.js'),
branding = require('../branding.js'),
HttpError = require('@cloudron/connect-lastmile').HttpError,
HttpSuccess = require('@cloudron/connect-lastmile').HttpSuccess,
safe = require('safetydance');
async function getFooter(req, res, next) {
const [error, footer] = await safe(branding.getFooter());
if (error) return next(BoxError.toHttpError(error));
+8 -10
View File
@@ -1,6 +1,12 @@
'use strict';
import assert from 'node:assert';
import BoxError from '../boxerror.js';
import * as cloudron from '../cloudron.js';
import { HttpError } from '@cloudron/connect-lastmile';
import { HttpSuccess } from '@cloudron/connect-lastmile';
import safe from 'safetydance';
import * as translations from '../translations.js';
exports = module.exports = {
export {
getStatus,
listLanguages,
@@ -11,14 +17,6 @@ exports = module.exports = {
setTimeZone
};
const assert = require('node:assert'),
BoxError = require('../boxerror.js'),
cloudron = require('../cloudron.js'),
HttpError = require('@cloudron/connect-lastmile').HttpError,
HttpSuccess = require('@cloudron/connect-lastmile').HttpSuccess,
safe = require('safetydance'),
translations = require('../translations.js');
async function getStatus(req, res, next) {
const [error, status] = await safe(cloudron.getStatus());
if (error) return next(BoxError.toHttpError(error));
+6 -8
View File
@@ -1,15 +1,13 @@
'use strict';
import assert from 'node:assert';
import BoxError from '../boxerror.js';
import * as community from '../community.js';
import { HttpSuccess } from '@cloudron/connect-lastmile';
import safe from 'safetydance';
exports = module.exports = {
export {
getAppVersion
};
const assert = require('node:assert'),
BoxError = require('../boxerror.js'),
community = require('../community.js'),
HttpSuccess = require('@cloudron/connect-lastmile').HttpSuccess,
safe = require('safetydance');
async function getAppVersion(req, res, next) {
assert.strictEqual(typeof req.query.url, 'string');
assert.strictEqual(typeof req.query.version, 'string');
+14 -16
View File
@@ -1,6 +1,18 @@
'use strict';
import AuditSource from '../auditsource.js';
import BoxError from '../boxerror.js';
import * as branding from '../branding.js';
import constants from '../constants.js';
import * as dashboard from '../dashboard.js';
import ejs from 'ejs';
import fs from 'node:fs';
import { HttpError } from '@cloudron/connect-lastmile';
import { HttpSuccess } from '@cloudron/connect-lastmile';
import path from 'node:path';
import paths from '../paths.js';
import safe from 'safetydance';
import * as settings from '../settings.js';
exports = module.exports = {
export {
getConfig,
startPrepareLocation,
@@ -17,20 +29,6 @@ exports = module.exports = {
renderActivation,
};
const AuditSource = require('../auditsource.js'),
BoxError = require('../boxerror.js'),
branding = require('../branding.js'),
constants = require('../constants.js'),
dashboard = require('../dashboard.js'),
ejs = require('ejs'),
fs = require('node:fs'),
HttpError = require('@cloudron/connect-lastmile').HttpError,
HttpSuccess = require('@cloudron/connect-lastmile').HttpSuccess,
path = require('node:path'),
paths = require('../paths.js'),
safe = require('safetydance'),
settings = require('../settings.js');
async function getConfig(req, res, next) {
const [error, cloudronConfig] = await safe(dashboard.getConfig());
if (error) return next(BoxError.toHttpError(error));
+8 -10
View File
@@ -1,18 +1,16 @@
'use strict';
import assert from 'node:assert';
import AuditSource from '../auditsource.js';
import BoxError from '../boxerror.js';
import * as directoryServer from '../directoryserver.js';
import { HttpError } from '@cloudron/connect-lastmile';
import { HttpSuccess } from '@cloudron/connect-lastmile';
import safe from 'safetydance';
exports = module.exports = {
export {
getConfig,
setConfig,
};
const assert = require('node:assert'),
AuditSource = require('../auditsource.js'),
BoxError = require('../boxerror.js'),
directoryServer = require('../directoryserver.js'),
HttpError = require('@cloudron/connect-lastmile').HttpError,
HttpSuccess = require('@cloudron/connect-lastmile').HttpSuccess,
safe = require('safetydance');
async function getConfig(req, res, next) {
const [error, config] = await safe(directoryServer.getConfig());
if (error) return next(BoxError.toHttpError(error));
+8 -10
View File
@@ -1,6 +1,12 @@
'use strict';
import assert from 'node:assert';
import AuditSource from '../auditsource.js';
import BoxError from '../boxerror.js';
import * as dockerRegistries from '../dockerregistries.js';
import { HttpError } from '@cloudron/connect-lastmile';
import { HttpSuccess } from '@cloudron/connect-lastmile';
import safe from 'safetydance';
exports = module.exports = {
export {
list,
add,
get,
@@ -9,14 +15,6 @@ exports = module.exports = {
load
};
const assert = require('node:assert'),
AuditSource = require('../auditsource.js'),
BoxError = require('../boxerror.js'),
dockerRegistries = require('../dockerregistries.js'),
HttpError = require('@cloudron/connect-lastmile').HttpError,
HttpSuccess = require('@cloudron/connect-lastmile').HttpSuccess,
safe = require('safetydance');
async function load(req, res, next) {
assert.strictEqual(typeof req.params.id, 'string');
+9 -11
View File
@@ -1,6 +1,13 @@
'use strict';
import assert from 'node:assert';
import AuditSource from '../auditsource.js';
import BoxError from '../boxerror.js';
import * as dns from '../dns.js';
import * as domains from '../domains.js';
import { HttpError } from '@cloudron/connect-lastmile';
import { HttpSuccess } from '@cloudron/connect-lastmile';
import safe from 'safetydance';
exports = module.exports = {
export {
add,
get,
list,
@@ -12,15 +19,6 @@ exports = module.exports = {
syncDnsRecords,
};
const assert = require('node:assert'),
AuditSource = require('../auditsource.js'),
BoxError = require('../boxerror.js'),
dns = require('../dns.js'),
domains = require('../domains.js'),
HttpError = require('@cloudron/connect-lastmile').HttpError,
HttpSuccess = require('@cloudron/connect-lastmile').HttpSuccess,
safe = require('safetydance');
async function add(req, res, next) {
assert.strictEqual(typeof req.body, 'object');
+6 -8
View File
@@ -1,16 +1,14 @@
'use strict';
import BoxError from '../boxerror.js';
import eventlog from '../eventlog.js';
import { HttpError } from '@cloudron/connect-lastmile';
import { HttpSuccess } from '@cloudron/connect-lastmile';
import safe from 'safetydance';
exports = module.exports = {
export {
get,
list
};
const BoxError = require('../boxerror.js'),
eventlog = require('../eventlog.js'),
HttpError = require('@cloudron/connect-lastmile').HttpError,
HttpSuccess = require('@cloudron/connect-lastmile').HttpSuccess,
safe = require('safetydance');
async function get(req, res, next) {
const [error, event] = await safe(eventlog.get(req.params.eventId));
if (error) return next(BoxError.toHttpError(error));
+8 -10
View File
@@ -1,19 +1,17 @@
'use strict';
import assert from 'node:assert';
import AuditSource from '../auditsource.js';
import BoxError from '../boxerror.js';
import * as externalLdap from '../externalldap.js';
import { HttpError } from '@cloudron/connect-lastmile';
import { HttpSuccess } from '@cloudron/connect-lastmile';
import safe from 'safetydance';
exports = module.exports = {
export {
getConfig,
setConfig,
sync
};
const assert = require('node:assert'),
AuditSource = require('../auditsource.js'),
BoxError = require('../boxerror.js'),
externalLdap = require('../externalldap.js'),
HttpError = require('@cloudron/connect-lastmile').HttpError,
HttpSuccess = require('@cloudron/connect-lastmile').HttpSuccess,
safe = require('safetydance');
async function sync(req, res, next) {
const [error, taskId] = await safe(externalLdap.startSyncer());
if (error) return next(new HttpError(500, error.message));
+7 -9
View File
@@ -1,16 +1,14 @@
'use strict';
import assert from 'node:assert';
import BoxError from '../boxerror.js';
import http from 'node:http';
import { HttpError } from '@cloudron/connect-lastmile';
import safe from 'safetydance';
import services from '../services.js';
exports = module.exports = {
export {
proxy,
};
const assert = require('node:assert'),
BoxError = require('../boxerror.js'),
http = require('node:http'),
HttpError = require('@cloudron/connect-lastmile').HttpError,
safe = require('safetydance'),
services = require('../services.js');
function proxy(kind) {
assert(kind === 'mail' || kind === 'volume' || kind === 'app');
+8 -10
View File
@@ -1,6 +1,12 @@
'use strict';
import assert from 'node:assert';
import AuditSource from '../auditsource.js';
import BoxError from '../boxerror.js';
import * as groups from '../groups.js';
import { HttpError } from '@cloudron/connect-lastmile';
import { HttpSuccess } from '@cloudron/connect-lastmile';
import safe from 'safetydance';
exports = module.exports = {
export {
load,
get,
@@ -12,14 +18,6 @@ exports = module.exports = {
setAllowedApps
};
const assert = require('node:assert'),
AuditSource = require('../auditsource.js'),
BoxError = require('../boxerror.js'),
groups = require('../groups.js'),
HttpError = require('@cloudron/connect-lastmile').HttpError,
HttpSuccess = require('@cloudron/connect-lastmile').HttpSuccess,
safe = require('safetydance');
async function load(req, res, next) {
assert.strictEqual(typeof req.params.groupId, 'string');
+75 -39
View File
@@ -1,41 +1,77 @@
'use strict';
import * as accesscontrol from './accesscontrol.js';
import * as appPasswords from './apppasswords.js';
import * as apps from './apps.js';
import * as applinks from './applinks.js';
import * as appstore from './appstore.js';
import * as archives from './archives.js';
import * as auth from './auth.js';
import * as backups from './backups.js';
import * as backupSites from './backupsites.js';
import * as branding from './branding.js';
import * as cloudron from './cloudron.js';
import * as community from './community.js';
import * as dashboard from './dashboard.js';
import * as directoryServer from './directoryserver.js';
import * as dockerRegistries from './dockerregistries.js';
import * as domains from './domains.js';
import * as eventlog from './eventlog.js';
import * as externalLdap from './externalldap.js';
import * as filemanager from './filemanager.js';
import * as groups from './groups.js';
import * as mail from './mail.js';
import * as mailserver from './mailserver.js';
import * as network from './network.js';
import * as notifications from './notifications.js';
import * as oidcClients from './oidcclients.js';
import * as profile from './profile.js';
import * as provision from './provision.js';
import * as reverseProxy from './reverseproxy.js';
import * as services from './services.js';
import * as system from './system.js';
import * as tasks from './tasks.js';
import * as tokens from './tokens.js';
import * as updater from './updater.js';
import * as userDirectory from './user-directory.js';
import * as users from './users.js';
import * as volumes from './volumes.js';
import * as wellknown from './wellknown.js';
exports = module.exports = {
accesscontrol: require('./accesscontrol.js'),
appPasswords: require('./apppasswords.js'),
apps: require('./apps.js'),
applinks: require('./applinks.js'),
appstore: require('./appstore.js'),
archives: require('./archives.js'),
auth: require('./auth.js'),
backups: require('./backups.js'),
backupSites: require('./backupsites.js'),
branding: require('./branding.js'),
cloudron: require('./cloudron.js'),
community: require('./community.js'),
dashboard: require('./dashboard.js'),
directoryServer: require('./directoryserver.js'),
dockerRegistries: require('./dockerregistries.js'),
domains: require('./domains.js'),
eventlog: require('./eventlog.js'),
externalLdap: require('./externalldap.js'),
filemanager: require('./filemanager.js'),
groups: require('./groups.js'),
mail: require('./mail.js'),
mailserver: require('./mailserver.js'),
network: require('./network.js'),
notifications: require('./notifications.js'),
oidcClients: require('./oidcclients.js'),
profile: require('./profile.js'),
provision: require('./provision.js'),
reverseProxy: require('./reverseproxy.js'),
services: require('./services.js'),
system: require('./system.js'),
tasks: require('./tasks.js'),
tokens: require('./tokens.js'),
updater: require('./updater.js'),
userDirectory: require('./user-directory.js'),
users: require('./users.js'),
volumes: require('./volumes.js'),
wellknown: require('./wellknown.js')
export {
accesscontrol,
appPasswords,
apps,
applinks,
appstore,
archives,
auth,
backups,
backupSites,
branding,
cloudron,
community,
dashboard,
directoryServer,
dockerRegistries,
domains,
eventlog,
externalLdap,
filemanager,
groups,
mail,
mailserver,
network,
notifications,
oidcClients,
profile,
provision,
reverseProxy,
services,
system,
tasks,
tokens,
updater,
userDirectory,
users,
volumes,
wellknown
};
+8 -10
View File
@@ -1,6 +1,12 @@
'use strict';
import assert from 'node:assert';
import AuditSource from '../auditsource.js';
import BoxError from '../boxerror.js';
import * as mail from '../mail.js';
import { HttpError } from '@cloudron/connect-lastmile';
import { HttpSuccess } from '@cloudron/connect-lastmile';
import safe from 'safetydance';
exports = module.exports = {
export {
getDomain,
listDomains,
@@ -32,14 +38,6 @@ exports = module.exports = {
getStats
};
const assert = require('node:assert'),
AuditSource = require('../auditsource.js'),
BoxError = require('../boxerror.js'),
mail = require('../mail.js'),
HttpError = require('@cloudron/connect-lastmile').HttpError,
HttpSuccess = require('@cloudron/connect-lastmile').HttpSuccess,
safe = require('safetydance');
async function getDomain(req, res, next) {
assert.strictEqual(typeof req.params.domain, 'string');
+13 -13
View File
@@ -1,6 +1,17 @@
'use strict';
import assert from 'node:assert';
import AuditSource from '../auditsource.js';
import BoxError from '../boxerror.js';
import debugModule from 'debug';
import http from 'node:http';
import { HttpError } from '@cloudron/connect-lastmile';
import { HttpSuccess } from '@cloudron/connect-lastmile';
import * as mailServer from '../mailserver.js';
import safe from 'safetydance';
import services from '../services.js';
exports = module.exports = {
const debug = debugModule('box:routes/mailserver');
export {
proxy,
proxyAndRestart,
queueProxy,
@@ -9,17 +20,6 @@ exports = module.exports = {
getLocation
};
const assert = require('node:assert'),
AuditSource = require('../auditsource.js'),
BoxError = require('../boxerror.js'),
debug = require('debug')('box:routes/mailserver'),
http = require('node:http'),
HttpError = require('@cloudron/connect-lastmile').HttpError,
HttpSuccess = require('@cloudron/connect-lastmile').HttpSuccess,
mailServer = require('../mailserver.js'),
safe = require('safetydance'),
services = require('../services.js');
async function proxyToMailContainer(port, pathname, req, res, next) {
req.clearTimeout();
+8 -10
View File
@@ -1,6 +1,12 @@
'use strict';
import assert from 'node:assert';
import AuditSource from '../auditsource.js';
import BoxError from '../boxerror.js';
import { HttpError } from '@cloudron/connect-lastmile';
import { HttpSuccess } from '@cloudron/connect-lastmile';
import * as network from '../network.js';
import safe from 'safetydance';
exports = module.exports = {
export {
getBlocklist,
setBlocklist,
@@ -17,14 +23,6 @@ exports = module.exports = {
getIPv6,
};
const assert = require('node:assert'),
AuditSource = require('../auditsource.js'),
BoxError = require('../boxerror.js'),
HttpError = require('@cloudron/connect-lastmile').HttpError,
HttpSuccess = require('@cloudron/connect-lastmile').HttpSuccess,
network = require('../network.js'),
safe = require('safetydance');
async function getBlocklist(req, res, next) {
const [error, blocklist] = await safe(network.getBlocklist());
if (error) return next(BoxError.toHttpError(error));
+7 -9
View File
@@ -1,19 +1,17 @@
'use strict';
import assert from 'node:assert';
import BoxError from '../boxerror.js';
import { HttpError } from '@cloudron/connect-lastmile';
import { HttpSuccess } from '@cloudron/connect-lastmile';
import * as notifications from '../notifications.js';
import safe from 'safetydance';
exports = module.exports = {
export {
load,
get,
list,
update
};
const assert = require('node:assert'),
BoxError = require('../boxerror.js'),
HttpError = require('@cloudron/connect-lastmile').HttpError,
HttpSuccess = require('@cloudron/connect-lastmile').HttpSuccess,
notifications = require('../notifications.js'),
safe = require('safetydance');
async function load(req, res, next) {
assert.strictEqual(typeof req.params.notificationId, 'string');
+7 -9
View File
@@ -1,6 +1,11 @@
'use strict';
import assert from 'node:assert';
import BoxError from '../boxerror.js';
import oidcClients from '../oidcclients.js';
import { HttpError } from '@cloudron/connect-lastmile';
import { HttpSuccess } from '@cloudron/connect-lastmile';
import safe from 'safetydance';
exports = module.exports = {
export {
load,
add,
list,
@@ -9,13 +14,6 @@ exports = module.exports = {
del,
};
const assert = require('node:assert'),
BoxError = require('../boxerror.js'),
oidcClients = require('../oidcclients.js'),
HttpError = require('@cloudron/connect-lastmile').HttpError,
HttpSuccess = require('@cloudron/connect-lastmile').HttpSuccess,
safe = require('safetydance');
async function add(req, res, next) {
assert.strictEqual(typeof req.body, 'object');
+13 -15
View File
@@ -1,6 +1,17 @@
'use strict';
import assert from 'node:assert';
import AuditSource from '../auditsource.js';
import BoxError from '../boxerror.js';
import { HttpError } from '@cloudron/connect-lastmile';
import { HttpSuccess } from '@cloudron/connect-lastmile';
import * as oidcServer from '../oidcserver.js';
import * as passkeys from '../passkeys.js';
import safe from 'safetydance';
import * as tokens from '../tokens.js';
import * as userDirectory from '../user-directory.js';
import * as users from '../users.js';
import * as settings from '../settings.js';
exports = module.exports = {
export {
canEditProfile,
get,
setDisplayName,
@@ -25,19 +36,6 @@ exports = module.exports = {
deletePasskey
};
const assert = require('node:assert'),
AuditSource = require('../auditsource.js'),
BoxError = require('../boxerror.js'),
HttpError = require('@cloudron/connect-lastmile').HttpError,
HttpSuccess = require('@cloudron/connect-lastmile').HttpSuccess,
oidcServer = require('../oidcserver.js'),
passkeys = require('../passkeys.js'),
safe = require('safetydance'),
tokens = require('../tokens.js'),
userDirectory = require('../user-directory.js'),
users = require('../users.js'),
settings = require('../settings.js');
async function canEditProfile(req, res, next) {
assert.strictEqual(typeof req.user, 'object');
+12 -15
View File
@@ -1,6 +1,16 @@
'use strict';
import assert from 'node:assert';
import AuditSource from '../auditsource.js';
import BoxError from '../boxerror.js';
import { HttpError } from '@cloudron/connect-lastmile';
import { HttpSuccess } from '@cloudron/connect-lastmile';
import * as network from '../network.js';
import * as provision from '../provision.js';
import safe from 'safetydance';
import superagent from '@cloudron/superagent';
import * as system from '../system.js';
import * as users from '../users.js';
exports = module.exports = {
export {
providerTokenAuth,
verifyUnprovisioned,
setup,
@@ -11,18 +21,6 @@ exports = module.exports = {
detectIP
};
const assert = require('node:assert'),
AuditSource = require('../auditsource.js'),
BoxError = require('../boxerror.js'),
HttpError = require('@cloudron/connect-lastmile').HttpError,
HttpSuccess = require('@cloudron/connect-lastmile').HttpSuccess,
network = require('../network.js'),
provision = require('../provision.js'),
safe = require('safetydance'),
superagent = require('@cloudron/superagent'),
system = require('../system.js'),
users = require('../users.js');
async function verifyUnprovisioned(req, res, next) {
const activated = await users.isActivated();
if (activated) return next(new HttpError(405, 'route unavailable post activation'));
@@ -36,7 +34,6 @@ async function providerTokenAuth(req, res, next) {
if (system.getProvider() === 'ami') {
if (typeof req.body.providerToken !== 'string' || !req.body.providerToken) return next(new HttpError(400, 'providerToken must be a non empty string'));
// IMDSv2 https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/configuring-instance-metadata-options.html
// https://aws.amazon.com/blogs/security/defense-in-depth-open-firewalls-reverse-proxies-ssrf-vulnerabilities-ec2-instance-metadata-service/
const imdsIp = req.body.ipv4Config?.provider === 'noop' ? '[fd00:ec2::254]' : '169.254.169.254'; // use ipv4config carefully, it's not validated yet at this point
+8 -10
View File
@@ -1,20 +1,18 @@
'use strict';
import assert from 'node:assert';
import AuditSource from '../auditsource.js';
import BoxError from '../boxerror.js';
import { HttpError } from '@cloudron/connect-lastmile';
import { HttpSuccess } from '@cloudron/connect-lastmile';
import * as reverseProxy from '../reverseproxy.js';
import safe from 'safetydance';
exports = module.exports = {
export {
getTrustedIps,
setTrustedIps,
renewCerts,
};
const assert = require('node:assert'),
AuditSource = require('../auditsource.js'),
BoxError = require('../boxerror.js'),
HttpError = require('@cloudron/connect-lastmile').HttpError,
HttpSuccess = require('@cloudron/connect-lastmile').HttpSuccess,
reverseProxy = require('../reverseproxy.js'),
safe = require('safetydance');
async function getTrustedIps(req, res, next) {
const [error, trustedIps] = await safe(reverseProxy.getTrustedIps());
if (error) return next(BoxError.toHttpError(error));
+10 -12
View File
@@ -1,6 +1,14 @@
'use strict';
import assert from 'node:assert';
import AuditSource from '../auditsource.js';
import BoxError from '../boxerror.js';
import { HttpError } from '@cloudron/connect-lastmile';
import { HttpSuccess } from '@cloudron/connect-lastmile';
import * as metrics from '../metrics.js';
import * as platform from '../platform.js';
import safe from 'safetydance';
import services from '../services.js';
exports = module.exports = {
export {
list,
get,
configure,
@@ -12,16 +20,6 @@ exports = module.exports = {
getPlatformStatus
};
const assert = require('node:assert'),
AuditSource = require('../auditsource.js'),
BoxError = require('../boxerror.js'),
HttpError = require('@cloudron/connect-lastmile').HttpError,
HttpSuccess = require('@cloudron/connect-lastmile').HttpSuccess,
metrics = require('../metrics.js'),
platform = require('../platform.js'),
safe = require('safetydance'),
services = require('../services.js');
async function list(req, res, next) {
const [error, result] = await safe(services.listServices());
if (error) return next(BoxError.toHttpError(error));
+8 -10
View File
@@ -1,6 +1,12 @@
'use strict';
import assert from 'node:assert';
import BoxError from '../boxerror.js';
import { HttpError } from '@cloudron/connect-lastmile';
import { HttpSuccess } from '@cloudron/connect-lastmile';
import * as metrics from '../metrics.js';
import safe from 'safetydance';
import * as system from '../system.js';
exports = module.exports = {
export {
reboot,
getInfo,
getMemory,
@@ -14,14 +20,6 @@ exports = module.exports = {
getCpus,
};
const assert = require('node:assert'),
BoxError = require('../boxerror.js'),
HttpError = require('@cloudron/connect-lastmile').HttpError,
HttpSuccess = require('@cloudron/connect-lastmile').HttpSuccess,
metrics = require('../metrics.js'),
safe = require('safetydance'),
system = require('../system.js');
async function reboot(req, res, next) {
// Finish the request, to let the appstore know we triggered the reboot
next(new HttpSuccess(202, {}));
+7 -9
View File
@@ -1,6 +1,11 @@
'use strict';
import assert from 'node:assert';
import BoxError from '../boxerror.js';
import { HttpError } from '@cloudron/connect-lastmile';
import { HttpSuccess } from '@cloudron/connect-lastmile';
import safe from 'safetydance';
import tasks from '../tasks.js';
exports = module.exports = {
export {
load,
get,
list,
@@ -11,13 +16,6 @@ exports = module.exports = {
getLogStream
};
const assert = require('node:assert'),
BoxError = require('../boxerror.js'),
HttpError = require('@cloudron/connect-lastmile').HttpError,
HttpSuccess = require('@cloudron/connect-lastmile').HttpSuccess,
safe = require('safetydance'),
tasks = require('../tasks.js');
async function load(req, res, next) {
assert.strictEqual(typeof req.params.taskId, 'string');
+7 -9
View File
@@ -1,17 +1,16 @@
/* jslint node:true */
import common from './common.js';
import expect from 'expect.js';
import superagent from '@cloudron/superagent';
import timers from 'timers/promises';
import * as tokens from '../../tokens.js';
/* global it:false */
/* global describe:false */
/* global before:false */
/* global after:false */
'use strict';
const common = require('./common.js'),
expect = require('expect.js'),
superagent = require('@cloudron/superagent'),
timers = require('timers/promises'),
tokens = require('../../tokens.js');
describe('API', function () {
const { setup, cleanup, serverUrl, owner, user } = common;
@@ -58,7 +57,6 @@ describe('API', function () {
expect(response.status).to.equal(401);
});
it('can get userInfo with token in auth header', async function () {
const response = await superagent.get(`${serverUrl}/api/v1/users/${user.id}`)
.set('Authorization', 'Bearer ' + owner.token);
+6 -7
View File
@@ -1,15 +1,14 @@
'use strict';
/* global it:false */
import * as applinks from '../../applinks.js';
import common from './common.js';
import expect from 'expect.js';
import superagent from '@cloudron/superagent';
/* global describe:false */
/* global before:false */
/* global after:false */
const applinks = require('../../applinks.js'),
common = require('./common.js'),
expect = require('expect.js'),
superagent = require('@cloudron/superagent');
describe('AppLinks API', function () {
const { setup, cleanup, serverUrl, owner } = common;
+5 -6
View File
@@ -1,15 +1,14 @@
/* jslint node:true */
import common from './common.js';
import expect from 'expect.js';
import superagent from '@cloudron/superagent';
/* global it:false */
/* global describe:false */
/* global before:false */
/* global after:false */
'use strict';
const common = require('./common.js'),
expect = require('expect.js'),
superagent = require('@cloudron/superagent');
describe('App Passwords', function () {
const { setup, cleanup, serverUrl, user } = common;
+30 -31
View File
@@ -1,33 +1,32 @@
'use strict';
/* global it:false */
import apps from '../../apps.js';
import async from 'async';
import child_process from 'node:child_process';
import constants from '../../constants.js';
import crypto from 'node:crypto';
import * as database from '../../database.js';
import Docker from 'dockerode';
import expect from 'expect.js';
import fs from 'node:fs';
import hat from '../../hat.js';
import http from 'node:http';
import * as ldapServer from '../../ldapserver.js';
import net from 'node:net';
import nock from 'nock';
import path from 'node:path';
import paths from '../../paths.js';
import * as platform from '../../platform.js';
import safe from 'safetydance';
import * as server from '../../server.js';
import * as settings from '../../settings.js';
import superagent from '@cloudron/superagent';
import * as tokens from '../../tokens.js';
import url from 'node:url';
/* global describe:false */
/* global before:false */
const apps = require('../../apps.js'),
async = require('async'),
child_process = require('node:child_process'),
constants = require('../../constants.js'),
crypto = require('node:crypto'),
database = require('../../database.js'),
Docker = require('dockerode'),
expect = require('expect.js'),
fs = require('node:fs'),
hat = require('../../hat.js'),
http = require('node:http'),
ldapServer = require('../../ldapserver.js'),
net = require('node:net'),
nock = require('nock'),
path = require('node:path'),
paths = require('../../paths.js'),
platform = require('../../platform.js'),
safe = require('safetydance'),
server = require('../../server.js'),
settings = require('../../settings.js'),
superagent = require('@cloudron/superagent'),
tokens = require('../../tokens.js'),
url = require('node:url');
const SERVER_URL = 'http://localhost:' + constants.PORT;
const docker = new Docker({ socketPath: '/var/run/docker.sock' });
@@ -52,7 +51,7 @@ let APP_ID;
const APP_SUBDOMAIN = 'appssubdomain';
const APP_SUBDOMAIN_NEW = 'appssubdomainnew';
const APP_MANIFEST = {}; // JSON.parse(fs.readFileSync(__dirname + '/../../../../test-app/CloudronManifest.json', 'utf8'));
const APP_MANIFEST = {}; // JSON.parse(fs.readFileSync(import.meta.dirname + '/../../../../test-app/CloudronManifest.json', 'utf8'));
APP_MANIFEST.dockerImage = TEST_IMAGE;
const USERNAME = 'superadmin';
@@ -189,7 +188,7 @@ function startBox(done) {
function (callback) {
appstoreIconServer
.get('/api/v1/apps/' + APP_STORE_ID + '/versions/' + APP_MANIFEST.version + '/icon')
.replyWithFile(200, path.resolve(__dirname, '../../../assets/avatar.png'));
.replyWithFile(200, path.resolve(import.meta.dirname, '../../../assets/avatar.png'));
const port = parseInt(url.parse(settings.apiServerOrigin()).port, 10);
http.createServer(appstoreIconServer.handler).listen(port, callback);
@@ -403,7 +402,7 @@ xdescribe('App API', function () {
const res = await superagent.post(SERVER_URL + '/api/v1/apps')
.query({ access_token: token })
.send({ appStoreId: APP_STORE_ID, subdomain: APP_SUBDOMAIN, domain: DOMAIN_0.domain, portBindings: { ECHO_SERVER_PORT: 7171 }, accessRestriction: { users: [ 'someuser' ], groups: [] } })
.send({ appStoreId: APP_STORE_ID, subdomain: APP_SUBDOMAIN, domain: DOMAIN_0.domain, portBindings: { ECHO_SERVER_PORT: 7171 }, accessRestriction: { users: [ 'someuser' ], groups: [] } });
expect(res.status).to.equal(202);
expect(res.body.id).to.be.a('string');
@@ -524,7 +523,7 @@ xdescribe('App API', function () {
it('volume created', function (done) {
expect(fs.existsSync(paths.APPS_DATA_DIR + '/' + APP_ID));
let volume = docker.getVolume(APP_ID + '-localstorage');
const volume = docker.getVolume(APP_ID + '-localstorage');
volume.inspect(function (error, volume) {
expect(error).to.be(null);
expect(volume.Labels.appId).to.eql(APP_ID);
@@ -1355,7 +1354,7 @@ xdescribe('App API', function () {
});
xit('can set data dir', function (done) {
let dataDir = path.join(paths.baseDir(), 'apps-test-datadir-' + crypto.randomBytes(4).readUInt32LE(0));
const dataDir = path.join(paths.baseDir(), 'apps-test-datadir-' + crypto.randomBytes(4).readUInt32LE(0));
fs.mkdirSync(dataDir);
superagent.post(SERVER_URL + '/api/v1/apps/' + APP_ID + '/configure/data_dir')
+9 -10
View File
@@ -1,18 +1,17 @@
/* global it:false */
import * as appstore from '../../appstore.js';
import common from './common.js';
import constants from '../../constants.js';
import expect from 'expect.js';
import nock from 'nock';
import * as settings from '../../settings.js';
import superagent from '@cloudron/superagent';
/* global describe:false */
/* global before:false */
/* global after:false */
'use strict';
const appstore = require('../../appstore.js'),
common = require('./common.js'),
constants = require('../../constants.js'),
expect = require('expect.js'),
nock = require('nock'),
settings = require('../../settings.js'),
superagent = require('@cloudron/superagent');
const { setup, cleanup, serverUrl, owner, appstoreToken } = common;
describe('Appstore Apps API', function () {
+7 -8
View File
@@ -1,16 +1,15 @@
/* global it:false */
import * as archives from '../../archives.js';
import backups from '../../backups.js';
import common from './common.js';
import expect from 'expect.js';
import superagent from '@cloudron/superagent';
/* global describe:false */
/* global before:false */
/* global after:false */
'use strict';
const archives = require('../../archives.js'),
backups = require('../../backups.js'),
common = require('./common.js'),
expect = require('expect.js'),
superagent = require('@cloudron/superagent');
describe('Archives API', function () {
const { setup, cleanup, serverUrl, owner, auditSource, getDefaultBackupSite } = common;
+3 -6
View File
@@ -1,10 +1,8 @@
/* global it, describe, before, after */
'use strict';
const common = require('./common.js'),
expect = require('expect.js'),
superagent = require('@cloudron/superagent');
import common from './common.js';
import expect from 'expect.js';
import superagent from '@cloudron/superagent';
describe('Backups API', function () {
const { setup, cleanup, waitForTask, serverUrl, owner, admin, getDefaultBackupSite } = common;
@@ -40,7 +38,6 @@ describe('Backups API', function () {
expect(response.body.backups.length).to.be(1); // only box backups are listed
});
it('cannot get random id', async function () {
const response = await superagent.get(`${serverUrl}/api/v1/backups/bad_id`)
.query({ access_token: owner.token })
+4 -6
View File
@@ -1,11 +1,9 @@
/* global it, describe, before, after */
'use strict';
const backupSites = require('../../backupsites.js'),
common = require('./common.js'),
expect = require('expect.js'),
superagent = require('@cloudron/superagent');
import * as backupSites from '../../backupsites.js';
import common from './common.js';
import expect from 'expect.js';
import superagent from '@cloudron/superagent';
describe('Backups API', function () {
const { setup, cleanup, waitForTask, serverUrl, owner, admin, getDefaultBackupSite } = common;
+8 -9
View File
@@ -1,17 +1,16 @@
'use strict';
/* global it:false */
import common from './common.js';
import constants from '../../constants.js';
import expect from 'expect.js';
import fs from 'node:fs';
import paths from '../../paths.js';
import superagent from '@cloudron/superagent';
/* global describe:false */
/* global before:false */
/* global after:false */
const common = require('./common.js'),
constants = require('../../constants.js'),
expect = require('expect.js'),
fs = require('node:fs'),
paths = require('../../paths.js'),
superagent = require('@cloudron/superagent');
describe('Branding API', function () {
const { setup, cleanup, serverUrl, owner } = common;
+7 -8
View File
@@ -1,16 +1,15 @@
'use strict';
/* global it:false */
import constants from '../../constants.js';
import common from './common.js';
import expect from 'expect.js';
import superagent from '@cloudron/superagent';
import url from 'node:url';
/* global describe:false */
/* global before:false */
/* global after:false */
const constants = require('../../constants.js'),
common = require('./common.js'),
expect = require('expect.js'),
superagent = require('@cloudron/superagent'),
url = require('node:url');
describe('Cloudron', function () {
const { setup, cleanup, serverUrl, owner, user, dashboardFqdn } = common;
+82 -78
View File
@@ -1,22 +1,22 @@
'use strict';
import apps from '../../apps.js';
import * as appstore from '../../appstore.js';
import * as backupSites from '../../backupsites.js';
import debugModule from 'debug';
import constants from '../../constants.js';
import * as database from '../../database.js';
import expect from 'expect.js';
import * as mailer from '../../mailer.js';
import nock from 'nock';
import oidcClients from '../../oidcclients.js';
import * as oidcServer from '../../oidcserver.js';
import * as server from '../../server.js';
import * as settings from '../../settings.js';
import superagent from '@cloudron/superagent';
import tasks from '../../tasks.js';
import timers from 'timers/promises';
import * as tokens from '../../tokens.js';
const apps = require('../../apps.js'),
appstore = require('../../appstore.js'),
backupSites = require('../../backupsites.js'),
debug = require('debug')('box:test/common'),
constants = require('../../constants.js'),
database = require('../../database.js'),
expect = require('expect.js'),
mailer = require('../../mailer.js'),
nock = require('nock'),
oidcClients = require('../../oidcclients.js'),
oidcServer = require('../../oidcserver.js'),
server = require('../../server.js'),
settings = require('../../settings.js'),
superagent = require('@cloudron/superagent'),
tasks = require('../../tasks.js'),
timers = require('timers/promises'),
tokens = require('../../tokens.js');
const debug = debugModule('box:test/common');
const manifest = {
'id': 'io.cloudron.test',
@@ -46,7 +46,57 @@ const manifest = {
}
};
exports = module.exports = {
const mockApiServerOrigin = 'http://localhost:6060';
const dashboardDomain = 'test.example.com';
const appstoreToken = 'toktok';
const owner = {
id: null,
username: 'superadmin',
password: 'Foobar?1337',
email: 'superadmin@cloudron.local',
displayName: 'Super Admin',
token: null
};
const admin = {
id: null,
username: 'administrator',
password: 'Foobar?1339',
email: 'admin@cloudron.local',
token: null
};
const user = {
id: null,
username: 'user',
password: 'Foobar?1338',
email: 'user@cloudron.local',
token: null
};
const app = {
id: 'appid',
appStoreId: 'appStoreId',
installationState: apps.ISTATE_PENDING_INSTALL,
runState: 'running',
subdomain: 'app',
domain: 'test.example.com',
fqdn: 'app.test.example.com',
manifest,
containerId: 'someid',
portBindings: {},
accessRestriction: null,
memoryLimit: 0,
mailboxDomain: 'test.example.com',
secondaryDomains: [],
redirectDomains: [],
aliasDomains: []
};
const serverUrl = `http://localhost:${constants.PORT}`;
export default {
setup,
setupServer,
cleanup,
@@ -54,61 +104,17 @@ exports = module.exports = {
checkMails,
waitForTask,
waitForAsyncTask,
owner: {
id: null,
username: 'superadmin',
password: 'Foobar?1337',
email: 'superadmin@cloudron.local',
displayName: 'Super Admin',
token: null
},
admin: {
id: null,
username: 'administrator',
password: 'Foobar?1339',
email: 'admin@cloudron.local',
token: null
},
user: {
id: null,
username: 'user',
password: 'Foobar?1338',
email: 'user@cloudron.local',
token: null
},
app: {
id: 'appid',
appStoreId: 'appStoreId',
installationState: apps.ISTATE_PENDING_INSTALL,
runState: 'running',
subdomain: 'app',
domain: 'test.example.com',
fqdn: 'app.test.example.com',
manifest,
containerId: 'someid',
portBindings: {},
accessRestriction: null,
memoryLimit: 0,
mailboxDomain: 'test.example.com',
secondaryDomains: [],
redirectDomains: [],
aliasDomains: []
},
owner,
admin,
user,
app,
getDefaultBackupSite,
mockApiServerOrigin: 'http://localhost:6060',
dashboardDomain: 'test.example.com',
mockApiServerOrigin,
dashboardDomain,
dashboardFqdn: 'my.test.example.com',
appstoreToken: 'toktok',
appstoreToken,
mailFqdn: 'my.test.example.com',
serverUrl: `http://localhost:${constants.PORT}`,
serverUrl,
auditSource: { ip: '5.6.7.8' }
};
@@ -116,7 +122,7 @@ async function setupServer() {
debug('Setting up server');
await database.initialize();
await database._clear();
await appstore._setApiServerOrigin(exports.mockApiServerOrigin);
await appstore._setApiServerOrigin(mockApiServerOrigin);
await oidcServer.stop();
await server.start();
debug('Set up server complete');
@@ -125,13 +131,11 @@ async function setupServer() {
async function setup() {
debug('Setting up');
const owner = exports.owner, serverUrl = exports.serverUrl, user = exports.user, admin = exports.admin;
await setupServer();
// setup
let response = await superagent.post(`${serverUrl}/api/v1/provision/setup`)
.send({ domainConfig: { provider: 'noop', domain: exports.dashboardDomain, config: {}, tlsConfig: { provider: 'fallback' } } });
.send({ domainConfig: { provider: 'noop', domain: dashboardDomain, config: {}, tlsConfig: { provider: 'fallback' } } });
expect(response.status).to.eql(200);
await timers.setTimeout(2000);
@@ -178,9 +182,9 @@ async function setup() {
user.token = token2.accessToken;
// create app object
await apps.add(exports.app.id, exports.app.appStoreId, '', exports.app.manifest, exports.app.subdomain, exports.app.domain, exports.app.portBindings, exports.app);
await apps.add(app.id, app.appStoreId, '', app.manifest, app.subdomain, app.domain, app.portBindings, app);
await settings._set(settings.APPSTORE_API_TOKEN_KEY, exports.appstoreToken); // appstore token
await settings._set(settings.APPSTORE_API_TOKEN_KEY, appstoreToken); // appstore token
debug('Setup complete');
}
@@ -194,7 +198,7 @@ async function cleanup() {
}
function clearMailQueue() {
mailer._mailQueue = [];
mailer.clearMailQueue();
}
async function checkMails(number) {
+13 -14
View File
@@ -1,14 +1,13 @@
'use strict';
/* global it:false */
import common from './common.js';
import expect from 'expect.js';
import superagent from '@cloudron/superagent';
/* global describe:false */
/* global before:false */
/* global after:false */
const common = require('./common.js'),
expect = require('expect.js'),
superagent = require('@cloudron/superagent');
describe('Directory Server API', function () {
const { setup, cleanup, serverUrl, owner } = common;
@@ -17,7 +16,7 @@ describe('Directory Server API', function () {
describe('directory_server config', function () {
// keep in sync with defaults in settings.js
let defaultConfig = {
const defaultConfig = {
enabled: false,
secret: '',
allowlist: ''
@@ -32,7 +31,7 @@ describe('Directory Server API', function () {
});
it('cannot set directory_server config without enabled boolean', async function () {
let tmp = JSON.parse(JSON.stringify(defaultConfig));
const tmp = JSON.parse(JSON.stringify(defaultConfig));
delete tmp.enabled;
const response = await superagent.post(`${serverUrl}/api/v1/directory_server/config`)
@@ -44,7 +43,7 @@ describe('Directory Server API', function () {
});
it('cannot set directory_server config without secret', async function () {
let tmp = JSON.parse(JSON.stringify(defaultConfig));
const tmp = JSON.parse(JSON.stringify(defaultConfig));
tmp.enabled = true;
delete tmp.secret;
@@ -57,7 +56,7 @@ describe('Directory Server API', function () {
});
it('cannot enable directory_server config with empty secret', async function () {
let tmp = JSON.parse(JSON.stringify(defaultConfig));
const tmp = JSON.parse(JSON.stringify(defaultConfig));
tmp.enabled = true;
const response = await superagent.post(`${serverUrl}/api/v1/directory_server/config`)
@@ -69,7 +68,7 @@ describe('Directory Server API', function () {
});
it('cannot enable directory_server config with empty allowlist', async function () {
let tmp = JSON.parse(JSON.stringify(defaultConfig));
const tmp = JSON.parse(JSON.stringify(defaultConfig));
tmp.enabled = true;
tmp.secret = 'ldapsecret';
@@ -82,7 +81,7 @@ describe('Directory Server API', function () {
});
it('can enable directory_server config', async function () {
let tmp = JSON.parse(JSON.stringify(defaultConfig));
const tmp = JSON.parse(JSON.stringify(defaultConfig));
tmp.enabled = true;
tmp.secret = 'ldapsecret';
tmp.allowlist = '1.2.3.4';
@@ -95,7 +94,7 @@ describe('Directory Server API', function () {
});
it('can get directory_server config', async function () {
let tmp = JSON.parse(JSON.stringify(defaultConfig));
const tmp = JSON.parse(JSON.stringify(defaultConfig));
tmp.enabled = true;
const response = await superagent.get(`${serverUrl}/api/v1/directory_server/config`)
@@ -107,7 +106,7 @@ describe('Directory Server API', function () {
// keep this last. this ensures directory server is stopped and the tests can exit
it('can disable directory_server config', async function () {
let tmp = JSON.parse(JSON.stringify(defaultConfig));
const tmp = JSON.parse(JSON.stringify(defaultConfig));
tmp.enabled = false;
tmp.secret = 'ldapsecret';
+6 -7
View File
@@ -1,16 +1,15 @@
/* jslint node:true */
import common from './common.js';
import constants from '../../constants.js';
import expect from 'expect.js';
import superagent from '@cloudron/superagent';
/* global it:false */
/* global describe:false */
/* global before:false */
/* global after:false */
'use strict';
const common = require('./common.js'),
constants = require('../../constants.js'),
expect = require('expect.js'),
superagent = require('@cloudron/superagent');
describe('Docker Registries', function () {
const { setup, cleanup, serverUrl, owner } = common;
+9 -10
View File
@@ -1,18 +1,17 @@
'use strict';
/* global it:false */
import child_process from 'node:child_process';
import common from './common.js';
import expect from 'expect.js';
import fs from 'node:fs';
import path from 'node:path';
import paths from '../../paths.js';
import superagent from '@cloudron/superagent';
/* global describe:false */
/* global before:false */
/* global after:false */
const child_process = require('node:child_process'),
common = require('./common.js'),
expect = require('expect.js'),
fs = require('node:fs'),
path = require('node:path'),
paths = require('../../paths.js'),
superagent = require('@cloudron/superagent');
const DOMAIN_0 = {
domain: 'domain0.com',
zoneName: 'domain0.com',
+7 -8
View File
@@ -1,17 +1,16 @@
/* jslint node:true */
import async from 'async';
import common from './common.js';
import eventlog from '../../eventlog.js';
import expect from 'expect.js';
import superagent from '@cloudron/superagent';
/* global it:false */
/* global describe:false */
/* global before:false */
/* global after:false */
'use strict';
const async = require('async'),
common = require('./common.js'),
eventlog = require('../../eventlog.js'),
expect = require('expect.js'),
superagent = require('@cloudron/superagent');
describe('Eventlog API', function () {
const { setup, cleanup, serverUrl, owner, user } = common;
+6 -7
View File
@@ -1,14 +1,13 @@
'use strict';
/* global it:false */
import common from './common.js';
import expect from 'expect.js';
import superagent from '@cloudron/superagent';
/* global describe:false */
/* global before:false */
/* global after:false */
const common = require('./common.js'),
expect = require('expect.js'),
superagent = require('@cloudron/superagent');
describe('External LDAP API', function () {
const { setup, cleanup, serverUrl, owner } = common;
@@ -17,7 +16,7 @@ describe('External LDAP API', function () {
describe('external_ldap', function () {
// keep in sync with defaults in settings.js
let defaultConfig = { provider: 'noop', autoCreate: false };
const defaultConfig = { provider: 'noop', autoCreate: false };
it('can get external_ldap (default)', async function () {
const response = await superagent.get(`${serverUrl}/api/v1/external_ldap/config`)
+5 -6
View File
@@ -1,15 +1,14 @@
/* jslint node:true */
import common from './common.js';
import expect from 'expect.js';
import superagent from '@cloudron/superagent';
/* global it:false */
/* global describe:false */
/* global before:false */
/* global after:false */
'use strict';
const common = require('./common.js'),
expect = require('expect.js'),
superagent = require('@cloudron/superagent');
const GROUP_NAME = 'externals';
let group0Object, group1Object;
+11 -15
View File
@@ -1,16 +1,16 @@
'use strict';
/* global it:false */
import common from './common.js';
import expect from 'expect.js';
import * as mail from '../../mail.js';
import superagent from '@cloudron/superagent';
import * as _ from '../../underscore.js';
import * as dig from '../../dig.js';
/* global describe:false */
/* global before:false */
/* global after:false */
const common = require('./common.js'),
expect = require('expect.js'),
mail = require('../../mail.js'),
superagent = require('@cloudron/superagent'),
_ = require('../../underscore.js');
describe('Mail API', function () {
const { setup, cleanup, serverUrl, owner, dashboardDomain, dashboardFqdn, mailFqdn } = common;
@@ -48,16 +48,13 @@ describe('Mail API', function () {
});
describe('status', function () {
let resolve = null;
let dnsAnswerQueue = [];
let dkimDomain, spfDomain, mxDomain, dmarcDomain;
before(async function () {
const dig = require('../../dig.js');
// replace dns resolveTxt()
resolve = dig.resolve;
dig.resolve = async function (hostname, type/*, options*/) {
dig._setMockResolve(async function (hostname, type/*, options*/) {
expect(hostname).to.be.a('string');
if (!dnsAnswerQueue[hostname] || !(type in dnsAnswerQueue[hostname])) throw new Error('no mock answer');
@@ -65,7 +62,7 @@ describe('Mail API', function () {
if (dnsAnswerQueue[hostname][type] === null) throw new Error({ code: 'ENODATA'} );
return dnsAnswerQueue[hostname][type];
};
});
dkimDomain = `cloudron._domainkey.${dashboardDomain}`; // no suffix for provisioned domains
spfDomain = dashboardDomain;
@@ -80,9 +77,8 @@ describe('Mail API', function () {
});
after(function (done) {
const dig = require('../../dig.js');
dig.resolve = resolve;
dig._setMockResolve(null);
done();
});
+5 -6
View File
@@ -1,14 +1,13 @@
'use strict';
/* global it:false */
import common from './common.js';
import expect from 'expect.js';
import superagent from '@cloudron/superagent';
/* global describe:false */
/* global before:false */
/* global after:false */
const common = require('./common.js'),
expect = require('expect.js'),
superagent = require('@cloudron/superagent');
describe('Network API', function () {
const { setup, cleanup, serverUrl, owner } = common;
+6 -7
View File
@@ -1,15 +1,14 @@
'use strict';
/* global it:false */
import common from './common.js';
import expect from 'expect.js';
import * as notifications from '../../notifications.js';
import superagent from '@cloudron/superagent';
/* global describe:false */
/* global before:false */
/* global after:false */
const common = require('./common.js'),
expect = require('expect.js'),
notifications = require('../../notifications.js'),
superagent = require('@cloudron/superagent');
describe('Notifications API', function () {
const { setup, cleanup, serverUrl, owner } = common;
+5 -6
View File
@@ -1,15 +1,14 @@
/* jslint node:true */
import common from './common.js';
import expect from 'expect.js';
import superagent from '@cloudron/superagent';
/* global it:false */
/* global describe:false */
/* global before:false */
/* global after:false */
'use strict';
const common = require('./common.js'),
expect = require('expect.js'),
superagent = require('@cloudron/superagent');
const CLIENT_0 = {
id: 'client0',
name: 'test client 0',
+11 -10
View File
@@ -1,17 +1,19 @@
/* jslint node:true */
import common from './common.js';
import expect from 'expect.js';
import fs from 'node:fs';
import speakeasy from 'speakeasy';
import superagent from '@cloudron/superagent';
import * as tokens from '../../tokens.js';
const customAvatarSize = fs.readFileSync('./logo.png').length;
/* global it:false */
/* global describe:false */
/* global before:false */
/* global after:false */
'use strict';
const common = require('./common.js'),
expect = require('expect.js'),
speakeasy = require('speakeasy'),
superagent = require('@cloudron/superagent'),
tokens = require('../../tokens.js');
describe('Profile API', function () {
const { setup, cleanup, serverUrl, owner, user } = common;
@@ -316,7 +318,7 @@ describe('Profile API', function () {
.query({ access_token: user.token })
.attach('avatar', './logo.png');
customAvatarSize = require('node:fs').readFileSync('./logo.png').length;
customAvatarSize = fs.readFileSync('./logo.png').length;
expect(response.status).to.be(204);
});
@@ -363,7 +365,6 @@ describe('Profile API', function () {
.query({ access_token: user.token })
.ok(() => true);
const customAvatarSize = require('node:fs').readFileSync('./logo.png').length;
expect(parseInt(response2.headers['content-length'])).to.equal(customAvatarSize);
expect(response2.status).to.equal(200);
});
+8 -10
View File
@@ -1,18 +1,16 @@
'use strict';
/* global it:false */
import common from './common.js';
import * as appstore from '../../appstore.js';
import expect from 'expect.js';
import nock from 'nock';
import superagent from '@cloudron/superagent';
import timers from 'timers/promises';
/* global describe:false */
/* global before:false */
/* global after:false */
const common = require('./common.js');
const appstore = require('../../appstore.js'),
expect = require('expect.js'),
nock = require('nock'),
superagent = require('@cloudron/superagent'),
timers = require('timers/promises');
const DOMAIN = 'example-server-test.com';
describe('Provision', function () {
+13 -14
View File
@@ -1,22 +1,21 @@
'use strict';
/* global it:false */
import constants from '../../constants.js';
import common from './common.js';
import { EventSource } from 'eventsource';
import expect from 'expect.js';
import fs from 'node:fs';
import http from 'node:http';
import nock from 'nock';
import os from 'node:os';
import paths from '../../paths.js';
import safe from 'safetydance';
import superagent from '@cloudron/superagent';
/* global describe:false */
/* global before:false */
/* global after:false */
const constants = require('../../constants.js'),
common = require('./common.js'),
{ EventSource } = require('eventsource'),
expect = require('expect.js'),
fs = require('node:fs'),
http = require('node:http'),
nock = require('nock'),
os = require('node:os'),
paths = require('../../paths.js'),
safe = require('safetydance'),
superagent = require('@cloudron/superagent');
describe('System', function () {
const { setup, cleanup, serverUrl, owner, user, waitForAsyncTask } = common;
+7 -9
View File
@@ -1,16 +1,15 @@
'use strict';
/* global it:false */
import common from './common.js';
import expect from 'expect.js';
import safe from 'safetydance';
import superagent from '@cloudron/superagent';
import tasks from '../../tasks.js';
/* global describe:false */
/* global before:false */
/* global after:false */
const common = require('./common.js'),
expect = require('expect.js'),
safe = require('safetydance'),
superagent = require('@cloudron/superagent'),
tasks = require('../../tasks.js');
describe('Tasks API', function () {
const { setup, cleanup, serverUrl, owner } = common;
@@ -56,7 +55,6 @@ describe('Tasks API', function () {
if (response.status !== 409) throw Error('Expecting 409');
});
it('can stop task', async function () {
const taskId = await tasks.add(tasks._TASK_SLEEP, [ 10000 ]);
+5 -6
View File
@@ -1,14 +1,13 @@
'use strict';
/* global it:false */
import common from './common.js';
import expect from 'expect.js';
import superagent from '@cloudron/superagent';
/* global describe:false */
/* global before:false */
/* global after:false */
const common = require('./common.js'),
expect = require('expect.js'),
superagent = require('@cloudron/superagent');
describe('Tokens API', function () {
const { setup, cleanup, serverUrl, owner } = common;
+6 -7
View File
@@ -1,15 +1,14 @@
'use strict';
/* global it:false */
import common from './common.js';
import constants from '../../constants.js';
import expect from 'expect.js';
import superagent from '@cloudron/superagent';
/* global describe:false */
/* global before:false */
/* global after:false */
const common = require('./common.js'),
constants = require('../../constants.js'),
expect = require('expect.js'),
superagent = require('@cloudron/superagent');
describe('Updater API', function () {
const { setup, cleanup, serverUrl, owner } = common;
+5 -6
View File
@@ -1,15 +1,14 @@
/* jslint node:true */
import common from './common.js';
import expect from 'expect.js';
import superagent from '@cloudron/superagent';
/* global it:false */
/* global describe:false */
/* global before:false */
/* global after:false */
'use strict';
const common = require('./common.js'),
expect = require('expect.js'),
superagent = require('@cloudron/superagent');
describe('User Directory API', function () {
const { setup, cleanup, serverUrl, owner, user } = common;
+8 -8
View File
@@ -1,15 +1,15 @@
/* global it:false */
import common from './common.js';
import expect from 'expect.js';
import fs from 'node:fs';
import superagent from '@cloudron/superagent';
import * as users from '../../users.js';
/* global describe:false */
/* global before:false */
/* global after:false */
'use strict';
const common = require('./common.js'),
expect = require('expect.js'),
superagent = require('@cloudron/superagent'),
users = require('../../users.js');
describe('Users API', function () {
const { setup, cleanup, serverUrl, owner, user, dashboardDomain } = common;
@@ -389,7 +389,7 @@ describe('Users API', function () {
.query({ access_token: owner.token })
.attach('avatar', './logo.png');
customAvatarSize = require('node:fs').readFileSync('./logo.png').length;
customAvatarSize = fs.readFileSync('./logo.png').length;
expect(response.status).to.equal(204);
+7 -8
View File
@@ -1,15 +1,14 @@
'use strict';
/* global it:false */
import common from './common.js';
import expect from 'expect.js';
import safe from 'safetydance';
import superagent from '@cloudron/superagent';
/* global describe:false */
/* global before:false */
/* global after:false */
const common = require('./common.js'),
expect = require('expect.js'),
safe = require('safetydance'),
superagent = require('@cloudron/superagent');
describe('Volumes API', function () {
const { setup, cleanup, serverUrl, owner } = common;
@@ -69,7 +68,7 @@ describe('Volumes API', function () {
});
it('cannot update volume', async function () {
let [error, response] = await safe(superagent.post(`${serverUrl}/api/v1/volumes/${volumeId}`)
const [error, response] = await safe(superagent.post(`${serverUrl}/api/v1/volumes/${volumeId}`)
.query({ access_token: owner.token })
.send({ mountOptions: { hostPath: '/media/cloudron-test-music-2' }})
.ok(() => true));
+8 -10
View File
@@ -1,6 +1,12 @@
'use strict';
import assert from 'node:assert';
import BoxError from '../boxerror.js';
import { HttpError } from '@cloudron/connect-lastmile';
import { HttpSuccess } from '@cloudron/connect-lastmile';
import oidcClients from '../oidcclients.js';
import safe from 'safetydance';
import * as tokens from '../tokens.js';
exports = module.exports = {
export {
verifyOwnership,
list,
get,
@@ -8,14 +14,6 @@ exports = module.exports = {
del
};
const assert = require('node:assert'),
BoxError = require('../boxerror.js'),
HttpError = require('@cloudron/connect-lastmile').HttpError,
HttpSuccess = require('@cloudron/connect-lastmile').HttpSuccess,
oidcClients = require('../oidcclients.js'),
safe = require('safetydance'),
tokens = require('../tokens.js');
async function verifyOwnership(req, res, next) {
assert.strictEqual(typeof req.user, 'object');
assert.strictEqual(typeof req.params.id, 'string');
+8 -10
View File
@@ -1,6 +1,12 @@
'use strict';
import assert from 'node:assert';
import AuditSource from '../auditsource.js';
import BoxError from '../boxerror.js';
import { HttpError } from '@cloudron/connect-lastmile';
import { HttpSuccess } from '@cloudron/connect-lastmile';
import safe from 'safetydance';
import * as updater from '../updater.js';
exports = module.exports = {
export {
getAutoupdatePattern,
setAutoupdatePattern,
@@ -10,14 +16,6 @@ exports = module.exports = {
updateBox,
};
const assert = require('node:assert'),
AuditSource = require('../auditsource.js'),
BoxError = require('../boxerror.js'),
HttpError = require('@cloudron/connect-lastmile').HttpError,
HttpSuccess = require('@cloudron/connect-lastmile').HttpSuccess,
safe = require('safetydance'),
updater = require('../updater.js');
async function getAutoupdatePattern(req, res, next) {
const [error, pattern] = await safe(updater.getAutoupdatePattern());
if (error) return next(BoxError.toHttpError(error));
+8 -10
View File
@@ -1,18 +1,16 @@
'use strict';
import assert from 'node:assert';
import AuditSource from '../auditsource.js';
import BoxError from '../boxerror.js';
import { HttpError } from '@cloudron/connect-lastmile';
import { HttpSuccess } from '@cloudron/connect-lastmile';
import safe from 'safetydance';
import * as userDirectory from '../user-directory.js';
exports = module.exports = {
export {
getProfileConfig,
setProfileConfig
};
const assert = require('node:assert'),
AuditSource = require('../auditsource.js'),
BoxError = require('../boxerror.js'),
HttpError = require('@cloudron/connect-lastmile').HttpError,
HttpSuccess = require('@cloudron/connect-lastmile').HttpSuccess,
safe = require('safetydance'),
userDirectory = require('../user-directory.js');
async function getProfileConfig(req, res, next) {
const [error, directoryConfig] = await safe(userDirectory.getProfileConfig());
if (error) return next(BoxError.toHttpError(error));
+10 -12
View File
@@ -1,6 +1,14 @@
'use strict';
import assert from 'node:assert';
import AuditSource from '../auditsource.js';
import BoxError from '../boxerror.js';
import * as groups from '../groups.js';
import { HttpError } from '@cloudron/connect-lastmile';
import { HttpSuccess } from '@cloudron/connect-lastmile';
import safe from 'safetydance';
import * as users from '../users.js';
import * as _ from '../underscore.js';
exports = module.exports = {
export {
get,
list,
add,
@@ -29,16 +37,6 @@ exports = module.exports = {
load
};
const assert = require('node:assert'),
AuditSource = require('../auditsource.js'),
BoxError = require('../boxerror.js'),
groups = require('../groups.js'),
HttpError = require('@cloudron/connect-lastmile').HttpError,
HttpSuccess = require('@cloudron/connect-lastmile').HttpSuccess,
safe = require('safetydance'),
users = require('../users.js'),
_ = require('../underscore.js');
async function load(req, res, next) {
assert.strictEqual(typeof req.params.userId, 'string');
+8 -10
View File
@@ -1,6 +1,12 @@
'use strict';
import assert from 'node:assert';
import AuditSource from '../auditsource.js';
import BoxError from '../boxerror.js';
import * as volumes from '../volumes.js';
import { HttpError } from '@cloudron/connect-lastmile';
import { HttpSuccess } from '@cloudron/connect-lastmile';
import safe from 'safetydance';
exports = module.exports = {
export {
add,
get,
update,
@@ -11,14 +17,6 @@ exports = module.exports = {
getStatus
};
const assert = require('node:assert'),
AuditSource = require('../auditsource.js'),
BoxError = require('../boxerror.js'),
volumes = require('../volumes.js'),
HttpError = require('@cloudron/connect-lastmile').HttpError,
HttpSuccess = require('@cloudron/connect-lastmile').HttpSuccess,
safe = require('safetydance');
async function load(req, res, next) {
assert.strictEqual(typeof req.params.id, 'string');
+4 -6
View File
@@ -1,13 +1,11 @@
'use strict';
import { HttpError } from '@cloudron/connect-lastmile';
import safe from 'safetydance';
import * as wellknown from '../wellknown.js';
exports = module.exports = {
export {
get
};
const HttpError = require('@cloudron/connect-lastmile').HttpError,
safe = require('safetydance'),
wellknown = require('../wellknown.js');
async function get(req, res, next) {
const host = req.headers['host'];
const location = req.params.location.join('/');