@@ -94,7 +94,7 @@ module.exports = function (
9494 getSecurityConfig : SecurityConfigGetter
9595) {
9696 let securityWasEnabled = false
97- let restoreFilePath : string
97+ const restoreSessions = new Map < string , string > ( )
9898
9999 const logopath = path . resolve ( app . config . configPath , 'logo.svg' )
100100 if ( fs . existsSync ( logopath ) ) {
@@ -1008,16 +1008,28 @@ module.exports = function (
10081008 } )
10091009 }
10101010
1011- app . post ( `${ SERVERROUTESPREFIX } /restore` , ( req : Request , res : Response ) => {
1012- if ( ! restoreFilePath ) {
1013- res . status ( 400 ) . send ( 'not exting restore file' )
1014- } else if ( ! fs . existsSync ( restoreFilePath ) ) {
1015- res . status ( 400 ) . send ( 'restore file does not exist' )
1016- } else {
1017- res . status ( 202 ) . send ( )
1018- }
1011+ app . post (
1012+ `${ SERVERROUTESPREFIX } /restore` ,
1013+ ( req : Request , res : Response ) => {
1014+ if (
1015+ ! app . securityStrategy . isDummy ( ) &&
1016+ ! app . securityStrategy . allowConfigure ( req )
1017+ ) {
1018+ res . status ( 401 ) . send ( 'Restore not allowed' )
1019+ return
1020+ }
1021+ const sessionId = getCookie ( req , 'restoreSession' )
1022+ const restoreFilePath = sessionId ? restoreSessions . get ( sessionId ) : undefined
1023+
1024+ if ( ! restoreFilePath ) {
1025+ res . status ( 400 ) . send ( 'not exting restore file' )
1026+ } else if ( ! fs . existsSync ( restoreFilePath ) ) {
1027+ res . status ( 400 ) . send ( 'restore file does not exist' )
1028+ } else {
1029+ res . status ( 202 ) . send ( )
1030+ }
10191031
1020- listSafeRestoreFiles ( restoreFilePath )
1032+ listSafeRestoreFiles ( restoreFilePath ! )
10211033 . then ( ( files ) => {
10221034 const wanted = files . filter ( ( name ) => {
10231035 return req . body [ name ]
@@ -1032,7 +1044,7 @@ module.exports = function (
10321044 i / wanted . length
10331045 )
10341046 ncp (
1035- path . join ( restoreFilePath , name ) ,
1047+ path . join ( restoreFilePath ! , name ) ,
10361048 path . join ( app . config . configPath , name ) ,
10371049 { stopOnErr : true } ,
10381050 // eslint-disable-next-line @typescript-eslint/no-explicit-any
@@ -1072,6 +1084,13 @@ module.exports = function (
10721084 app . post (
10731085 `${ SERVERROUTESPREFIX } /validateBackup` ,
10741086 ( req : Request , res : Response ) => {
1087+ if (
1088+ ! app . securityStrategy . isDummy ( ) &&
1089+ ! app . securityStrategy . allowConfigure ( req )
1090+ ) {
1091+ res . status ( 401 ) . send ( 'Validate backup not allowed' )
1092+ return
1093+ }
10751094 const bb = busboy ( { headers : req . headers } )
10761095 bb . on (
10771096 'file' ,
@@ -1095,7 +1114,12 @@ module.exports = function (
10951114 return
10961115 }
10971116 const tmpDir = os . tmpdir ( )
1098- restoreFilePath = fs . mkdtempSync ( `${ tmpDir } ${ path . sep } ` )
1117+ const restoreFilePath = fs . mkdtempSync ( `${ tmpDir } ${ path . sep } ` )
1118+ const sessionId = Date . now ( ) + '_' + Math . random ( ) . toString ( 36 ) . substr ( 2 , 9 )
1119+ restoreSessions . set ( sessionId , restoreFilePath )
1120+ setTimeout ( ( ) => restoreSessions . delete ( sessionId ) , 15 * 60 * 1000 )
1121+ res . cookie ( 'restoreSession' , sessionId , { httpOnly : true , sameSite : 'strict' } )
1122+
10991123 const zipFileDir = fs . mkdtempSync ( `${ tmpDir } ${ path . sep } ` )
11001124 const zipFile = path . join ( zipFileDir , 'backup.zip' )
11011125 const unzipStream = unzipper . Extract ( { path : restoreFilePath } )
@@ -1185,3 +1209,14 @@ const setNoCache = (res: Response) => {
11851209 res . header ( 'Pragma' , 'no-cache' )
11861210 res . header ( 'Expires' , '0' )
11871211}
1212+
1213+ function getCookie ( req : Request , name : string ) : string | undefined {
1214+ if ( req . headers . cookie ) {
1215+ const value = '; ' + req . headers . cookie
1216+ const parts = value . split ( '; ' + name + '=' )
1217+ if ( parts . length === 2 ) {
1218+ return parts . pop ( ) ?. split ( ';' ) . shift ( )
1219+ }
1220+ }
1221+ return undefined
1222+ }
0 commit comments