2020-09-02 17:16:02 -04:00
const assert = require ( 'assert' ) . strict ;
2012-02-25 17:23:44 +01:00
var hasPadAccess = require ( "../../padaccess" ) ;
var settings = require ( '../../utils/Settings' ) ;
var exportHandler = require ( '../../handler/ExportHandler' ) ;
var importHandler = require ( '../../handler/ImportHandler' ) ;
2018-04-04 21:48:32 +01:00
var padManager = require ( "../../db/PadManager" ) ;
2020-04-04 21:43:33 +00:00
var authorManager = require ( "../../db/AuthorManager" ) ;
2020-04-04 20:39:33 +00:00
const rateLimit = require ( "express-rate-limit" ) ;
2020-09-02 17:16:02 -04:00
const securityManager = require ( "../../db/SecurityManager" ) ;
2020-04-04 20:39:33 +00:00
settings . importExportRateLimiting . onLimitReached = function ( req , res , options ) {
// when the rate limiter triggers, write a warning in the logs
console . warn ( ` Import/Export rate limiter triggered on " ${ req . originalUrl } " for IP address ${ req . ip } ` ) ;
}
var limiter = rateLimit ( settings . importExportRateLimiting ) ;
2012-02-25 16:06:08 +01:00
exports . expressCreateServer = function ( hook _name , args , cb ) {
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 ) ;
2019-01-23 16:29:36 +00:00
args . app . get ( '/p/:pad/:rev?/export/:type' , async function ( req , res , next ) {
2014-12-29 20:57:58 +01:00
var types = [ "pdf" , "doc" , "txt" , "html" , "odt" , "etherpad" ] ;
2012-02-25 16:06:08 +01:00
//send a 404 if we don't support this filetype
if ( types . indexOf ( req . params . type ) == - 1 ) {
2019-01-23 16:29:36 +00:00
return next ( ) ;
2012-02-25 16:06:08 +01:00
}
2019-02-08 23:20:57 +01:00
// if abiword is disabled, and this is a format we only support with abiword, output a message
2015-12-18 00:14:13 -06:00
if ( settings . exportAvailable ( ) == "no" &&
2012-02-25 16:06:08 +01:00
[ "odt" , "pdf" , "doc" ] . indexOf ( req . params . type ) !== - 1 ) {
2020-04-13 01:33:43 +02:00
console . error ( ` Impossible to export pad " ${ req . params . pad } " in ${ req . params . type } format. There is no converter configured ` ) ;
// 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" ) ;
2012-02-25 16:06:08 +01:00
return ;
}
res . header ( "Access-Control-Allow-Origin" , "*" ) ;
2019-01-23 16:29:36 +00:00
if ( await hasPadAccess ( req , res ) ) {
let exists = await padManager . doesPadExists ( req . params . pad ) ;
if ( ! exists ) {
2020-04-13 01:33:43 +02:00
console . warn ( ` Someone tried to export a pad that doesn't exist ( ${ req . params . pad } ) ` ) ;
2019-01-23 16:29:36 +00:00
return next ( ) ;
}
2018-04-04 21:48:32 +01:00
2020-04-13 01:33:43 +02:00
console . log ( ` Exporting pad " ${ req . params . pad } " in ${ req . params . type } format ` ) ;
2019-01-23 16:29:36 +00:00
exportHandler . doExport ( req , res , req . params . pad , req . params . type ) ;
}
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 ) ;
2019-01-23 16:29:36 +00:00
args . app . post ( '/p/:pad/import' , async function ( req , res , next ) {
2020-09-02 17:16:02 -04:00
if ( ! ( await padManager . doesPadExists ( req . params . pad ) ) ) {
console . warn ( ` Someone tried to import into a pad that doesn't exist ( ${ req . params . pad } ) ` ) ;
return next ( ) ;
}
2020-04-04 21:43:33 +00:00
2020-09-11 17:12:29 -04:00
const { session : { user } = { } } = req ;
2020-09-02 17:16:02 -04:00
const { accessStatus , authorID } = await securityManager . checkAccess (
2020-09-11 17:12:29 -04:00
req . params . pad , req . cookies . sessionID , req . cookies . token , req . cookies . password , user ) ;
2020-09-02 17:16:02 -04:00
if ( accessStatus !== 'grant' ) return res . status ( 403 ) . send ( 'Forbidden' ) ;
assert ( authorID ) ;
/ *
* Starting from Etherpad 1.8 . 3 onwards , importing into a pad is allowed
* only if a user has his browser opened and connected to the pad ( i . e . a
* Socket . IO session is estabilished for him ) and he has already
* contributed to that specific pad .
*
* Note that this does not have anything to do with the "session" , used
* for logging into "group pads" . That kind of session is not needed here .
*
* This behaviour does not apply to API requests , only to / p / $PAD$ / import
*
* See : https : //github.com/ether/etherpad-lite/pull/3833#discussion_r407490205
* /
if ( ! settings . allowAnyoneToImport ) {
const authorsPads = await authorManager . listPadsOfAuthor ( authorID ) ;
if ( ! authorsPads ) {
console . warn ( ` Unable to import file into " ${ req . params . pad } ". Author " ${ authorID } " exists but he never contributed to any pad ` ) ;
2020-04-04 21:43:33 +00:00
return next ( ) ;
}
2020-09-02 17:16:02 -04:00
if ( authorsPads . padIDs . indexOf ( req . params . pad ) === - 1 ) {
console . warn ( ` Unable to import file into " ${ req . params . pad } ". Author " ${ authorID } " exists but he never contributed to this pad ` ) ;
2020-04-04 21:43:33 +00:00
return next ( ) ;
}
2019-01-23 16:29:36 +00:00
}
2020-09-02 17:16:02 -04:00
importHandler . doImport ( req , res , req . params . pad ) ;
2012-02-25 16:06:08 +01:00
} ) ;
}