2021-01-21 21:06:52 +00:00
|
|
|
'use strict';
|
|
|
|
|
2024-02-05 21:13:02 +01:00
|
|
|
import {ArgsExpressType} from "../../types/ArgsExpressType";
|
|
|
|
|
2020-11-23 13:24:19 -05:00
|
|
|
const hasPadAccess = require('../../padaccess');
|
2024-02-21 21:48:51 +01:00
|
|
|
import {exportAvailable, settings} from '../../utils/Settings';
|
2020-11-23 13:24:19 -05:00
|
|
|
const exportHandler = require('../../handler/ExportHandler');
|
|
|
|
const importHandler = require('../../handler/ImportHandler');
|
|
|
|
const padManager = require('../../db/PadManager');
|
|
|
|
const readOnlyManager = require('../../db/ReadOnlyManager');
|
|
|
|
const rateLimit = require('express-rate-limit');
|
|
|
|
const securityManager = require('../../db/SecurityManager');
|
|
|
|
const webaccess = require('./webaccess');
|
2020-04-04 20:39:33 +00:00
|
|
|
|
2024-02-05 21:13:02 +01:00
|
|
|
exports.expressCreateServer = (hookName:string, args:ArgsExpressType, cb:Function) => {
|
2023-10-22 18:26:58 +02:00
|
|
|
const limiter = rateLimit({
|
2024-02-21 21:48:51 +01:00
|
|
|
...settings.importExportRateLimiting,
|
2024-02-05 21:13:02 +01:00
|
|
|
handler: (request:any) => {
|
2023-10-22 18:26:58 +02:00
|
|
|
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 ' +
|
|
|
|
`"${request.originalUrl}" for IP address ${request.ip}`);
|
|
|
|
}
|
|
|
|
},
|
|
|
|
});
|
2021-02-16 20:53:42 -05:00
|
|
|
|
2020-04-13 01:33:43 +02:00
|
|
|
// handle export requests
|
2020-04-04 20:39:33 +00:00
|
|
|
args.app.use('/p/:pad/:rev?/export/:type', limiter);
|
2024-02-05 21:13:02 +01:00
|
|
|
args.app.get('/p/:pad/:rev?/export/:type', (req:any, res:any, next:Function) => {
|
2021-02-07 19:56:07 -05:00
|
|
|
(async () => {
|
|
|
|
const types = ['pdf', 'doc', 'txt', 'html', 'odt', 'etherpad'];
|
|
|
|
// send a 404 if we don't support this filetype
|
|
|
|
if (types.indexOf(req.params.type) === -1) {
|
|
|
|
return next();
|
|
|
|
}
|
2012-02-25 16:06:08 +01:00
|
|
|
|
2021-02-07 19:56:07 -05:00
|
|
|
// if abiword is disabled, and this is a format we only support with abiword, output a message
|
2024-02-21 19:56:50 +01:00
|
|
|
if (exportAvailable() === 'no' &&
|
2021-02-07 19:56:07 -05:00
|
|
|
['odt', 'pdf', 'doc'].indexOf(req.params.type) !== -1) {
|
|
|
|
console.error(`Impossible to export pad "${req.params.pad}" in ${req.params.type} format.` +
|
|
|
|
' There is no converter configured');
|
2020-04-13 01:33:43 +02:00
|
|
|
|
2021-02-07 19:56:07 -05:00
|
|
|
// ACHTUNG: do not include req.params.type in res.send() because there is
|
|
|
|
// no HTML escaping and it would lead to an XSS
|
|
|
|
res.send('This export is not enabled at this Etherpad instance. Set the path to Abiword' +
|
|
|
|
' or soffice (LibreOffice) in settings.json to enable this feature');
|
|
|
|
return;
|
|
|
|
}
|
2012-02-25 16:06:08 +01:00
|
|
|
|
2021-02-07 19:56:07 -05:00
|
|
|
res.header('Access-Control-Allow-Origin', '*');
|
2012-02-25 16:06:08 +01:00
|
|
|
|
2021-02-07 19:56:07 -05:00
|
|
|
if (await hasPadAccess(req, res)) {
|
|
|
|
let padId = req.params.pad;
|
2020-09-16 14:57:27 -03:00
|
|
|
|
2021-02-07 19:56:07 -05:00
|
|
|
let readOnlyId = null;
|
|
|
|
if (readOnlyManager.isReadOnlyId(padId)) {
|
|
|
|
readOnlyId = padId;
|
|
|
|
padId = await readOnlyManager.getPadId(readOnlyId);
|
|
|
|
}
|
2020-09-16 14:57:27 -03:00
|
|
|
|
2021-02-07 19:56:07 -05:00
|
|
|
const exists = await padManager.doesPadExists(padId);
|
|
|
|
if (!exists) {
|
|
|
|
console.warn(`Someone tried to export a pad that doesn't exist (${padId})`);
|
|
|
|
return next();
|
|
|
|
}
|
2018-04-04 21:48:32 +01:00
|
|
|
|
2021-02-07 19:56:07 -05:00
|
|
|
console.log(`Exporting pad "${req.params.pad}" in ${req.params.type} format`);
|
2021-03-17 18:54:57 -04:00
|
|
|
await exportHandler.doExport(req, res, padId, readOnlyId, req.params.type);
|
2021-02-07 19:56:07 -05:00
|
|
|
}
|
|
|
|
})().catch((err) => next(err || new Error(err)));
|
2012-02-25 16:06:08 +01:00
|
|
|
});
|
|
|
|
|
2019-02-08 23:20:57 +01:00
|
|
|
// handle import requests
|
2020-04-04 20:39:33 +00:00
|
|
|
args.app.use('/p/:pad/import', limiter);
|
2024-02-05 21:13:02 +01:00
|
|
|
args.app.post('/p/:pad/import', (req:any, res:any, next:Function) => {
|
2021-02-07 19:56:07 -05:00
|
|
|
(async () => {
|
2024-02-05 21:13:02 +01:00
|
|
|
// @ts-ignore
|
2021-02-07 19:56:07 -05:00
|
|
|
const {session: {user} = {}} = req;
|
2022-02-17 00:01:07 -05:00
|
|
|
const {accessStatus, authorID: authorId} = await securityManager.checkAccess(
|
2021-02-07 19:56:07 -05:00
|
|
|
req.params.pad, req.cookies.sessionID, req.cookies.token, user);
|
|
|
|
if (accessStatus !== 'grant' || !webaccess.userCanModify(req.params.pad, req)) {
|
|
|
|
return res.status(403).send('Forbidden');
|
|
|
|
}
|
2022-02-17 00:01:07 -05:00
|
|
|
await importHandler.doImport(req, res, req.params.pad, authorId);
|
2021-02-07 19:56:07 -05:00
|
|
|
})().catch((err) => next(err || new Error(err)));
|
2012-02-25 16:06:08 +01:00
|
|
|
});
|
2020-10-10 22:51:26 -04:00
|
|
|
|
|
|
|
return cb();
|
2020-11-23 13:24:19 -05:00
|
|
|
};
|