Moved settings.js to ts.

This commit is contained in:
SamTV12345 2024-02-21 21:48:51 +01:00
parent 71c74bc633
commit fbf8667019
44 changed files with 852 additions and 760 deletions

View file

@ -12,7 +12,7 @@ process.on('unhandledRejection', (err) => { throw err; });
const fs = require('fs'); const fs = require('fs');
const path = require('path'); const path = require('path');
const querystring = require('querystring'); const querystring = require('querystring');
import * as settings from '../node/utils/Settings'; import {settings} from '../node/utils/Settings';
const supertest = require('supertest'); const supertest = require('supertest');
(async () => { (async () => {

View file

@ -49,7 +49,7 @@ const unescape = (val) => {
const fs = require('fs'); const fs = require('fs');
const log4js = require('log4js'); const log4js = require('log4js');
const readline = require('readline'); const readline = require('readline');
import * as settings from '../node/utils/Settings'; import {settings} from '../node/utils/Settings';
const ueberDB = require('ueberdb2'); const ueberDB = require('ueberdb2');
const dbWrapperSettings = { const dbWrapperSettings = {

View file

@ -14,7 +14,7 @@ process.on('unhandledRejection', (err) => { throw err; });
const dirtyDb = require('dirty'); const dirtyDb = require('dirty');
const log4js = require('log4js'); const log4js = require('log4js');
import * as settings from '../node/utils/Settings'; import {settings} from '../node/utils/Settings';
const ueberDB = require('ueberdb2'); const ueberDB = require('ueberdb2');
const util = require('util'); const util = require('util');

View file

@ -19,7 +19,7 @@ let valueCount = 0;
(async () => { (async () => {
// initialize database // initialize database
import * as settings from '../node/utils/Settings'; import {settings} from '../node/utils/Settings';
const db = require('../node/db/DB'); const db = require('../node/db/DB');
await db.init(); await db.init();

View file

@ -21,7 +21,7 @@
* limitations under the License. * limitations under the License.
*/ */
import {dbSettings, dbType} from "../utils/Settings"; import {settings} from "../utils/Settings";
const ueberDB = require('ueberdb2'); const ueberDB = require('ueberdb2');
const log4js = require('log4js'); const log4js = require('log4js');
@ -38,7 +38,7 @@ exports.db = null;
* Initializes the database with the settings provided by the settings module * Initializes the database with the settings provided by the settings module
*/ */
exports.init = async () => { exports.init = async () => {
exports.db = new ueberDB.Database(dbType, dbSettings, null, logger); exports.db = new ueberDB.Database(settings.dbType, settings.dbSettings, null, logger);
await exports.db.init(); await exports.db.init();
if (exports.db.metrics != null) { if (exports.db.metrics != null) {
for (const [metric, value] of Object.entries(exports.db.metrics)) { for (const [metric, value] of Object.entries(exports.db.metrics)) {

View file

@ -10,7 +10,7 @@ const AttributePool = require('../../static/js/AttributePool');
const Stream = require('../utils/Stream'); const Stream = require('../utils/Stream');
const assert = require('assert').strict; const assert = require('assert').strict;
const db = require('./DB'); const db = require('./DB');
import * as settings from '../utils/Settings'; import {settings} from '../utils/Settings';
const authorManager = require('./AuthorManager'); const authorManager = require('./AuthorManager');
const padManager = require('./PadManager'); const padManager = require('./PadManager');
const padMessageHandler = require('../handler/PadMessageHandler'); const padMessageHandler = require('../handler/PadMessageHandler');

View file

@ -22,7 +22,7 @@
const CustomError = require('../utils/customError'); const CustomError = require('../utils/customError');
const Pad = require('../db/Pad'); const Pad = require('../db/Pad');
const db = require('./DB'); const db = require('./DB');
import * as settings from '../utils/Settings'; import {settings} from '../utils/Settings';
/** /**
* A cache of all loaded Pads. * A cache of all loaded Pads.

View file

@ -24,7 +24,7 @@ const hooks = require('../../static/js/pluginfw/hooks.js');
const padManager = require('./PadManager'); const padManager = require('./PadManager');
const readOnlyManager = require('./ReadOnlyManager'); const readOnlyManager = require('./ReadOnlyManager');
const sessionManager = require('./SessionManager'); const sessionManager = require('./SessionManager');
import * as settings from '../utils/Settings'; import {settings} from '../utils/Settings';
const webaccess = require('../hooks/express/webaccess'); const webaccess = require('../hooks/express/webaccess');
const log4js = require('log4js'); const log4js = require('log4js');
const authLogger = log4js.getLogger('auth'); const authLogger = log4js.getLogger('auth');

View file

@ -25,7 +25,7 @@ const fs = require('fs');
const hooks = require('../../static/js/pluginfw/hooks.js'); const hooks = require('../../static/js/pluginfw/hooks.js');
const path = require('path'); const path = require('path');
const resolve = require('resolve'); const resolve = require('resolve');
import * as settings from '../utils/Settings' import {root, settings} from '../utils/Settings'
const templateCache = new Map(); const templateCache = new Map();
@ -38,16 +38,16 @@ exports.info = {
const getCurrentFile = () => exports.info.file_stack[exports.info.file_stack.length - 1]; const getCurrentFile = () => exports.info.file_stack[exports.info.file_stack.length - 1];
exports._init = (b, recursive) => { exports._init = (b:string, recursive: boolean) => {
exports.info.__output_stack.push(exports.info.__output); exports.info.__output_stack.push(exports.info.__output);
exports.info.__output = b; exports.info.__output = b;
}; };
exports._exit = (b, recursive) => { exports._exit = (b: string, recursive: boolean) => {
exports.info.__output = exports.info.__output_stack.pop(); exports.info.__output = exports.info.__output_stack.pop();
}; };
exports.begin_block = (name) => { exports.begin_block = (name:string) => {
exports.info.block_stack.push(name); exports.info.block_stack.push(name);
exports.info.__output_stack.push(exports.info.__output.get()); exports.info.__output_stack.push(exports.info.__output.get());
exports.info.__output.set(''); exports.info.__output.set('');
@ -63,7 +63,7 @@ exports.end_block = () => {
exports.info.__output.set(exports.info.__output.get().concat(args.content)); exports.info.__output.set(exports.info.__output.get().concat(args.content));
}; };
exports.require = (name, args, mod) => { exports.require = (name: string, args: any, mod: any) => {
if (args == null) args = {}; if (args == null) args = {};
let basedir = __dirname; let basedir = __dirname;
@ -76,7 +76,7 @@ exports.require = (name, args, mod) => {
basedir = path.dirname(mod.filename); basedir = path.dirname(mod.filename);
paths = mod.paths; paths = mod.paths;
} }
paths.push(settings.root + '/plugin_packages') paths.push(root + '/plugin_packages')
const ejspath = resolve.sync(name, {paths, basedir, extensions: ['.html', '.ejs']}); const ejspath = resolve.sync(name, {paths, basedir, extensions: ['.html', '.ejs']});

View file

@ -24,7 +24,7 @@ const exporthtml = require('../utils/ExportHtml');
const exporttxt = require('../utils/ExportTxt'); const exporttxt = require('../utils/ExportTxt');
const exportEtherpad = require('../utils/ExportEtherpad'); const exportEtherpad = require('../utils/ExportEtherpad');
const fs = require('fs'); const fs = require('fs');
import * as settings from '../utils/Settings'; import {settings} from '../utils/Settings';
const os = require('os'); const os = require('os');
const hooks = require('../../static/js/pluginfw/hooks'); const hooks = require('../../static/js/pluginfw/hooks');
const util = require('util'); const util = require('util');

View file

@ -25,7 +25,7 @@ const padManager = require('../db/PadManager');
const padMessageHandler = require('./PadMessageHandler'); const padMessageHandler = require('./PadMessageHandler');
const fs = require('fs').promises; const fs = require('fs').promises;
const path = require('path'); const path = require('path');
import * as settings from '../utils/Settings'; import {settings} from '../utils/Settings';
const {Formidable} = require('formidable'); const {Formidable} = require('formidable');
const os = require('os'); const os = require('os');
const importHtml = require('../utils/ImportHtml'); const importHtml = require('../utils/ImportHtml');

View file

@ -28,7 +28,7 @@ const AttributeManager = require('../../static/js/AttributeManager');
const authorManager = require('../db/AuthorManager'); const authorManager = require('../db/AuthorManager');
const {padutils} = require('../../static/js/pad_utils'); const {padutils} = require('../../static/js/pad_utils');
const readOnlyManager = require('../db/ReadOnlyManager'); const readOnlyManager = require('../db/ReadOnlyManager');
import * as settings from '../utils/Settings'; import {settings} from '../utils/Settings';
const securityManager = require('../db/SecurityManager'); const securityManager = require('../db/SecurityManager');
const plugins = require('../../static/js/pluginfw/plugin_defs.js'); const plugins = require('../../static/js/pluginfw/plugin_defs.js');
const log4js = require('log4js'); const log4js = require('log4js');

View file

@ -21,7 +21,7 @@
*/ */
const log4js = require('log4js'); const log4js = require('log4js');
import * as settings from '../utils/Settings'; import {settings} from '../utils/Settings';
const stats = require('../../node/stats') const stats = require('../../node/stats')
const logger = log4js.getLogger('socket.io'); const logger = log4js.getLogger('socket.io');

View file

@ -14,7 +14,7 @@ import fs from 'fs';
const hooks = require('../../static/js/pluginfw/hooks'); const hooks = require('../../static/js/pluginfw/hooks');
import log4js from 'log4js'; import log4js from 'log4js';
const SessionStore = require('../db/SessionStore'); const SessionStore = require('../db/SessionStore');
import * as settings from '../utils/Settings'; import {getEpVersion, getGitCommit, settings} from '../utils/Settings';
const stats = require('../stats') const stats = require('../stats')
import util from 'util'; import util from 'util';
const webaccess = require('./express/webaccess'); const webaccess = require('./express/webaccess');
@ -68,9 +68,9 @@ const closeServer = async () => {
exports.createServer = async () => { exports.createServer = async () => {
console.log('Report bugs at https://github.com/ether/etherpad-lite/issues'); console.log('Report bugs at https://github.com/ether/etherpad-lite/issues');
serverName = `Etherpad ${settings.getGitCommit()} (https://etherpad.org)`; serverName = `Etherpad ${getGitCommit()} (https://etherpad.org)`;
console.log(`Your Etherpad version is ${settings.getEpVersion()} (${settings.getGitCommit()})`); console.log(`Your Etherpad version is ${getEpVersion()} (${getGitCommit()})`);
await exports.restartServer(); await exports.restartServer();

View file

@ -7,7 +7,7 @@ import {QueryType} from "../../types/QueryType";
import {PluginType} from "../../types/Plugin"; import {PluginType} from "../../types/Plugin";
const eejs = require('../../eejs'); const eejs = require('../../eejs');
import * as settings from '../../utils/Settings'; import {getEpVersion, getGitCommit} from '../../utils/Settings';
const installer = require('../../../static/js/pluginfw/installer'); const installer = require('../../../static/js/pluginfw/installer');
const pluginDefs = require('../../../static/js/pluginfw/plugin_defs'); const pluginDefs = require('../../../static/js/pluginfw/plugin_defs');
const plugins = require('../../../static/js/pluginfw/plugins'); const plugins = require('../../../static/js/pluginfw/plugins');
@ -24,8 +24,8 @@ exports.expressCreateServer = (hookName:string, args: ArgsExpressType, cb:Functi
}); });
args.app.get('/admin/plugins/info', (req:any, res:any) => { args.app.get('/admin/plugins/info', (req:any, res:any) => {
const gitCommit = settings.getGitCommit(); const gitCommit = getGitCommit();
const epVersion = settings.getEpVersion(); const epVersion = getEpVersion();
res.send(eejs.require('ep_etherpad-lite/templates/admin/plugins-info.html', { res.send(eejs.require('ep_etherpad-lite/templates/admin/plugins-info.html', {
gitCommit, gitCommit,

View file

@ -4,8 +4,7 @@ const eejs = require('../../eejs');
const fsp = require('fs').promises; const fsp = require('fs').promises;
const hooks = require('../../../static/js/pluginfw/hooks'); const hooks = require('../../../static/js/pluginfw/hooks');
const plugins = require('../../../static/js/pluginfw/plugins'); const plugins = require('../../../static/js/pluginfw/plugins');
import {reloadSettings, settingsFilename, showSettingsInAdminPage} from '../../utils/Settings'; import {reloadSettings, settings} from '../../utils/Settings';
import * as settings from '../../utils/Settings';
exports.expressCreateServer = (hookName:string, {app}:any) => { exports.expressCreateServer = (hookName:string, {app}:any) => {
app.get('/admin/settings', (req:any, res:any) => { app.get('/admin/settings', (req:any, res:any) => {
@ -26,12 +25,12 @@ exports.socketio = (hookName:string, {io}:any) => {
socket.on('load', async (query:string):Promise<any> => { socket.on('load', async (query:string):Promise<any> => {
let data; let data;
try { try {
data = await fsp.readFile(settingsFilename, 'utf8'); data = await fsp.readFile(settings.settingsFilename, 'utf8');
} catch (err) { } catch (err) {
return console.log(err); return console.log(err);
} }
// if showSettingsInAdminPage is set to false, then return NOT_ALLOWED in the result // if showSettingsInAdminPage is set to false, then return NOT_ALLOWED in the result
if (!showSettingsInAdminPage) { if (!settings.showSettingsInAdminPage) {
socket.emit('settings', {results: 'NOT_ALLOWED'}); socket.emit('settings', {results: 'NOT_ALLOWED'});
} else { } else {
socket.emit('settings', {results: data}); socket.emit('settings', {results: data});
@ -39,7 +38,7 @@ exports.socketio = (hookName:string, {io}:any) => {
}); });
socket.on('saveSettings', async (newSettings:string) => { socket.on('saveSettings', async (newSettings:string) => {
await fsp.writeFile(settingsFilename, newSettings); await fsp.writeFile(settings.settingsFilename, newSettings);
socket.emit('saveprogress', 'saved'); socket.emit('saveprogress', 'saved');
}); });

View file

@ -2,7 +2,7 @@
const log4js = require('log4js'); const log4js = require('log4js');
const clientLogger = log4js.getLogger('client'); const clientLogger = log4js.getLogger('client');
const {Formidable} = require('formidable'); import {Formidable} from 'formidable';
const apiHandler = require('../../handler/APIHandler'); const apiHandler = require('../../handler/APIHandler');
const util = require('util'); const util = require('util');
@ -25,6 +25,7 @@ exports.expressPreSession = async (hookName:string, {app}:any) => {
// The Etherpad client side sends information about client side javscript errors // The Etherpad client side sends information about client side javscript errors
app.post('/jserror', (req:any, res:any, next:Function) => { app.post('/jserror', (req:any, res:any, next:Function) => {
(async () => { (async () => {
// @ts-ignore
const data = JSON.parse(await parseJserrorForm(req)); const data = JSON.parse(await parseJserrorForm(req));
clientLogger.warn(`${data.msg} --`, { clientLogger.warn(`${data.msg} --`, {
[util.inspect.custom]: (depth: number, options:any) => { [util.inspect.custom]: (depth: number, options:any) => {

View file

@ -3,7 +3,7 @@
import {ArgsExpressType} from "../../types/ArgsExpressType"; import {ArgsExpressType} from "../../types/ArgsExpressType";
const hasPadAccess = require('../../padaccess'); const hasPadAccess = require('../../padaccess');
import {exportAvailable, importExportRateLimiting} from '../../utils/Settings'; import {exportAvailable, settings} from '../../utils/Settings';
const exportHandler = require('../../handler/ExportHandler'); const exportHandler = require('../../handler/ExportHandler');
const importHandler = require('../../handler/ImportHandler'); const importHandler = require('../../handler/ImportHandler');
const padManager = require('../../db/PadManager'); const padManager = require('../../db/PadManager');
@ -14,7 +14,7 @@ const webaccess = require('./webaccess');
exports.expressCreateServer = (hookName:string, args:ArgsExpressType, cb:Function) => { exports.expressCreateServer = (hookName:string, args:ArgsExpressType, cb:Function) => {
const limiter = rateLimit({ const limiter = rateLimit({
...importExportRateLimiting, ...settings.importExportRateLimiting,
handler: (request:any) => { handler: (request:any) => {
if (request.rateLimit.current === request.rateLimit.limit + 1) { if (request.rateLimit.current === request.rateLimit.limit + 1) {
// when the rate limiter triggers, write a warning in the logs // when the rate limiter triggers, write a warning in the logs

View file

@ -24,7 +24,7 @@ const cloneDeep = require('lodash.clonedeep');
const createHTTPError = require('http-errors'); const createHTTPError = require('http-errors');
const apiHandler = require('../../handler/APIHandler'); const apiHandler = require('../../handler/APIHandler');
import {ssl} from '../../utils/Settings'; import {settings} from '../../utils/Settings';
const log4js = require('log4js'); const log4js = require('log4js');
const logger = log4js.getLogger('API'); const logger = log4js.getLogger('API');
@ -724,5 +724,5 @@ const getApiRootForVersion = (version:string, style:any = APIPathStyle.FLAT): st
const generateServerForApiVersion = (apiRoot:string, req:any): { const generateServerForApiVersion = (apiRoot:string, req:any): {
url:string url:string
} => ({ } => ({
url: `${ssl ? 'https' : 'http'}://${req.headers.host}${apiRoot}`, url: `${settings.ssl ? 'https' : 'http'}://${req.headers.host}${apiRoot}`,
}); });

View file

@ -6,7 +6,7 @@ const events = require('events');
const express = require('../express'); const express = require('../express');
const log4js = require('log4js'); const log4js = require('log4js');
const proxyaddr = require('proxy-addr'); const proxyaddr = require('proxy-addr');
import * as settings from '../../utils/Settings'; import {settings} from '../../utils/Settings';
import {Server} from 'socket.io' import {Server} from 'socket.io'
const socketIORouter = require('../../handler/SocketIORouter'); const socketIORouter = require('../../handler/SocketIORouter');
const hooks = require('../../../static/js/pluginfw/hooks'); const hooks = require('../../../static/js/pluginfw/hooks');

View file

@ -6,7 +6,7 @@ const fs = require('fs');
const fsp = fs.promises; const fsp = fs.promises;
const toolbar = require('../../utils/toolbar'); const toolbar = require('../../utils/toolbar');
const hooks = require('../../../static/js/pluginfw/hooks'); const hooks = require('../../../static/js/pluginfw/hooks');
import * as settings from '../../utils/Settings'; import {getEpVersion, root, settings} from '../../utils/Settings';
const util = require('util'); const util = require('util');
const webaccess = require('./webaccess'); const webaccess = require('./webaccess');
@ -17,7 +17,7 @@ exports.expressPreSession = async (hookName, {app}) => {
res.set('Content-Type', 'application/health+json'); res.set('Content-Type', 'application/health+json');
res.json({ res.json({
status: 'pass', status: 'pass',
releaseId: settings.getEpVersion(), releaseId: getEpVersion(),
}); });
}); });
@ -31,11 +31,11 @@ exports.expressPreSession = async (hookName, {app}) => {
app.get('/robots.txt', (req, res) => { app.get('/robots.txt', (req, res) => {
let filePath = let filePath =
path.join(settings.root, 'src', 'static', 'skins', settings.skinName, 'robots.txt'); path.join(root, 'src', 'static', 'skins', settings.skinName, 'robots.txt');
res.sendFile(filePath, (err) => { res.sendFile(filePath, (err) => {
// there is no custom robots.txt, send the default robots.txt which dissallows all // there is no custom robots.txt, send the default robots.txt which dissallows all
if (err) { if (err) {
filePath = path.join(settings.root, 'src', 'static', 'robots.txt'); filePath = path.join(root, 'src', 'static', 'robots.txt');
res.sendFile(filePath); res.sendFile(filePath);
} }
}); });
@ -54,9 +54,9 @@ exports.expressPreSession = async (hookName, {app}) => {
const fns = [ const fns = [
...(settings.favicon ? [path.resolve(settings.root, settings.favicon)] : []), ...(settings.favicon ? [path.resolve(root, settings.favicon)] : []),
path.join(settings.root, 'src', 'static', 'skins', settings.skinName, 'favicon.ico'), path.join(root, 'src', 'static', 'skins', settings.skinName, 'favicon.ico'),
path.join(settings.root, 'src', 'static', 'favicon.ico'), path.join(root, 'src', 'static', 'favicon.ico'),
]; ];
for (const fn of fns) { for (const fn of fns) {
try { try {

View file

@ -1,34 +1,37 @@
'use strict'; 'use strict';
const fs = require('fs').promises; const fs = require('fs').promises;
const minify = require('../../utils/Minify'); const minify = require('../../utils/Minify');
const path = require('path'); const path = require('path');
const plugins = require('../../../static/js/pluginfw/plugin_defs'); const plugins = require('../../../static/js/pluginfw/plugin_defs');
import * as settings from '../../utils/Settings'; import {root, settings} from '../../utils/Settings';
const CachingMiddleware = require('../../utils/caching_middleware'); const CachingMiddleware = require('../../utils/caching_middleware');
const Yajsml = require('etherpad-yajsml'); const Yajsml = require('etherpad-yajsml');
// Rewrite tar to include modules with no extensions and proper rooted paths. // Rewrite tar to include modules with no extensions and proper rooted paths.
const getTar = async () => { const getTar = async () => {
const prefixLocalLibraryPath = (path) => { const prefixLocalLibraryPath = (path: string) => {
if (path.charAt(0) === '$') { if (path.charAt(0) === '$') {
return path.slice(1); return path.slice(1);
} else { } else {
return `ep_etherpad-lite/static/js/${path}`; return `ep_etherpad-lite/static/js/${path}`;
} }
}; };
const tarJson = await fs.readFile(path.join(settings.root, 'src/node/utils/tar.json'), 'utf8'); const tarJson = await fs.readFile(path.join(root, 'src/node/utils/tar.json'), 'utf8');
const tar = {}; const tar = {};
for (const [key, relativeFiles] of Object.entries(JSON.parse(tarJson))) { for (const [key, relativeFiles] of Object.entries(JSON.parse(tarJson))) {
// @ts-ignore
const files = relativeFiles.map(prefixLocalLibraryPath); const files = relativeFiles.map(prefixLocalLibraryPath);
// @ts-ignore
tar[prefixLocalLibraryPath(key)] = files tar[prefixLocalLibraryPath(key)] = files
.concat(files.map((p) => p.replace(/\.js$/, ''))) .concat(files.map((p:string) => p.replace(/\.js$/, '')))
.concat(files.map((p) => `${p.replace(/\.js$/, '')}/index.js`)); .concat(files.map((p:string) => `${p.replace(/\.js$/, '')}/index.js`));
} }
return tar; return tar;
}; };
exports.expressPreSession = async (hookName, {app}) => { exports.expressPreSession = async (hookName: string, {app}:any) => {
// Cache both minified and static. // Cache both minified and static.
const assetCache = new CachingMiddleware(); const assetCache = new CachingMiddleware();
app.all(/\/javascripts\/(.*)/, assetCache.handle.bind(assetCache)); app.all(/\/javascripts\/(.*)/, assetCache.handle.bind(assetCache));
@ -58,11 +61,13 @@ exports.expressPreSession = async (hookName, {app}) => {
// serve plugin definitions // serve plugin definitions
// not very static, but served here so that client can do // not very static, but served here so that client can do
// require("pluginfw/static/js/plugin-definitions.js"); // require("pluginfw/static/js/plugin-definitions.js");
app.get('/pluginfw/plugin-definitions.json', (req, res, next) => { app.get('/pluginfw/plugin-definitions.json', (req:any, res:any, next:Function) => {
const clientParts = plugins.parts.filter((part) => part.client_hooks != null); const clientParts = plugins.parts.filter((part:any) => part.client_hooks != null);
const clientPlugins = {}; const clientPlugins = {};
for (const name of new Set(clientParts.map((part) => part.plugin))) { for (const name of new Set(clientParts.map((part:any) => part.plugin))) {
// @ts-ignore
clientPlugins[name] = {...plugins.plugins[name]}; clientPlugins[name] = {...plugins.plugins[name]};
// @ts-ignore
delete clientPlugins[name].package; delete clientPlugins[name].package;
} }
res.setHeader('Content-Type', 'application/json; charset=utf-8'); res.setHeader('Content-Type', 'application/json; charset=utf-8');

View file

@ -4,7 +4,7 @@ const path = require('path');
const fsp = require('fs').promises; const fsp = require('fs').promises;
const plugins = require('../../../static/js/pluginfw/plugin_defs'); const plugins = require('../../../static/js/pluginfw/plugin_defs');
const sanitizePathname = require('../../utils/sanitizePathname'); const sanitizePathname = require('../../utils/sanitizePathname');
import * as settings from '../../utils/Settings'; import {root, settings} from '../../utils/Settings';
// Returns all *.js files under specDir (recursively) as relative paths to specDir, using '/' // Returns all *.js files under specDir (recursively) as relative paths to specDir, using '/'
// instead of path.sep to separate pathname components. // instead of path.sep to separate pathname components.
@ -57,7 +57,7 @@ exports.expressPreSession = async (hookName, {app}) => {
})().catch((err) => next(err || new Error(err))); })().catch((err) => next(err || new Error(err)));
}); });
const rootTestFolder = path.join(settings.root, 'src/tests/frontend/'); const rootTestFolder = path.join(root, 'src/tests/frontend/');
app.get('/tests/frontend/index.html', (req, res) => { app.get('/tests/frontend/index.html', (req, res) => {
res.redirect(['./', ...req.url.split('?').slice(1)].join('?')); res.redirect(['./', ...req.url.split('?').slice(1)].join('?'));

View file

@ -3,7 +3,7 @@
const assert = require('assert').strict; const assert = require('assert').strict;
const log4js = require('log4js'); const log4js = require('log4js');
const httpLogger = log4js.getLogger('http'); const httpLogger = log4js.getLogger('http');
import * as settings from '../../utils/Settings'; import {settings} from '../../utils/Settings';
const hooks = require('../../../static/js/pluginfw/hooks'); const hooks = require('../../../static/js/pluginfw/hooks');
const readOnlyManager = require('../../db/ReadOnlyManager'); const readOnlyManager = require('../../db/ReadOnlyManager');

View file

@ -9,7 +9,7 @@ const path = require('path');
const _ = require('underscore'); const _ = require('underscore');
const pluginDefs = require('../../static/js/pluginfw/plugin_defs.js'); const pluginDefs = require('../../static/js/pluginfw/plugin_defs.js');
const existsSync = require('../utils/path_exists'); const existsSync = require('../utils/path_exists');
import {customLocaleStrings, maxAge, root} from '../utils/Settings'; import {settings, root} from '../utils/Settings';
// returns all existing messages merged together and grouped by langcode // returns all existing messages merged together and grouped by langcode
// {es: {"foo": "string"}, en:...} // {es: {"foo": "string"}, en:...}
@ -71,9 +71,9 @@ const getAllLocales = () => {
const wrongFormatErr = Error( const wrongFormatErr = Error(
'customLocaleStrings in wrong format. See documentation ' + 'customLocaleStrings in wrong format. See documentation ' +
'for Customization for Administrators, under Localization.'); 'for Customization for Administrators, under Localization.');
if (customLocaleStrings) { if (settings.customLocaleStrings) {
if (typeof customLocaleStrings !== 'object') throw wrongFormatErr; if (typeof settings.customLocaleStrings !== 'object') throw wrongFormatErr;
_.each(customLocaleStrings, (overrides:MapArrayType<string> , langcode:string) => { _.each(settings.customLocaleStrings, (overrides:MapArrayType<string> , langcode:string) => {
if (typeof overrides !== 'object') throw wrongFormatErr; if (typeof overrides !== 'object') throw wrongFormatErr;
_.each(overrides, (localeString:string|object, key:string) => { _.each(overrides, (localeString:string|object, key:string) => {
if (typeof localeString !== 'string') throw wrongFormatErr; if (typeof localeString !== 'string') throw wrongFormatErr;
@ -133,7 +133,7 @@ exports.expressPreSession = async (hookName:string, {app}:any) => {
// works with /locale/en and /locale/en.json requests // works with /locale/en and /locale/en.json requests
const locale = req.params.locale.split('.')[0]; const locale = req.params.locale.split('.')[0];
if (Object.prototype.hasOwnProperty.call(exports.availableLangs, locale)) { if (Object.prototype.hasOwnProperty.call(exports.availableLangs, locale)) {
res.setHeader('Cache-Control', `public, max-age=${maxAge}`); res.setHeader('Cache-Control', `public, max-age=${settings.maxAge}`);
res.setHeader('Content-Type', 'application/json; charset=utf-8'); res.setHeader('Content-Type', 'application/json; charset=utf-8');
res.send(`{"${locale}":${JSON.stringify(locales[locale])}}`); res.send(`{"${locale}":${JSON.stringify(locales[locale])}}`);
} else { } else {
@ -142,7 +142,7 @@ exports.expressPreSession = async (hookName:string, {app}:any) => {
}); });
app.get('/locales.json', (req: any, res:any) => { app.get('/locales.json', (req: any, res:any) => {
res.setHeader('Cache-Control', `public, max-age=${maxAge}`); res.setHeader('Cache-Control', `public, max-age=${settings.maxAge}`);
res.setHeader('Content-Type', 'application/json; charset=utf-8'); res.setHeader('Content-Type', 'application/json; charset=utf-8');
res.send(localeIndex); res.send(localeIndex);
}); });

View file

@ -28,11 +28,10 @@ import {PluginType} from "./types/Plugin";
import {ErrorCaused} from "./types/ErrorCaused"; import {ErrorCaused} from "./types/ErrorCaused";
import log4js from 'log4js'; import log4js from 'log4js';
import {dumpOnUncleanExit} from './utils/Settings'; import {settings} from './utils/Settings';
import * as settings from './utils/Settings';
let wtfnode: any; let wtfnode: any;
if (dumpOnUncleanExit) { if (settings.dumpOnUncleanExit) {
// wtfnode should be loaded after log4js.replaceConsole() so that it uses log4js for logging, and // wtfnode should be loaded after log4js.replaceConsole() so that it uses log4js for logging, and
// it should be above everything else so that it can hook in before resources are used. // it should be above everything else so that it can hook in before resources are used.
wtfnode = require('wtfnode'); wtfnode = require('wtfnode');
@ -266,7 +265,7 @@ exports.exit = async (err: ErrorCaused|string|null = null) => {
logger.error('Something that should have been cleaned up during the shutdown hook (such as ' + logger.error('Something that should have been cleaned up during the shutdown hook (such as ' +
'a timer, worker thread, or open connection) is preventing Node.js from exiting'); 'a timer, worker thread, or open connection) is preventing Node.js from exiting');
if (dumpOnUncleanExit) { if (settings.dumpOnUncleanExit) {
wtfnode.dump(); wtfnode.dump();
} else { } else {
logger.error('Enable `dumpOnUncleanExit` setting to get a dump of objects preventing a ' + logger.error('Enable `dumpOnUncleanExit` setting to get a dump of objects preventing a ' +

View file

@ -0,0 +1,113 @@
export type SettingsObj = {
settingsFilename: string;
credentialsFilename: string;
title: string;
favicon: string|null;
skinName: string|null;
skinVariants: string;
ip: string;
port: string|number,
suppressErrorsInPadText: boolean,
ssl:false|{
key: string;
cert: string;
ca: string[];
},
socketTransportProtocols: string[];
socketIo: {
maxHttpBufferSize: number;
},
dbType: string;
dbSettings: any,
defaultPadText: string,
padOptions:{
noColors: boolean;
showControls: boolean;
showChat: boolean;
showLineNumbers: boolean;
useMonospaceFont: boolean;
userName: string|null;
userColor: string|null;
rtl: boolean;
alwaysShowChat: boolean;
chatAndUsers: boolean;
lang: string|null;
},
padShortcutEnabled: {
altF9: boolean;
altC: boolean;
delete: boolean;
cmdShift2: boolean;
return: boolean;
esc: boolean;
cmdS: boolean;
tab: boolean;
cmdZ: boolean;
cmdY: boolean;
cmdB: boolean;
cmdI: boolean;
cmdU: boolean;
cmd5: boolean;
cmdShiftL: boolean;
cmdShiftN: boolean;
cmdShift1: boolean;
cmdShiftC: boolean;
cmdH: boolean;
ctrlHome: boolean;
pageUp: boolean;
pageDown: boolean;
},
toolbar: {
left: string[][];
right: string[][];
timeslider: string[][];
},
requireSession: boolean;
editOnly: boolean;
maxAge: number;
minify: boolean;
abiword: string|null;
soffice: string|null;
allowUnknownFileEnds: boolean;
loglevel: string;
disableIPlogging: boolean;
automaticReconnectionTimeout: number;
loadTest: boolean;
dumpOnUncleanExit: boolean;
indentationOnNewLine: boolean;
logconfig: any;
sessionKey:string|null|string[],
trustProxy: boolean;
cookie:{
keyRotationInterval: number;
sameSite: string;
sessionLifetime: number;
sessionRefreshInterval: number;
},
requireAuthentication: boolean;
requireAuthorization: boolean;
users: object,
showSettingsInAdminPage: boolean;
scrollWhenFocusLineIsOutOfViewport:{
percentage: {
editionAboveViewport: number;
editionBelowViewport: number;
},
duration: number;
percentageToScrollWhenUserPressesArrowUp: number,
scrollWhenCaretIsInTheLastLineOfViewport: boolean
},
exposeVersion: boolean;
customLocaleStrings: {},
importExportRateLimiting: {
windowMs: number;
max: number;
},
commitRateLimiting: {
duration: number;
points: number;
},
importMaxFileSize: number;
enableAdminUITests: boolean;
lowerCasePadIds: boolean;
}

View file

@ -24,14 +24,14 @@ import {AsyncQueueTask} from "../types/AsyncQueueTask";
const spawn = require('child_process').spawn; const spawn = require('child_process').spawn;
const async = require('async'); const async = require('async');
import {abiword} from './Settings'; import {settings} from './Settings';
const os = require('os'); const os = require('os');
// on windows we have to spawn a process for each convertion, // on windows we have to spawn a process for each convertion,
// cause the plugin abicommand doesn't exist on this platform // cause the plugin abicommand doesn't exist on this platform
if (os.type().indexOf('Windows') > -1) { if (os.type().indexOf('Windows') > -1) {
exports.convertFile = async (srcFile: string, destFile: string, type: string) => { exports.convertFile = async (srcFile: string, destFile: string, type: string) => {
const _abiword = spawn(abiword, [`--to=${destFile}`, srcFile]); const _abiword = spawn(settings.abiword, [`--to=${destFile}`, srcFile]);
let stdoutBuffer = ''; let stdoutBuffer = '';
_abiword.stdout.on('data', (data: string) => { stdoutBuffer += data.toString(); }); _abiword.stdout.on('data', (data: string) => { stdoutBuffer += data.toString(); });
_abiword.stderr.on('data', (data: string) => { stdoutBuffer += data.toString(); }); _abiword.stderr.on('data', (data: string) => { stdoutBuffer += data.toString(); });
@ -47,12 +47,12 @@ if (os.type().indexOf('Windows') > -1) {
}; };
// on unix operating systems, we can start abiword with abicommand and // on unix operating systems, we can start abiword with abicommand and
// communicate with it via stdin/stdout // communicate with it via stdin/stdout
// thats much faster, about factor 10 // that's much faster, about factor 10
} else { } else {
let _abiword: ChildProcess; let _abiword: ChildProcess;
let stdoutCallback: Function|null = null; let stdoutCallback: Function|null = null;
const spawnAbiword = () => { const spawnAbiword = () => {
_abiword = spawn(abiword, ['--plugin', 'AbiCommand']); _abiword = spawn(settings.abiword, ['--plugin', 'AbiCommand']);
let stdoutBuffer = ''; let stdoutBuffer = '';
let firstPrompt = true; let firstPrompt = true;
_abiword.stderr!.on('data', (data) => { stdoutBuffer += data.toString(); }); _abiword.stderr!.on('data', (data) => { stdoutBuffer += data.toString(); });

View file

@ -21,7 +21,7 @@
* limitations under the License. * limitations under the License.
*/ */
const settings = require('./Settings'); import {root, settings} from './Settings';
const fs = require('fs').promises; const fs = require('fs').promises;
const path = require('path'); const path = require('path');
const plugins = require('../../static/js/pluginfw/plugin_defs'); const plugins = require('../../static/js/pluginfw/plugin_defs');
@ -33,7 +33,7 @@ const sanitizePathname = require('./sanitizePathname');
const logger = log4js.getLogger('Minify'); const logger = log4js.getLogger('Minify');
const ROOT_DIR = path.join(settings.root, 'src/static/'); const ROOT_DIR = path.join(root, 'src/static/');
const threadsPool = new Threads.Pool(() => Threads.spawn(new Threads.Worker('./MinifyWorker')), 2); const threadsPool = new Threads.Pool(() => Threads.spawn(new Threads.Worker('./MinifyWorker')), 2);

View file

@ -35,6 +35,7 @@ import jsonminify from 'jsonminify';
import log4js from 'log4js'; import log4js from 'log4js';
import randomString from './randomstring'; import randomString from './randomstring';
import _ from 'underscore'; import _ from 'underscore';
import {SettingsObj} from "../types/SettingsObj";
const absolutePaths = require('./AbsolutePaths'); const absolutePaths = require('./AbsolutePaths');
const argv = require('./Cli').argv; const argv = require('./Cli').argv;
@ -50,16 +51,17 @@ const nonSettings = [
]; ];
// This is a function to make it easy to create a new instance. It is important to not reuse a // This is a function to make it easy to create a new instance. It is important to not reuse a
// config object after passing it to log4js.configure() because that method mutates the object. :( // config object after passing it to log4js.configure() because that method mutates the object. :(
const defaultLogConfig = (level: string) => ({appenders: {console: {type: 'console'}}, const defaultLogConfig = (level: string) => ({
appenders: {console: {type: 'console'}},
categories: { categories: {
default: {appenders: ['console'], level}, default: {appenders: ['console'], level},
}}); }
});
const defaultLogLevel = 'INFO'; const defaultLogLevel = 'INFO';
const initLogging = (config:any) => { const initLogging = (config: any) => {
// log4js.configure() modifies logconfig so check for equality first. // log4js.configure() modifies logconfig so check for equality first.
log4js.configure(config); log4js.configure(config);
log4js.getLogger('console'); log4js.getLogger('console');
@ -75,67 +77,55 @@ const initLogging = (config:any) => {
// with the user's chosen log level and logger config after the settings have been loaded. // with the user's chosen log level and logger config after the settings have been loaded.
initLogging(defaultLogConfig(defaultLogLevel)); initLogging(defaultLogConfig(defaultLogLevel));
/* Root path of the installation */
export const root = absolutePaths.findEtherpadRoot();
logger.info('All relative paths will be interpreted relative to the identified ' +
`Etherpad base dir: ${root}`);
export const settingsFilename = absolutePaths.makeAbsolute(argv.settings || 'settings.json');
export const credentialsFilename = absolutePaths.makeAbsolute(argv.credentials || 'credentials.json');
/** export const root = absolutePaths.findEtherpadRoot()
export const settings: SettingsObj = {
settingsFilename: absolutePaths.makeAbsolute(argv.settings || 'settings.json'),
credentialsFilename: absolutePaths.makeAbsolute(argv.credentials || 'credentials.json'),
/**
* The app title, visible e.g. in the browser window * The app title, visible e.g. in the browser window
*/ */
export const title = 'Etherpad'; title: 'Etherpad',
/**
/**
* Pathname of the favicon you want to use. If null, the skin's favicon is * Pathname of the favicon you want to use. If null, the skin's favicon is
* used if one is provided by the skin, otherwise the default Etherpad favicon * used if one is provided by the skin, otherwise the default Etherpad favicon
* is used. If this is a relative path it is interpreted as relative to the * is used. If this is a relative path it is interpreted as relative to the
* Etherpad root directory. * Etherpad root directory.
*/ */
export let favicon = null; favicon: null,
/* /*
* Skin name. * Skin name.
* *
* Initialized to null, so we can spot an old configuration file and invite the * Initialized to null, so we can spot an old configuration file and invite the
* user to update it before falling back to the default. * user to update it before falling back to the default.
*/ */
export let skinName:string|null = null; skinName: null,
export const skinVariants = 'super-light-toolbar super-light-editor light-background'; skinVariants: 'super-light-toolbar super-light-editor light-background',
/**
/**
* The IP ep-lite should listen to * The IP ep-lite should listen to
*/ */
export const ip:string = '0.0.0.0'; ip: '0.0.0.0',
/**
/**
* The Port ep-lite should listen to * The Port ep-lite should listen to
*/ */
export const port = process.env.PORT || 9001; port: process.env.PORT || 9001,
/**
/**
* Should we suppress Error messages from being in Pad Contents * Should we suppress Error messages from being in Pad Contents
*/ */
export const suppressErrorsInPadText = false; suppressErrorsInPadText: false,
/**
/**
* The SSL signed server key and the Certificate Authority's own certificate * The SSL signed server key and the Certificate Authority's own certificate
* default case: ep-lite does *not* use SSL. A signed server key is not required in this case. * default case: ep-lite does *not* use SSL. A signed server key is not required in this case.
*/ */
export const ssl:false|{ ssl: false,
key: string; /**
cert: string;
ca: string[];
} = false;
/**
* socket.io transport methods * socket.io transport methods
**/ **/
export const socketTransportProtocols = ['websocket', 'polling']; socketTransportProtocols: ['websocket', 'polling'],
socketIo: {
export const socketIo = {
/** /**
* Maximum permitted client message size (in bytes). * Maximum permitted client message size (in bytes).
* *
@ -145,33 +135,28 @@ export const socketIo = {
* (malicious clients can exhaust memory). * (malicious clients can exhaust memory).
*/ */
maxHttpBufferSize: 10000, maxHttpBufferSize: 10000,
}; },
/*
/*
* The Type of the database * The Type of the database
*/ */
export const dbType = 'dirty'; dbType: 'dirty',
/** /**
* This setting is passed with dbType to ueberDB to set up the database * This setting is passed with dbType to ueberDB to set up the database
*/ */
export const dbSettings = {filename: path.join(root, 'var/dirty.db')}; dbSettings: {
filename: path.join(root, 'var/dirty.db')
/** },
/**
* The default Text of a new pad * The default Text of a new pad
*/ */
export let defaultPadText = [ defaultPadText: [
'Welcome to Etherpad!', 'Welcome to Etherpad!',
'', '',
'This pad text is synchronized as you type, so that everyone viewing this page sees the same ' + 'This pad text is synchronized as you type, so that everyone viewing this page sees the same ' +
'text. This allows you to collaborate seamlessly on documents!', 'text. This allows you to collaborate seamlessly on documents!',
'', '',
'Etherpad on Github: https://github.com/ether/etherpad-lite', 'Etherpad on Github: https://github.com/ether/etherpad-lite',].join('\n'),
].join('\n'); padOptions: {
/**
* The default Pad Settings for a user (Can be overridden by changing the setting
*/
export const padOptions = {
noColors: false, noColors: false,
showControls: true, showControls: true,
showChat: true, showChat: true,
@ -182,13 +167,17 @@ export const padOptions = {
rtl: false, rtl: false,
alwaysShowChat: false, alwaysShowChat: false,
chatAndUsers: false, chatAndUsers: false,
/**
* The default Pad Settings for a user (Can be overridden by changing the setting
*/
lang: null, lang: null,
}; },
/**
/**
* Whether certain shortcut keys are enabled for a user in the pad * Whether certain shortcut keys are enabled for a user in the pad
*/ */
export const padShortcutEnabled = { padShortcutEnabled: {
altF9: true, altF9: true,
altC: true, altC: true,
delete: true, delete: true,
@ -211,12 +200,11 @@ export const padShortcutEnabled = {
ctrlHome: true, ctrlHome: true,
pageUp: true, pageUp: true,
pageDown: true, pageDown: true,
}; },
/**
/**
* The toolbar buttons and order. * The toolbar buttons and order.
*/ */
export const toolbar = { toolbar: {
left: [ left: [
['bold', 'italic', 'underline', 'strikethrough'], ['bold', 'italic', 'underline', 'strikethrough'],
['orderedlist', 'unorderedlist', 'indent', 'outdent'], ['orderedlist', 'unorderedlist', 'indent', 'outdent'],
@ -231,92 +219,72 @@ export const toolbar = {
timeslider: [ timeslider: [
['timeslider_export', 'timeslider_settings', 'timeslider_returnToPad'], ['timeslider_export', 'timeslider_settings', 'timeslider_returnToPad'],
], ],
}; },
/**
/**
* A flag that requires any user to have a valid session (via the api) before accessing a pad * A flag that requires any user to have a valid session (via the api) before accessing a pad
*/ */
export const requireSession = false; requireSession: false,
/**
/**
* A flag that prevents users from creating new pads * A flag that prevents users from creating new pads
*/ */
export const editOnly = false; editOnly: false,
/**
/**
* Max age that responses will have (affects caching layer). * Max age that responses will have (affects caching layer).
*/ */
export const maxAge = 1000 * 60 * 60 * 6; // 6 hours maxAge: 1000 * 60 * 60 * 6, // 6 hours
/**
/**
* A flag that shows if minification is enabled or not * A flag that shows if minification is enabled or not
*/ */
export const minify = true; minify: true,
/**
/**
* The path of the abiword executable * The path of the abiword executable
*/ */
export let abiword = null; abiword: null,
/**
/**
* The path of the libreoffice executable * The path of the libreoffice executable
*/ */
export let soffice = null; soffice: null,
/**
/**
* Should we support none natively supported file types on import? * Should we support none natively supported file types on import?
*/ */
export const allowUnknownFileEnds = true; allowUnknownFileEnds: true,
/**
/**
* The log level of log4js * The log level of log4js
*/ */
export const loglevel:string = defaultLogLevel; loglevel: defaultLogLevel,
/**
/**
* Disable IP logging * Disable IP logging
*/ */
export const disableIPlogging = false; disableIPlogging: false,
/**
/**
* Number of seconds to automatically reconnect pad * Number of seconds to automatically reconnect pad
*/ */
export const automaticReconnectionTimeout = 0; automaticReconnectionTimeout: 0,
/**
/**
* Disable Load Testing * Disable Load Testing
*/ */
export const loadTest = false; loadTest: false,
/**
/**
* Disable dump of objects preventing a clean exit * Disable dump of objects preventing a clean exit
*/ */
export const dumpOnUncleanExit = false; dumpOnUncleanExit: false,
/**
/**
* Enable indentation on new lines * Enable indentation on new lines
*/ */
export const indentationOnNewLine = true; indentationOnNewLine: true,
logconfig: null,
/* /*
* log4js appender configuration
*/
export let logconfig:any = null;
/*
* Deprecated cookie signing key. * Deprecated cookie signing key.
*/ */
export let sessionKey:string|null|string[] = null; sessionKey: null,
/*
/*
* Trust Proxy, whether trust the x-forwarded-for header. * Trust Proxy, whether trust the x-forwarded-for header.
*/ */
export const trustProxy = false; trustProxy: false,
/*
/*
* Settings controlling the session cookie issued by Etherpad. * Settings controlling the session cookie issued by Etherpad.
*/ */
export const cookie = { cookie: {
keyRotationInterval: 1 * 24 * 60 * 60 * 1000, keyRotationInterval: 1 * 24 * 60 * 60 * 1000,
/* /*
* Value of the SameSite cookie property. "Lax" is recommended unless * Value of the SameSite cookie property. "Lax" is recommended unless
@ -332,27 +300,25 @@ export const cookie = {
sameSite: 'Lax', sameSite: 'Lax',
sessionLifetime: 10 * 24 * 60 * 60 * 1000, sessionLifetime: 10 * 24 * 60 * 60 * 1000,
sessionRefreshInterval: 1 * 24 * 60 * 60 * 1000, sessionRefreshInterval: 1 * 24 * 60 * 60 * 1000,
}; },
/* /*
* This setting is used if you need authentication and/or * This setting is used if you need authentication and/or
* authorization. Note: /admin always requires authentication, and * authorization. Note: /admin always requires authentication, and
* either authorization by a module, or a user with is_admin set * either authorization by a module, or a user with is_admin set
*/ */
export let requireAuthentication = false; requireAuthentication: false,
export let requireAuthorization = false; requireAuthorization: false,
export const users = {}; users: {},
/*
/*
* Show settings in admin page, by default it is true * Show settings in admin page, by default it is true
*/ */
export const showSettingsInAdminPage = true; showSettingsInAdminPage: true,
/*
/*
* By default, when caret is moved out of viewport, it scrolls the minimum * By default, when caret is moved out of viewport, it scrolls the minimum
* height needed to make this line visible. * height needed to make this line visible.
*/ */
export const scrollWhenFocusLineIsOutOfViewport = { scrollWhenFocusLineIsOutOfViewport: {
/* /*
* Percentage of viewport height to be additionally scrolled. * Percentage of viewport height to be additionally scrolled.
*/ */
@ -378,21 +344,18 @@ export const scrollWhenFocusLineIsOutOfViewport = {
* line of the viewport * line of the viewport
*/ */
scrollWhenCaretIsInTheLastLineOfViewport: false, scrollWhenCaretIsInTheLastLineOfViewport: false,
}; },
/*
/*
* Expose Etherpad version in the web interface and in the Server http header. * Expose Etherpad version in the web interface and in the Server http header.
* *
* Do not enable on production machines. * Do not enable on production machines.
*/ */
export const exposeVersion = false; exposeVersion: false,
/*
/*
* Override any strings found in locale directories * Override any strings found in locale directories
*/ */
export const customLocaleStrings = {}; customLocaleStrings: {},
/*
/*
* From Etherpad 1.8.3 onwards, import and export of pads is always rate * From Etherpad 1.8.3 onwards, import and export of pads is always rate
* limited. * limited.
* *
@ -401,15 +364,15 @@ export const customLocaleStrings = {};
* *
* See https://github.com/nfriedly/express-rate-limit for more options * See https://github.com/nfriedly/express-rate-limit for more options
*/ */
export const importExportRateLimiting = {
importExportRateLimiting: {
// duration of the rate limit window (milliseconds) // duration of the rate limit window (milliseconds)
windowMs: 90000, windowMs: 90000,
// maximum number of requests per IP to allow during the rate limit window // maximum number of requests per IP to allow during the rate limit window
max: 10, max: 10,
}; },
/*
/*
* From Etherpad 1.9.0 onwards, commits from individual users are rate limited * From Etherpad 1.9.0 onwards, commits from individual users are rate limited
* *
* The default is to allow at most 10 changes per IP in a 1 second window. * The default is to allow at most 10 changes per IP in a 1 second window.
@ -417,36 +380,40 @@ export const importExportRateLimiting = {
* *
* See https://github.com/animir/node-rate-limiter-flexible/wiki/Overall-example#websocket-single-connection-prevent-flooding for more options * See https://github.com/animir/node-rate-limiter-flexible/wiki/Overall-example#websocket-single-connection-prevent-flooding for more options
*/ */
export const commitRateLimiting = { commitRateLimiting: {
// duration of the rate limit window (seconds) // duration of the rate limit window (seconds)
duration: 1, duration: 1,
// maximum number of chanes per IP to allow during the rate limit window // maximum number of chanes per IP to allow during the rate limit window
points: 10, points: 10,
}; },
/*
/*
* From Etherpad 1.8.3 onwards, the maximum allowed size for a single imported * From Etherpad 1.8.3 onwards, the maximum allowed size for a single imported
* file is always bounded. * file is always bounded.
* *
* File size is specified in bytes. Default is 50 MB. * File size is specified in bytes. Default is 50 MB.
*/ */
export const importMaxFileSize = 50 * 1024 * 1024; importMaxFileSize: 50 * 1024 * 1024,
/*
/*
* Disable Admin UI tests * Disable Admin UI tests
*/ */
export const enableAdminUITests = false; enableAdminUITests: false,
/*
/*
* Enable auto conversion of pad Ids to lowercase. * Enable auto conversion of pad Ids to lowercase.
* e.g. /p/EtHeRpAd to /p/etherpad * e.g. /p/EtHeRpAd to /p/etherpad
*/ */
export const lowerCasePadIds = false; lowerCasePadIds: false,
}
/* Root path of the installation */
logger.info('All relative paths will be interpreted relative to the identified ' +
`Etherpad base dir: ${root}`);
// checks if abiword is avaiable // checks if abiword is avaiable
export const abiwordAvailable = () => { export const abiwordAvailable = () => {
if (abiword != null) { if (settings.abiword != null) {
return os.type().indexOf('Windows') !== -1 ? 'withoutPDF' : 'yes'; return os.type().indexOf('Windows') !== -1 ? 'withoutPDF' : 'yes';
} else { } else {
return 'no'; return 'no';
@ -454,7 +421,7 @@ export const abiwordAvailable = () => {
}; };
export const sofficeAvailable = () => { export const sofficeAvailable = () => {
if (soffice != null) { if (settings.soffice != null) {
return os.type().indexOf('Windows') !== -1 ? 'withoutPDF' : 'yes'; return os.type().indexOf('Windows') !== -1 ? 'withoutPDF' : 'yes';
} else { } else {
return 'no'; return 'no';
@ -510,7 +477,7 @@ export const getEpVersion = () => require('../../package.json').version;
* This code refactors a previous version that copied & pasted the same code for * This code refactors a previous version that copied & pasted the same code for
* both "settings.json" and "credentials.json". * both "settings.json" and "credentials.json".
*/ */
const storeSettings = (settingsObj:MapArrayType<any>) => { const storeSettings = (settingsObj: MapArrayType<any>) => {
for (const i of Object.keys(settingsObj || {})) { for (const i of Object.keys(settingsObj || {})) {
if (nonSettings.includes(i)) { if (nonSettings.includes(i)) {
logger.warn(`Ignoring setting: '${i}'`); logger.warn(`Ignoring setting: '${i}'`);
@ -522,15 +489,16 @@ const storeSettings = (settingsObj:MapArrayType<any>) => {
logger.warn(`Settings should start with a lowercase character: '${i}'`); logger.warn(`Settings should start with a lowercase character: '${i}'`);
} }
console.log(globalThis)
// we know this setting, so we overwrite it, // we know this setting, so we overwrite it,
// or it's a settings hash, specific to a plugin // or it's a settings hash, specific to a plugin
if (exports[i] !== undefined || i.indexOf('ep_') === 0) { // @ts-ignore
if (settings[i] !== undefined || i.indexOf('ep_') === 0) {
if (_.isObject(settingsObj[i]) && !Array.isArray(settingsObj[i])) { if (_.isObject(settingsObj[i]) && !Array.isArray(settingsObj[i])) {
exports[i] = _.defaults(settingsObj[i], exports[i]); // @ts-ignore
settings[i] = _.defaults(settingsObj[i], settings[i]);
} else { } else {
exports[i] = settingsObj[i]; // @ts-ignore
settings[i] = settingsObj[i];
} }
} else { } else {
// this setting is unknown, output a warning and throw it away // this setting is unknown, output a warning and throw it away
@ -563,11 +531,16 @@ const coerceValue = (stringValue: string) => {
} }
switch (stringValue) { switch (stringValue) {
case 'true': return true; case 'true':
case 'false': return false; return true;
case 'undefined': return undefined; case 'false':
case 'null': return null; return false;
default: return stringValue; case 'undefined':
return undefined;
case 'null':
return null;
default:
return stringValue;
} }
}; };
@ -693,7 +666,7 @@ const lookupEnvironmentVariables = (obj: object) => {
* *
* The isSettings variable only controls the error logging. * The isSettings variable only controls the error logging.
*/ */
const parseSettings = (settingsFilename: string, isSettings: boolean) => { export const parseSettings = (settingsFilename: string, isSettings: boolean) => {
let settingsStr = ''; let settingsStr = '';
let settingsType, notFoundMessage, notFoundFunction; let settingsType, notFoundMessage, notFoundFunction;
@ -726,7 +699,7 @@ const parseSettings = (settingsFilename: string, isSettings: boolean) => {
logger.info(`${settingsType} loaded from: ${settingsFilename}`); logger.info(`${settingsType} loaded from: ${settingsFilename}`);
return lookupEnvironmentVariables(settings); return lookupEnvironmentVariables(settings);
} catch (e:any) { } catch (e: any) {
logger.error(`There was an error processing your ${settingsType} ` + logger.error(`There was an error processing your ${settingsType} ` +
`file from ${settingsFilename}: ${e.message}`); `file from ${settingsFilename}: ${e.message}`);
@ -737,97 +710,98 @@ const parseSettings = (settingsFilename: string, isSettings: boolean) => {
export let randomVersionString: string | undefined export let randomVersionString: string | undefined
export const reloadSettings = () => { export const reloadSettings = () => {
const settings = parseSettings(settingsFilename, true); const settingsParsed = parseSettings(settings.settingsFilename, true);
const credentials = parseSettings(credentialsFilename, false); const credentials = parseSettings(settings.credentialsFilename, false);
storeSettings(settings); storeSettings(settingsParsed);
storeSettings(credentials); storeSettings(credentials);
// Init logging config // Init logging config
logconfig = defaultLogConfig(loglevel ? loglevel : defaultLogLevel); settings.logconfig = defaultLogConfig(settings.loglevel ? settings.loglevel : defaultLogLevel);
initLogging(logconfig); initLogging(settings.logconfig);
if (!skinName) { if (!settings.skinName) {
logger.warn('No "skinName" parameter found. Please check out settings.json.template and ' + logger.warn('No "skinName" parameter found. Please check out settings.json.template and ' +
'update your settings.json. Falling back to the default "colibris".'); 'update your settings.json. Falling back to the default "colibris".');
skinName = 'colibris'; settings.skinName = 'colibris';
} }
// checks if skinName has an acceptable value, otherwise falls back to "colibris" // checks if skinName has an acceptable value, otherwise falls back to "colibris"
if (skinName) { if (settings.skinName) {
const skinBasePath = path.join(root, 'src', 'static', 'skins'); const skinBasePath = path.join(root, 'src', 'static', 'skins');
const countPieces = skinName.split(path.sep).length; const countPieces = settings.skinName.split(path.sep).length;
if (countPieces !== 1) { if (countPieces !== 1) {
logger.error(`skinName must be the name of a directory under "${skinBasePath}". This is ` + logger.error(`skinName must be the name of a directory under "${skinBasePath}". This is ` +
`not valid: "${skinName}". Falling back to the default "colibris".`); `not valid: "${settings.skinName}". Falling back to the default "colibris".`);
skinName = 'colibris'; settings.skinName = 'colibris';
} }
// informative variable, just for the log messages // informative variable, just for the log messages
let skinPath = path.join(skinBasePath, skinName); let skinPath = path.join(skinBasePath, settings.skinName);
// what if someone sets skinName == ".." or "."? We catch him! // what if someone sets skinName == ".." or "."? We catch him!
if (absolutePaths.isSubdir(skinBasePath, skinPath) === false) { if (absolutePaths.isSubdir(skinBasePath, skinPath) === false) {
logger.error(`Skin path ${skinPath} must be a subdirectory of ${skinBasePath}. ` + logger.error(`Skin path ${skinPath} must be a subdirectory of ${skinBasePath}. ` +
'Falling back to the default "colibris".'); 'Falling back to the default "colibris".');
skinName = 'colibris'; settings.skinName = 'colibris';
skinPath = path.join(skinBasePath, skinName); skinPath = path.join(skinBasePath, settings.skinName);
} }
if (!fs.existsSync(skinPath)) { if (!fs.existsSync(skinPath)) {
logger.error(`Skin path ${skinPath} does not exist. Falling back to the default "colibris".`); logger.error(`Skin path ${skinPath} does not exist. Falling back to the default "colibris".`);
skinName = 'colibris'; settings.skinName = 'colibris';
skinPath = path.join(skinBasePath, skinName); skinPath = path.join(skinBasePath, settings.skinName);
} }
logger.info(`Using skin "${skinName}" in dir: ${skinPath}`); logger.info(`Using skin "${settings.skinName}" in dir: ${skinPath}`);
} }
if (abiword) { if (settings.abiword) {
// Check abiword actually exists // Check abiword actually exists
if (abiword != null) { if (settings.abiword != null) {
fs.exists(abiword, (exists) => { fs.exists(settings.abiword, (exists) => {
if (!exists) { if (!exists) {
const abiwordError = 'Abiword does not exist at this path, check your settings file.'; const abiwordError = 'Abiword does not exist at this path, check your settings file.';
if (!suppressErrorsInPadText) { if (!settings.suppressErrorsInPadText) {
defaultPadText += `\nError: ${abiwordError}${suppressDisableMsg}`; settings.defaultPadText += `\nError: ${abiwordError}${suppressDisableMsg}`;
} }
logger.error(`${abiwordError} File location: ${abiword}`); logger.error(`${abiwordError} File location: ${settings.abiword}`);
abiword = null; settings.abiword = null;
} }
}); });
} }
} }
if (soffice) { if (settings.soffice) {
fs.exists(soffice, (exists) => { fs.exists(settings.soffice, (exists) => {
if (!exists) { if (!exists) {
const sofficeError = const sofficeError =
'soffice (libreoffice) does not exist at this path, check your settings file.'; 'soffice (libreoffice) does not exist at this path, check your settings file.';
if (!suppressErrorsInPadText) { if (!settings.suppressErrorsInPadText) {
defaultPadText += `\nError: ${sofficeError}${suppressDisableMsg}`; settings.defaultPadText += `\nError: ${sofficeError}${suppressDisableMsg}`;
} }
logger.error(`${sofficeError} File location: ${soffice}`); logger.error(`${sofficeError} File location: ${settings.soffice}`);
soffice = null; settings.soffice = null;
} }
}); });
} }
const sessionkeyFilename = absolutePaths.makeAbsolute(argv.sessionkey || './SESSIONKEY.txt'); const sessionkeyFilename = absolutePaths.makeAbsolute(argv.sessionkey || './SESSIONKEY.txt');
if (!sessionKey) { if (!settings.sessionKey) {
try { try {
sessionKey = fs.readFileSync(sessionkeyFilename, 'utf8'); settings.sessionKey = fs.readFileSync(sessionkeyFilename, 'utf8');
logger.info(`Session key loaded from: ${sessionkeyFilename}`); logger.info(`Session key loaded from: ${sessionkeyFilename}`);
} catch (err) { /* ignored */ } } catch (err) { /* ignored */
const keyRotationEnabled = cookie.keyRotationInterval && cookie.sessionLifetime; }
if (!sessionKey && !keyRotationEnabled) { const keyRotationEnabled = settings.cookie.keyRotationInterval && settings.cookie.sessionLifetime;
if (!settings.sessionKey && !keyRotationEnabled) {
logger.info( logger.info(
`Session key file "${sessionkeyFilename}" not found. Creating with random contents.`); `Session key file "${sessionkeyFilename}" not found. Creating with random contents.`);
sessionKey = randomString(32); settings.sessionKey = randomString(32);
fs.writeFileSync(sessionkeyFilename, sessionKey, 'utf8'); fs.writeFileSync(sessionkeyFilename, settings.sessionKey, 'utf8');
} }
} else { } else {
logger.warn('Declaring the sessionKey in the settings.json is deprecated. ' + logger.warn('Declaring the sessionKey in the settings.json is deprecated. ' +
@ -835,22 +809,22 @@ export const reloadSettings = () => {
'If you are seeing this error after restarting using the Admin User ' + 'If you are seeing this error after restarting using the Admin User ' +
'Interface then you can ignore this message.'); 'Interface then you can ignore this message.');
} }
if (sessionKey) { if (settings.sessionKey) {
logger.warn(`The sessionKey setting and ${sessionkeyFilename} file are deprecated; ` + logger.warn(`The sessionKey setting and ${sessionkeyFilename} file are deprecated; ` +
'use automatic key rotation instead (see the cookie.keyRotationInterval setting).'); 'use automatic key rotation instead (see the cookie.keyRotationInterval setting).');
} }
if (dbType === 'dirty') { if (settings.dbType === 'dirty') {
const dirtyWarning = 'DirtyDB is used. This is not recommended for production.'; const dirtyWarning = 'DirtyDB is used. This is not recommended for production.';
if (!suppressErrorsInPadText) { if (!settings.suppressErrorsInPadText) {
defaultPadText += `\nWarning: ${dirtyWarning}${suppressDisableMsg}`; settings.defaultPadText += `\nWarning: ${dirtyWarning}${suppressDisableMsg}`;
} }
dbSettings.filename = absolutePaths.makeAbsolute(dbSettings.filename); settings.dbSettings.filename = absolutePaths.makeAbsolute(settings.dbSettings.filename);
logger.warn(`${dirtyWarning} File location: ${dbSettings.filename}`); logger.warn(`${dirtyWarning} File location: ${settings.dbSettings.filename}`);
} }
if (ip === '') { if (settings.ip === '') {
// using Unix socket for connectivity // using Unix socket for connectivity
logger.warn('The settings file contains an empty string ("") for the "ip" parameter. The ' + logger.warn('The settings file contains an empty string ("") for the "ip" parameter. The ' +
'"port" parameter will be interpreted as the path to a Unix socket to bind at.'); '"port" parameter will be interpreted as the path to a Unix socket to bind at.');

View file

@ -1,9 +1,9 @@
'use strict'; 'use strict';
const semver = require('semver'); const semver = require('semver');
const settings = require('./Settings'); import {getEpVersion, settings} from './Settings';
const axios = require('axios'); const axios = require('axios');
const headers = { const headers = {
'User-Agent': 'Etherpad/' + settings.getEpVersion(), 'User-Agent': 'Etherpad/' + getEpVersion(),
} }
type Infos = { type Infos = {
@ -45,7 +45,7 @@ exports.getLatestVersion = () => {
exports.needsUpdate = async (cb: Function) => { exports.needsUpdate = async (cb: Function) => {
await loadEtherpadInformations() await loadEtherpadInformations()
.then((info:Infos) => { .then((info:Infos) => {
if (semver.gt(info.latestVersion, settings.getEpVersion())) { if (semver.gt(info.latestVersion, getEpVersion())) {
if (cb) return cb(true); if (cb) return cb(true);
} }
}).catch((err: Error) => { }).catch((err: Error) => {

View file

@ -21,7 +21,7 @@ const fs = require('fs');
const fsp = fs.promises; const fsp = fs.promises;
const path = require('path'); const path = require('path');
const zlib = require('zlib'); const zlib = require('zlib');
const settings = require('./Settings'); import {root} from './Settings';
const existsSync = require('./path_exists'); const existsSync = require('./path_exists');
const util = require('util'); const util = require('util');
@ -40,7 +40,7 @@ const util = require('util');
const _crypto = require('crypto'); const _crypto = require('crypto');
let CACHE_DIR = path.join(settings.root, 'var/'); let CACHE_DIR = path.join(root, 'var/');
CACHE_DIR = existsSync(CACHE_DIR) ? CACHE_DIR : undefined; CACHE_DIR = existsSync(CACHE_DIR) ? CACHE_DIR : undefined;
type Headers = { type Headers = {

View file

@ -5,11 +5,11 @@ import {ChildProcess} from "node:child_process";
import {PromiseWithStd} from "../types/PromiseWithStd"; import {PromiseWithStd} from "../types/PromiseWithStd";
import {Readable} from "node:stream"; import {Readable} from "node:stream";
import {root, settings} from "./Settings";
const spawn = require('cross-spawn'); const spawn = require('cross-spawn');
const log4js = require('log4js'); const log4js = require('log4js');
const path = require('path'); const path = require('path');
const settings = require('./Settings');
const logger = log4js.getLogger('runCmd'); const logger = log4js.getLogger('runCmd');
const logLines = (readable: undefined | Readable | null, logLineFn: (arg0: (string | undefined)) => void) => { const logLines = (readable: undefined | Readable | null, logLineFn: (arg0: (string | undefined)) => void) => {
@ -77,7 +77,7 @@ const logLines = (readable: undefined | Readable | null, logLineFn: (arg0: (stri
module.exports = exports = (args: string[], opts:RunCMDOptions = {}) => { module.exports = exports = (args: string[], opts:RunCMDOptions = {}) => {
logger.debug(`Executing command: ${args.join(' ')}`); logger.debug(`Executing command: ${args.join(' ')}`);
opts = {cwd: settings.root, ...opts}; opts = {cwd: root, ...opts};
logger.debug(`cwd: ${opts.cwd}`); logger.debug(`cwd: ${opts.cwd}`);
// Log stdout and stderr by default. // Log stdout and stderr by default.
@ -112,8 +112,8 @@ module.exports = exports = (args: string[], opts:RunCMDOptions = {}) => {
opts.env = { opts.env = {
...env, // Copy env to avoid modifying process.env or the caller's supplied env. ...env, // Copy env to avoid modifying process.env or the caller's supplied env.
[pathVarName]: [ [pathVarName]: [
path.join(settings.root, 'src', 'node_modules', '.bin'), path.join(root, 'src', 'node_modules', '.bin'),
path.join(settings.root, 'node_modules', '.bin'), path.join(root, 'node_modules', '.bin'),
...(PATH ? PATH.split(path.delimiter) : []), ...(PATH ? PATH.split(path.delimiter) : []),
].join(path.delimiter), ].join(path.delimiter),
}; };

View file

@ -81,6 +81,7 @@
"devDependencies": { "devDependencies": {
"@types/async": "^3.2.24", "@types/async": "^3.2.24",
"@types/express": "^4.17.21", "@types/express": "^4.17.21",
"@types/formidable": "^3.4.5",
"@types/jsonminify": "^0.4.3", "@types/jsonminify": "^0.4.3",
"@types/node": "^20.11.19", "@types/node": "^20.11.19",
"@types/underscore": "^1.11.15", "@types/underscore": "^1.11.15",

View file

@ -4,7 +4,7 @@ const log4js = require('log4js');
const plugins = require('./plugins'); const plugins = require('./plugins');
const hooks = require('./hooks'); const hooks = require('./hooks');
const runCmd = require('../../../node/utils/run_cmd'); const runCmd = require('../../../node/utils/run_cmd');
const settings = require('../../../node/utils/Settings'); import {getEpVersion, reloadSettings, root, settings} from '../../../node/utils/Settings';
const axios = require('axios'); const axios = require('axios');
const {PluginManager} = require('live-plugin-manager-pnpm'); const {PluginManager} = require('live-plugin-manager-pnpm');
const {promises: fs} = require('fs'); const {promises: fs} = require('fs');
@ -14,18 +14,18 @@ const logger = log4js.getLogger('plugins');
exports.manager = new PluginManager(); exports.manager = new PluginManager();
const installedPluginsPath = path.join(settings.root, 'var/installed_plugins.json'); const installedPluginsPath = path.join(root, 'var/installed_plugins.json');
const onAllTasksFinished = async () => { const onAllTasksFinished = async () => {
await plugins.update(); await plugins.update();
await persistInstalledPlugins(); await persistInstalledPlugins();
settings.reloadSettings(); reloadSettings();
await hooks.aCallAll('loadSettings', {settings}); await hooks.aCallAll('loadSettings', {settings});
await hooks.aCallAll('restartServer'); await hooks.aCallAll('restartServer');
}; };
const headers = { const headers = {
'User-Agent': `Etherpad/${settings.getEpVersion()}`, 'User-Agent': `Etherpad/${getEpVersion()}`,
}; };
let tasks = 0; let tasks = 0;

View file

@ -9,7 +9,7 @@ const {padutils} = require('../../static/js/pad_utils');
const process = require('process'); const process = require('process');
const server = require('../../node/server'); const server = require('../../node/server');
const setCookieParser = require('set-cookie-parser'); const setCookieParser = require('set-cookie-parser');
const settings = require('../../node/utils/Settings'); import {settings} from '../../node/utils/Settings';
const supertest = require('supertest'); const supertest = require('supertest');
const webaccess = require('../../node/hooks/express/webaccess'); const webaccess = require('../../node/hooks/express/webaccess');

View file

@ -6,7 +6,7 @@ const authorManager = require('../../../node/db/AuthorManager');
const common = require('../common'); const common = require('../common');
const padManager = require('../../../node/db/PadManager'); const padManager = require('../../../node/db/PadManager');
const plugins = require('../../../static/js/pluginfw/plugin_defs'); const plugins = require('../../../static/js/pluginfw/plugin_defs');
import * as settings from '../../../node/utils/Settings'; import {settings} from '../../../node/utils/Settings';
describe(__filename, function () { describe(__filename, function () {
const backups = {}; const backups = {};

View file

@ -7,7 +7,7 @@
const assert = require('assert').strict; const assert = require('assert').strict;
const common = require('../../common'); const common = require('../../common');
const fs = require('fs'); const fs = require('fs');
import * as settings from '../../../../node/utils/Settings'; import {settings} from '../../../../node/utils/Settings';
const superagent = require('superagent'); const superagent = require('superagent');
const padManager = require('../../../../node/db/PadManager'); const padManager = require('../../../../node/db/PadManager');
const plugins = require('../../../../static/js/pluginfw/plugin_defs'); const plugins = require('../../../../static/js/pluginfw/plugin_defs');

View file

@ -9,7 +9,7 @@
const common = require('../common'); const common = require('../common');
const assert = require('../assert-legacy').strict; const assert = require('../assert-legacy').strict;
const queryString = require('querystring'); const queryString = require('querystring');
import * as settings from '../../../node/utils/Settings'; import {settings} from '../../../node/utils/Settings';
let agent; let agent;

View file

@ -2,7 +2,7 @@
const common = require('../common'); const common = require('../common');
const padManager = require('../../../node/db/PadManager'); const padManager = require('../../../node/db/PadManager');
import * as settings from '../../../node/utils/Settings'; import {settings} from '../../../node/utils/Settings';
describe(__filename, function () { describe(__filename, function () {
let agent; let agent;

View file

@ -5,7 +5,7 @@ const common = require('../common');
const fs = require('fs'); const fs = require('fs');
const fsp = fs.promises; const fsp = fs.promises;
const path = require('path'); const path = require('path');
import * as settings from '../../../node/utils/Settings' import {settings} from '../../../node/utils/Settings'
const superagent = require('superagent'); const superagent = require('superagent');
describe(__filename, function () { describe(__filename, function () {

View file

@ -3,7 +3,7 @@
const assert = require('assert').strict; const assert = require('assert').strict;
const common = require('../common'); const common = require('../common');
const padManager = require('../../../node/db/PadManager'); const padManager = require('../../../node/db/PadManager');
const settings = require('../../../node/utils/Settings'); import {settings} from '../../../node/utils/Settings';
describe(__filename, function () { describe(__filename, function () {
let agent; let agent;

View file

@ -1,7 +1,7 @@
'use strict'; 'use strict';
const assert = require('assert').strict; const assert = require('assert').strict;
const {parseSettings} = require('../../../node/utils/Settings').exportedForTestingOnly; import {parseSettings} from '../../../node/utils/Settings';
const path = require('path'); const path = require('path');
const process = require('process'); const process = require('process');

View file

@ -5,7 +5,7 @@ const common = require('../common');
const padManager = require('../../../node/db/PadManager'); const padManager = require('../../../node/db/PadManager');
const plugins = require('../../../static/js/pluginfw/plugin_defs'); const plugins = require('../../../static/js/pluginfw/plugin_defs');
const readOnlyManager = require('../../../node/db/ReadOnlyManager'); const readOnlyManager = require('../../../node/db/ReadOnlyManager');
const settings = require('../../../node/utils/Settings'); import {settings} from '../../../node/utils/Settings';
const socketIoRouter = require('../../../node/handler/SocketIORouter'); const socketIoRouter = require('../../../node/handler/SocketIORouter');
describe(__filename, function () { describe(__filename, function () {