an upload with ?existing=overwrite will return an error if the file exists and you don't have permission

Massimo Melina committed Aug 19, 2024 at 00:06 UTC 092c4afcb1033303f16c3883b81c7e401ce78054
1 file changed +11 -4
src/upload.ts
+11 -4
@@ -1,4 +1,4 @@
1 -import { getNodeByName, hasPermission, statusCodeForMissingPerm, VfsNode } from './vfs'
1 +import { getNodeByName, statusCodeForMissingPerm, VfsNode } from './vfs'
2 import Koa from 'koa'
3 import { HTTP_CONFLICT, HTTP_FOOL, HTTP_PAYLOAD_TOO_LARGE, HTTP_RANGE_NOT_SATISFIABLE, HTTP_SERVER_ERROR,
4 HTTP_BAD_REQUEST } from './const'
@@ -15,7 +15,7 @@ import { getCurrentUsername } from './auth'
15 import { setCommentFor } from './comments'
16 import _ from 'lodash'
17 import events from './events'
18 -import { rename } from 'fs/promises'
18 +import { rename, rm } from 'fs/promises'
19
20 export const deleteUnfinishedUploadsAfter = defineConfig<undefined|number>('delete_unfinished_uploads_after', 86_400)
21 export const minAvailableMb = defineConfig('min_available_mb', 100)
@@ -86,6 +86,7 @@ export function uploadWriter(base: VfsNode, path: string, ctx: Koa.Context) {
86 if (ctx.query.existing === 'skip' && fs.existsSync(fullPath))
87 return fail(HTTP_CONFLICT, 'exists')
88 openFiles.add(fullPath)
89 + let overwriteRequestedButForbidden = false
90 try {
91 // if upload creates a folder, then add meta to it too
92 if (fs.mkdirSync(dir, { recursive: true }))
@@ -146,6 +147,10 @@ export function uploadWriter(base: VfsNode, path: string, ctx: Koa.Context) {
147 }
148 let dest = fullPath
149 if (dontOverwriteUploading.get() && !await overwriteAnyway() && fs.existsSync(dest)) {
150 + if (overwriteRequestedButForbidden) {
151 + await rm(tempName)
152 + return fail()
153 + }
154 const ext = extname(dest)
155 const base = dest.slice(0, -ext.length || Infinity)
156 let i = 1
@@ -203,9 +208,11 @@ export function uploadWriter(base: VfsNode, path: string, ctx: Koa.Context) {
208 }
209
210 async function overwriteAnyway() {
206 - if (ctx.query.existing !== 'overwrite') return
211 + if (ctx.query.existing !== 'overwrite') return false
212 const n = await getNodeByName(path, base)
208 - return n && hasPermission(n, 'can_delete', ctx)
213 + if (n && !statusCodeForMissingPerm(n, 'can_delete', ctx)) return true
214 + overwriteRequestedButForbidden = true
215 + return false
216 }
217
218 function delayedDelete(path: string, secs: number, cb?: Callback) {