diff --git a/src/node/hooks/express.js b/src/node/hooks/express.ts similarity index 93% rename from src/node/hooks/express.js rename to src/node/hooks/express.ts index 98be763c2..b1ca252ac 100644 --- a/src/node/hooks/express.js +++ b/src/node/hooks/express.ts @@ -1,7 +1,9 @@ 'use strict'; +import {Socket} from "node:net"; +import {MapArrayType} from "../types/MapType"; + const _ = require('underscore'); -const SecretRotator = require('../security/SecretRotator'); const cookieParser = require('cookie-parser'); const events = require('events'); const express = require('express'); @@ -15,11 +17,14 @@ const stats = require('../stats'); const util = require('util'); const webaccess = require('./express/webaccess'); -let secretRotator = null; +const SecretRotator = require('../security/SecretRotator') + +// TODO once we have ESM we can use the type of the class +let secretRotator: any|null = null; const logger = log4js.getLogger('http'); -let serverName; -let sessionStore; -const sockets = new Set(); +let serverName:string; +let sessionStore: { shutdown: () => void; } | null; +const sockets:Set = new Set(); const socketsEvents = new events.EventEmitter(); const startTime = stats.settableGauge('httpStartTime'); @@ -101,7 +106,7 @@ exports.restartServer = async () => { console.log(`SSL -- server key file: ${settings.ssl.key}`); console.log(`SSL -- Certificate Authority's certificate file: ${settings.ssl.cert}`); - const options = { + const options: MapArrayType = { key: fs.readFileSync(settings.ssl.key), cert: fs.readFileSync(settings.ssl.cert), }; @@ -121,7 +126,7 @@ exports.restartServer = async () => { exports.server = http.createServer(app); } - app.use((req, res, next) => { + app.use((req:any, res:any, next:Function) => { // res.header("X-Frame-Options", "deny"); // breaks embedded pads if (settings.ssl) { // we use SSL @@ -160,10 +165,10 @@ exports.restartServer = async () => { } // Measure response time - app.use((req, res, next) => { + app.use((req:any, res:any, next:Function) => { const stopWatch = stats.timer('httpRequests').start(); const sendFn = res.send.bind(res); - res.send = (...args) => { stopWatch.end(); sendFn(...args); }; + res.send = (...args: any) => { stopWatch.end(); sendFn(...args); }; next(); }); @@ -237,7 +242,7 @@ exports.restartServer = async () => { hooks.aCallAll('expressConfigure', {app}), hooks.aCallAll('expressCreateServer', {app, server: exports.server}), ]); - exports.server.on('connection', (socket) => { + exports.server.on('connection', (socket:Socket) => { sockets.add(socket); socketsEvents.emit('updated'); socket.on('close', () => { @@ -250,6 +255,6 @@ exports.restartServer = async () => { logger.info('HTTP server listening for connections'); }; -exports.shutdown = async (hookName, context) => { +exports.shutdown = async (hookName:string, context: any) => { await closeServer(); }; diff --git a/src/node/hooks/express/admin.js b/src/node/hooks/express/admin.ts similarity index 68% rename from src/node/hooks/express/admin.js rename to src/node/hooks/express/admin.ts index ed272efd8..90e491396 100644 --- a/src/node/hooks/express/admin.js +++ b/src/node/hooks/express/admin.ts @@ -1,6 +1,7 @@ 'use strict'; -const eejs = require('../../eejs'); +import {ArgsExpressType} from "../../types/ArgsExpressType"; +const eejs = require('../../eejs'); /** * Add the admin navigation link @@ -9,8 +10,8 @@ const eejs = require('../../eejs'); * @param {Function} cb the callback function * @return {*} */ -exports.expressCreateServer = (hookName, args, cb) => { - args.app.get('/admin', (req, res) => { +exports.expressCreateServer = (hookName:string, args: ArgsExpressType, cb:Function): any => { + args.app.get('/admin', (req:any, res:any) => { if ('/' !== req.path[req.path.length - 1]) return res.redirect('./admin/'); res.send(eejs.require('ep_etherpad-lite/templates/admin/index.html', {req})); }); diff --git a/src/node/hooks/express/adminplugins.js b/src/node/hooks/express/adminplugins.ts similarity index 76% rename from src/node/hooks/express/adminplugins.js rename to src/node/hooks/express/adminplugins.ts index 19908cf59..ad1795e17 100644 --- a/src/node/hooks/express/adminplugins.js +++ b/src/node/hooks/express/adminplugins.ts @@ -1,5 +1,11 @@ 'use strict'; +import {ArgsExpressType} from "../../types/ArgsExpressType"; +import {Socket} from "node:net"; +import {ErrorCaused} from "../../types/ErrorCaused"; +import {QueryType} from "../../types/QueryType"; +import {PluginType} from "../../types/Plugin"; + const eejs = require('../../eejs'); const settings = require('../../utils/Settings'); const installer = require('../../../static/js/pluginfw/installer'); @@ -8,8 +14,8 @@ const plugins = require('../../../static/js/pluginfw/plugins'); const semver = require('semver'); const UpdateCheck = require('../../utils/UpdateCheck'); -exports.expressCreateServer = (hookName, args, cb) => { - args.app.get('/admin/plugins', (req, res) => { +exports.expressCreateServer = (hookName:string, args: ArgsExpressType, cb:Function) => { + args.app.get('/admin/plugins', (req:any, res:any) => { res.send(eejs.require('ep_etherpad-lite/templates/admin/plugins.html', { plugins: pluginDefs.plugins, req, @@ -17,7 +23,7 @@ exports.expressCreateServer = (hookName, args, cb) => { })); }); - args.app.get('/admin/plugins/info', (req, res) => { + args.app.get('/admin/plugins/info', (req:any, res:any) => { const gitCommit = settings.getGitCommit(); const epVersion = settings.getEpVersion(); @@ -36,13 +42,14 @@ exports.expressCreateServer = (hookName, args, cb) => { return cb(); }; -exports.socketio = (hookName, args, cb) => { +exports.socketio = (hookName:string, args:ArgsExpressType, cb:Function) => { const io = args.io.of('/pluginfw/installer'); - io.on('connection', (socket) => { + io.on('connection', (socket:any) => { + // @ts-ignore const {session: {user: {is_admin: isAdmin} = {}} = {}} = socket.conn.request; if (!isAdmin) return; - socket.on('getInstalled', (query) => { + socket.on('getInstalled', (query:string) => { // send currently installed plugins const installed = Object.keys(pluginDefs.plugins).map((plugin) => pluginDefs.plugins[plugin].package); @@ -66,13 +73,14 @@ exports.socketio = (hookName, args, cb) => { socket.emit('results:updatable', {updatable}); } catch (err) { - console.warn(err.stack || err.toString()); + const errc = err as ErrorCaused + console.warn(errc.stack || errc.toString()); socket.emit('results:updatable', {updatable: {}}); } }); - socket.on('getAvailable', async (query) => { + socket.on('getAvailable', async (query:string) => { try { const results = await installer.getAvailablePlugins(/* maxCacheAge:*/ false); socket.emit('results:available', results); @@ -82,7 +90,7 @@ exports.socketio = (hookName, args, cb) => { } }); - socket.on('search', async (query) => { + socket.on('search', async (query: QueryType) => { try { const results = await installer.search(query.searchTerm, /* maxCacheAge:*/ 60 * 10); let res = Object.keys(results) @@ -98,8 +106,8 @@ exports.socketio = (hookName, args, cb) => { } }); - socket.on('install', (pluginName) => { - installer.install(pluginName, (err) => { + socket.on('install', (pluginName: string) => { + installer.install(pluginName, (err: ErrorCaused) => { if (err) console.warn(err.stack || err.toString()); socket.emit('finished:install', { @@ -110,8 +118,8 @@ exports.socketio = (hookName, args, cb) => { }); }); - socket.on('uninstall', (pluginName) => { - installer.uninstall(pluginName, (err) => { + socket.on('uninstall', (pluginName:string) => { + installer.uninstall(pluginName, (err:ErrorCaused) => { if (err) console.warn(err.stack || err.toString()); socket.emit('finished:uninstall', {plugin: pluginName, error: err ? err.message : null}); @@ -128,11 +136,13 @@ exports.socketio = (hookName, args, cb) => { * @param {String} dir The directory of the plugin * @return {Object[]} */ -const sortPluginList = (plugins, property, /* ASC?*/dir) => plugins.sort((a, b) => { +const sortPluginList = (plugins:PluginType[], property:string, /* ASC?*/dir:string): object[] => plugins.sort((a, b) => { + // @ts-ignore if (a[property] < b[property]) { return dir ? -1 : 1; } + // @ts-ignore if (a[property] > b[property]) { return dir ? 1 : -1; } diff --git a/src/node/hooks/express/adminsettings.js b/src/node/hooks/express/adminsettings.ts similarity index 79% rename from src/node/hooks/express/adminsettings.js rename to src/node/hooks/express/adminsettings.ts index 792801dc7..900bfd479 100644 --- a/src/node/hooks/express/adminsettings.js +++ b/src/node/hooks/express/adminsettings.ts @@ -6,8 +6,8 @@ const hooks = require('../../../static/js/pluginfw/hooks'); const plugins = require('../../../static/js/pluginfw/plugins'); const settings = require('../../utils/Settings'); -exports.expressCreateServer = (hookName, {app}) => { - app.get('/admin/settings', (req, res) => { +exports.expressCreateServer = (hookName:string, {app}:any) => { + app.get('/admin/settings', (req:any, res:any) => { res.send(eejs.require('ep_etherpad-lite/templates/admin/settings.html', { req, settings: '', @@ -16,12 +16,13 @@ exports.expressCreateServer = (hookName, {app}) => { }); }; -exports.socketio = (hookName, {io}) => { - io.of('/settings').on('connection', (socket) => { +exports.socketio = (hookName:string, {io}:any) => { + io.of('/settings').on('connection', (socket: any ) => { + // @ts-ignore const {session: {user: {is_admin: isAdmin} = {}} = {}} = socket.conn.request; if (!isAdmin) return; - socket.on('load', async (query) => { + socket.on('load', async (query:string):Promise => { let data; try { data = await fsp.readFile(settings.settingsFilename, 'utf8'); @@ -36,7 +37,7 @@ exports.socketio = (hookName, {io}) => { } }); - socket.on('saveSettings', async (newSettings) => { + socket.on('saveSettings', async (newSettings:string) => { await fsp.writeFile(settings.settingsFilename, newSettings); socket.emit('saveprogress', 'saved'); }); diff --git a/src/node/hooks/express/apicalls.js b/src/node/hooks/express/apicalls.ts similarity index 78% rename from src/node/hooks/express/apicalls.js rename to src/node/hooks/express/apicalls.ts index 5dbb57e16..91c44e389 100644 --- a/src/node/hooks/express/apicalls.js +++ b/src/node/hooks/express/apicalls.ts @@ -6,15 +6,15 @@ const {Formidable} = require('formidable'); const apiHandler = require('../../handler/APIHandler'); const util = require('util'); -exports.expressPreSession = async (hookName, {app}) => { +exports.expressPreSession = async (hookName:string, {app}:any) => { // The Etherpad client side sends information about how a disconnect happened - app.post('/ep/pad/connection-diagnostic-info', async (req, res) => { + app.post('/ep/pad/connection-diagnostic-info', async (req:any, res:any) => { const [fields, files] = await (new Formidable({})).parse(req); clientLogger.info(`DIAGNOSTIC-INFO: ${fields.diagnosticInfo}`); res.end('OK'); }); - const parseJserrorForm = async (req) => { + const parseJserrorForm = async (req:any) => { const form = new Formidable({ maxFileSize: 1, // Files are not expected. Not sure if 0 means unlimited, so 1 is used. }); @@ -23,11 +23,11 @@ exports.expressPreSession = async (hookName, {app}) => { }; // The Etherpad client side sends information about client side javscript errors - app.post('/jserror', (req, res, next) => { + app.post('/jserror', (req:any, res:any, next:Function) => { (async () => { const data = JSON.parse(await parseJserrorForm(req)); clientLogger.warn(`${data.msg} --`, { - [util.inspect.custom]: (depth, options) => { + [util.inspect.custom]: (depth: number, options:any) => { // Depth is forced to infinity to ensure that all of the provided data is logged. options = Object.assign({}, options, {depth: Infinity, colors: true}); return util.inspect(data, options); @@ -38,7 +38,7 @@ exports.expressPreSession = async (hookName, {app}) => { }); // Provide a possibility to query the latest available API version - app.get('/api', (req, res) => { + app.get('/api', (req:any, res:any) => { res.json({currentVersion: apiHandler.latestApiVersion}); }); }; diff --git a/src/node/hooks/express/errorhandling.js b/src/node/hooks/express/errorhandling.ts similarity index 61% rename from src/node/hooks/express/errorhandling.js rename to src/node/hooks/express/errorhandling.ts index 884ca9be0..fd16cb9af 100644 --- a/src/node/hooks/express/errorhandling.js +++ b/src/node/hooks/express/errorhandling.ts @@ -1,12 +1,15 @@ 'use strict'; +import {ArgsExpressType} from "../../types/ArgsExpressType"; +import {ErrorCaused} from "../../types/ErrorCaused"; + const stats = require('../../stats'); -exports.expressCreateServer = (hook_name, args, cb) => { +exports.expressCreateServer = (hook_name:string, args: ArgsExpressType, cb:Function) => { exports.app = args.app; // Handle errors - args.app.use((err, req, res, next) => { + args.app.use((err:ErrorCaused, req:any, res:any, next:Function) => { // if an error occurs Connect will pass it down // through these "error-handling" middleware // allowing you to respond however you like diff --git a/src/node/hooks/express/importexport.js b/src/node/hooks/express/importexport.ts similarity index 90% rename from src/node/hooks/express/importexport.js rename to src/node/hooks/express/importexport.ts index e1adefc4c..898606e49 100644 --- a/src/node/hooks/express/importexport.js +++ b/src/node/hooks/express/importexport.ts @@ -1,5 +1,7 @@ 'use strict'; +import {ArgsExpressType} from "../../types/ArgsExpressType"; + const hasPadAccess = require('../../padaccess'); const settings = require('../../utils/Settings'); const exportHandler = require('../../handler/ExportHandler'); @@ -10,10 +12,10 @@ const rateLimit = require('express-rate-limit'); const securityManager = require('../../db/SecurityManager'); const webaccess = require('./webaccess'); -exports.expressCreateServer = (hookName, args, cb) => { +exports.expressCreateServer = (hookName:string, args:ArgsExpressType, cb:Function) => { const limiter = rateLimit({ ...settings.importExportRateLimiting, - handler: (request, response, next, options) => { + handler: (request:any) => { if (request.rateLimit.current === request.rateLimit.limit + 1) { // when the rate limiter triggers, write a warning in the logs console.warn('Import/Export rate limiter triggered on ' + @@ -24,7 +26,7 @@ exports.expressCreateServer = (hookName, args, cb) => { // handle export requests args.app.use('/p/:pad/:rev?/export/:type', limiter); - args.app.get('/p/:pad/:rev?/export/:type', (req, res, next) => { + args.app.get('/p/:pad/:rev?/export/:type', (req:any, res:any, next:Function) => { (async () => { const types = ['pdf', 'doc', 'txt', 'html', 'odt', 'etherpad']; // send a 404 if we don't support this filetype @@ -70,8 +72,9 @@ exports.expressCreateServer = (hookName, args, cb) => { // handle import requests args.app.use('/p/:pad/import', limiter); - args.app.post('/p/:pad/import', (req, res, next) => { + args.app.post('/p/:pad/import', (req:any, res:any, next:Function) => { (async () => { + // @ts-ignore const {session: {user} = {}} = req; const {accessStatus, authorID: authorId} = await securityManager.checkAccess( req.params.pad, req.cookies.sessionID, req.cookies.token, user); diff --git a/src/node/hooks/express/openapi.js b/src/node/hooks/express/openapi.ts similarity index 90% rename from src/node/hooks/express/openapi.js rename to src/node/hooks/express/openapi.ts index 69f268256..aa2f1e483 100644 --- a/src/node/hooks/express/openapi.js +++ b/src/node/hooks/express/openapi.ts @@ -1,5 +1,9 @@ 'use strict'; +import {OpenAPIOperations, OpenAPISuccessResponse, SwaggerUIResource} from "../../types/SwaggerUIResource"; +import {MapArrayType} from "../../types/MapType"; +import {ErrorCaused} from "../../types/ErrorCaused"; + /** * node/hooks/express/openapi.js * @@ -52,8 +56,9 @@ const APIPathStyle = { REST: 'rest', // restful paths e.g. /rest/group/create }; + // API resources - describe your API endpoints here -const resources = { +const resources:SwaggerUIResource = { // Group group: { create: { @@ -372,7 +377,7 @@ const defaultResponses = { }, }; -const defaultResponseRefs = { +const defaultResponseRefs:OpenAPISuccessResponse = { 200: { $ref: '#/components/responses/Success', }, @@ -388,16 +393,16 @@ const defaultResponseRefs = { }; // convert to a dictionary of operation objects -const operations = {}; +const operations: OpenAPIOperations = {}; for (const [resource, actions] of Object.entries(resources)) { for (const [action, spec] of Object.entries(actions)) { - const {operationId, responseSchema, ...operation} = spec; + const {operationId,responseSchema, ...operation} = spec; // add response objects - const responses = {...defaultResponseRefs}; + const responses:OpenAPISuccessResponse = {...defaultResponseRefs}; if (responseSchema) { responses[200] = cloneDeep(defaultResponses.Success); - responses[200].content['application/json'].schema.properties.data = { + responses[200].content!['application/json'].schema.properties.data = { type: 'object', properties: responseSchema, }; @@ -414,7 +419,7 @@ for (const [resource, actions] of Object.entries(resources)) { } } -const generateDefinitionForVersion = (version, style = APIPathStyle.FLAT) => { +const generateDefinitionForVersion = (version:string, style = APIPathStyle.FLAT) => { const definition = { openapi: OPENAPI_VERSION, info, @@ -490,7 +495,7 @@ const generateDefinitionForVersion = (version, style = APIPathStyle.FLAT) => { // build operations for (const funcName of Object.keys(apiHandler.version[version])) { - let operation = {}; + let operation:OpenAPIOperations = {}; if (operations[funcName]) { operation = {...operations[funcName]}; } else { @@ -505,7 +510,9 @@ const generateDefinitionForVersion = (version, style = APIPathStyle.FLAT) => { operation.parameters = operation.parameters || []; for (const paramName of apiHandler.version[version][funcName]) { operation.parameters.push({$ref: `#/components/parameters/${paramName}`}); + // @ts-ignore if (!definition.components.parameters[paramName]) { + // @ts-ignore definition.components.parameters[paramName] = { name: paramName, in: 'query', @@ -525,6 +532,7 @@ const generateDefinitionForVersion = (version, style = APIPathStyle.FLAT) => { // add to definition // NOTE: It may be confusing that every operation can be called with both GET and POST + // @ts-ignore definition.paths[path] = { get: { ...operation, @@ -539,7 +547,7 @@ const generateDefinitionForVersion = (version, style = APIPathStyle.FLAT) => { return definition; }; -exports.expressPreSession = async (hookName, {app}) => { +exports.expressPreSession = async (hookName:string, {app}:any) => { // create openapi-backend handlers for each api version under /api/{version}/* for (const version of Object.keys(apiHandler.version)) { // we support two different styles of api: flat + rest @@ -552,7 +560,7 @@ exports.expressPreSession = async (hookName, {app}) => { const definition = generateDefinitionForVersion(version, style); // serve version specific openapi definition - app.get(`${apiRoot}/openapi.json`, (req, res) => { + app.get(`${apiRoot}/openapi.json`, (req:any, res:any) => { // For openapi definitions, wide CORS is probably fine res.header('Access-Control-Allow-Origin', '*'); res.json({...definition, servers: [generateServerForApiVersion(apiRoot, req)]}); @@ -561,7 +569,7 @@ exports.expressPreSession = async (hookName, {app}) => { // serve latest openapi definition file under /api/openapi.json const isLatestAPIVersion = version === apiHandler.latestApiVersion; if (isLatestAPIVersion) { - app.get(`/${style}/openapi.json`, (req, res) => { + app.get(`/${style}/openapi.json`, (req:any, res:any) => { res.header('Access-Control-Allow-Origin', '*'); res.json({...definition, servers: [generateServerForApiVersion(apiRoot, req)]}); }); @@ -588,12 +596,12 @@ exports.expressPreSession = async (hookName, {app}) => { // register operation handlers for (const funcName of Object.keys(apiHandler.version[version])) { - const handler = async (c, req, res) => { + const handler = async (c: any, req:any, res:any) => { // parse fields from request const {header, params, query} = c.request; // read form data if method was POST - let formData = {}; + let formData:MapArrayType = {}; if (c.request.method === 'post') { const form = new IncomingForm(); formData = (await form.parse(req))[0]; @@ -615,18 +623,19 @@ exports.expressPreSession = async (hookName, {app}) => { try { data = await apiHandler.handle(version, funcName, fields, req, res); } catch (err) { + const errCaused = err as ErrorCaused // convert all errors to http errors if (createHTTPError.isHttpError(err)) { // pass http errors thrown by handler forward throw err; - } else if (err.name === 'apierror') { + } else if (errCaused.name === 'apierror') { // parameters were wrong and the api stopped execution, pass the error // convert to http error - throw new createHTTPError.BadRequest(err.message); + throw new createHTTPError.BadRequest(errCaused.message); } else { // an unknown error happened // log it and throw internal error - logger.error(err.stack || err.toString()); + logger.error(errCaused.stack || errCaused.toString()); throw new createHTTPError.InternalError('internal error'); } } @@ -649,7 +658,7 @@ exports.expressPreSession = async (hookName, {app}) => { // start and bind to express api.init(); - app.use(apiRoot, async (req, res) => { + app.use(apiRoot, async (req:any, res:any) => { let response = null; try { if (style === APIPathStyle.REST) { @@ -660,31 +669,33 @@ exports.expressPreSession = async (hookName, {app}) => { // pass to openapi-backend handler response = await api.handleRequest(req, req, res); } catch (err) { + const errCaused = err as ErrorCaused // handle http errors - res.statusCode = err.statusCode || 500; + // @ts-ignore + res.statusCode = errCaused.statusCode || 500; // convert to our json response format // https://github.com/ether/etherpad-lite/tree/master/doc/api/http_api.md#response-format switch (res.statusCode) { case 403: // forbidden - response = {code: 4, message: err.message, data: null}; + response = {code: 4, message: errCaused.message, data: null}; break; case 401: // unauthorized (no or wrong api key) - response = {code: 4, message: err.message, data: null}; + response = {code: 4, message: errCaused.message, data: null}; break; case 404: // not found (no such function) - response = {code: 3, message: err.message, data: null}; + response = {code: 3, message: errCaused.message, data: null}; break; case 500: // server error (internal error) - response = {code: 2, message: err.message, data: null}; + response = {code: 2, message: errCaused.message, data: null}; break; case 400: // bad request (wrong parameters) // respond with 200 OK to keep old behavior and pass tests res.statusCode = 200; // @TODO: this is bad api design - response = {code: 1, message: err.message, data: null}; + response = {code: 1, message: errCaused.message, data: null}; break; default: - response = {code: 1, message: err.message, data: null}; + response = {code: 1, message: errCaused.message, data: null}; break; } } @@ -702,7 +713,7 @@ exports.expressPreSession = async (hookName, {app}) => { * @param {APIPathStyle} style The style of the API path * @return {String} The root path for the API version */ -const getApiRootForVersion = (version, style = APIPathStyle.FLAT) => `/${style}/${version}`; +const getApiRootForVersion = (version:string, style:any = APIPathStyle.FLAT): string => `/${style}/${version}`; /** * Helper to generate an OpenAPI server object when serving definitions @@ -710,6 +721,8 @@ const getApiRootForVersion = (version, style = APIPathStyle.FLAT) => `/${style}/ * @param {Request} req The express request object * @return {url: String} The server object for the OpenAPI definition location */ -const generateServerForApiVersion = (apiRoot, req) => ({ +const generateServerForApiVersion = (apiRoot:string, req:any): { + url:string +} => ({ url: `${settings.ssl ? 'https' : 'http'}://${req.headers.host}${apiRoot}`, }); diff --git a/src/node/hooks/express/padurlsanitize.js b/src/node/hooks/express/padurlsanitize.ts similarity index 81% rename from src/node/hooks/express/padurlsanitize.js rename to src/node/hooks/express/padurlsanitize.ts index ff1afa477..8679bcfe3 100644 --- a/src/node/hooks/express/padurlsanitize.js +++ b/src/node/hooks/express/padurlsanitize.ts @@ -1,10 +1,12 @@ 'use strict'; +import {ArgsExpressType} from "../../types/ArgsExpressType"; + const padManager = require('../../db/PadManager'); -exports.expressCreateServer = (hookName, args, cb) => { +exports.expressCreateServer = (hookName:string, args:ArgsExpressType, cb:Function) => { // redirects browser to the pad's sanitized url if needed. otherwise, renders the html - args.app.param('pad', (req, res, next, padId) => { + args.app.param('pad', (req:any, res:any, next:Function, padId:string) => { (async () => { // ensure the padname is valid and the url doesn't end with a / if (!padManager.isValidPadId(padId) || /\/$/.test(req.url)) { diff --git a/src/node/hooks/express/socketio.js b/src/node/hooks/express/socketio.ts similarity index 94% rename from src/node/hooks/express/socketio.js rename to src/node/hooks/express/socketio.ts index edb679940..ba1a6a313 100644 --- a/src/node/hooks/express/socketio.js +++ b/src/node/hooks/express/socketio.ts @@ -1,5 +1,7 @@ 'use strict'; +import {ArgsExpressType} from "../../types/ArgsExpressType"; + const events = require('events'); const express = require('../express'); const log4js = require('log4js'); @@ -10,7 +12,7 @@ const socketIORouter = require('../../handler/SocketIORouter'); const hooks = require('../../../static/js/pluginfw/hooks'); const padMessageHandler = require('../../handler/PadMessageHandler'); -let io; +let io:any; const logger = log4js.getLogger('socket.io'); const sockets = new Set(); const socketsEvents = new events.EventEmitter(); @@ -46,7 +48,7 @@ exports.expressCloseServer = async () => { logger.info('All socket.io clients have disconnected'); }; -exports.expressCreateServer = (hookName, args, cb) => { +exports.expressCreateServer = (hookName:string, args:ArgsExpressType, cb:Function) => { // init socket.io and redirect all requests to the MessageHandler // there shouldn't be a browser that isn't compatible to all // transports in this list at once @@ -77,7 +79,7 @@ exports.expressCreateServer = (hookName, args, cb) => { maxHttpBufferSize: settings.socketIo.maxHttpBufferSize, }); - io.on('connect', (socket) => { + io.on('connect', (socket:any) => { sockets.add(socket); socketsEvents.emit('updated'); socket.on('disconnect', () => { @@ -86,7 +88,7 @@ exports.expressCreateServer = (hookName, args, cb) => { }); }); - io.use((socket, next) => { + io.use((socket:any, next: Function) => { const req = socket.request; // Express sets req.ip but socket.io does not. Replicate Express's behavior here. if (req.ip == null) { @@ -105,8 +107,8 @@ exports.expressCreateServer = (hookName, args, cb) => { express.sessionMiddleware(req, {}, next); }); - io.use((socket, next) => { - socket.conn.on('packet', (packet) => { + io.use((socket:any, next:Function) => { + socket.conn.on('packet', (packet:string) => { // Tell express-session that the session is still active. The session store can use these // touch events to defer automatic session cleanup, and if express-session is configured with // rolling=true the cookie's expiration time will be renewed. (Note that WebSockets does not diff --git a/src/node/security/SecretRotator.ts b/src/node/security/SecretRotator.ts index b694ffb42..7d1c3a370 100644 --- a/src/node/security/SecretRotator.ts +++ b/src/node/security/SecretRotator.ts @@ -63,7 +63,7 @@ const intervalStart = (t:number, interval:number) => t - mod(t, interval); * The secrets are generated using a key derivation function (KDF) with input keying material coming * from a long-lived secret stored in the database (generated if missing). */ -class SecretRotator { +export class SecretRotator { private readonly secrets: string[]; private readonly _dbPrefix private readonly _interval diff --git a/src/node/types/ArgsExpressType.ts b/src/node/types/ArgsExpressType.ts new file mode 100644 index 000000000..5c0675b97 --- /dev/null +++ b/src/node/types/ArgsExpressType.ts @@ -0,0 +1,5 @@ +export type ArgsExpressType = { + app:any, + io: any, + server:any +} \ No newline at end of file diff --git a/src/node/types/ErrorCaused.ts b/src/node/types/ErrorCaused.ts index c3c32b071..63cc677b5 100644 --- a/src/node/types/ErrorCaused.ts +++ b/src/node/types/ErrorCaused.ts @@ -1,5 +1,6 @@ export class ErrorCaused extends Error { cause: Error; + code: any; constructor(message: string, cause: Error) { super(); this.cause = cause diff --git a/src/node/types/QueryType.ts b/src/node/types/QueryType.ts new file mode 100644 index 000000000..f851c6534 --- /dev/null +++ b/src/node/types/QueryType.ts @@ -0,0 +1,3 @@ +export type QueryType = { +searchTerm: string; sortBy: string; sortDir: string; offset: number; limit: number; +} \ No newline at end of file diff --git a/src/node/types/SecretRotatorType.ts b/src/node/types/SecretRotatorType.ts new file mode 100644 index 000000000..2c0f05f15 --- /dev/null +++ b/src/node/types/SecretRotatorType.ts @@ -0,0 +1,3 @@ +export type SecretRotatorType = { + stop: ()=>void +} \ No newline at end of file diff --git a/src/node/types/SwaggerUIResource.ts b/src/node/types/SwaggerUIResource.ts new file mode 100644 index 000000000..3f61f9ba8 --- /dev/null +++ b/src/node/types/SwaggerUIResource.ts @@ -0,0 +1,34 @@ +export type SwaggerUIResource = { + [key: string]: { + [secondKey: string]: { + operationId: string, + summary?: string, + description?:string + responseSchema?: object + } + } +} + + +export type OpenAPISuccessResponse = { + [key: number] :{ + $ref: string, + content?: { + [key: string]: { + schema: { + properties: { + data: { + type: string, + properties: object + } + } + } + } + } + } +} + + +export type OpenAPIOperations = { + [key:string]: any +} \ No newline at end of file