fix: faulty upload of files with # in the name #722

Massimo Melina committed Sep 4, 2024 at 16:39 UTC ccca4cd5529c9feacd4e580db0f7c861fc1c624b
4 files changed +8 -7
admin/src/addFiles.ts
+4 -4
@@ -7,7 +7,7 @@ import { reloadVfs } from './VfsPage'
7 import { state } from './state'
8 import { apiCall } from './api'
9 import FilePicker from './FilePicker'
10 -import { focusSelector } from '@hfs/shared'
10 +import { focusSelector, pathEncode } from '@hfs/shared'
11
12 let lastFolder: undefined | string
13 export default function addFiles() {
@@ -36,7 +36,7 @@ export default function addFiles() {
36 h('li', { key: file }, file, ': ', err))
37 )
38 ), 'error')
39 - const ids = res.filter(x => x.name).map(x => parent.id + encodeURI(x.name) + (x.link.endsWith('/') ? '/' : ''))
39 + const ids = res.filter(x => x.name).map(x => parent.id + pathEncode(x.name) + (x.link.endsWith('/') ? '/' : ''))
40 reloadVfs(ids)
41 close()
42 }
@@ -53,7 +53,7 @@ export async function addVirtual() {
53 const { id: parent } = getFolderFromSelected()
54 const res = await apiCall('add_vfs', { parent, name })
55 await alertDialog(`Folder "${res.name}" created`, 'success')
56 - reloadVfs([ parent + encodeURI(res.name) + '/' ])
56 + reloadVfs([ parent + pathEncode(res.name) + '/' ])
57 }
58 catch(e) {
59 await alertDialog(e as Error)
@@ -64,7 +64,7 @@ export async function addLink() {
64 try {
65 const { id: parent } = getFolderFromSelected()
66 const res = await apiCall('add_vfs', { parent, name: 'new link', url: 'https://example.com' })
67 - reloadVfs([ parent + encodeURI(res.name) ])
67 + reloadVfs([ parent + pathEncode(res.name) ])
68 toast("Link created", 'success', {
69 onClose: () => focusSelector('input[name=url]')
70 })
frontend/src/fileMenu.ts
+1 -1
@@ -79,7 +79,7 @@ export function openFileMenu(entry: DirEntry, ev: MouseEvent, addToMenu: (Falsy
79 id: 'folder',
80 label: t`Folder`,
81 value: h(Link, {
82 - to: (folder.startsWith('/') ? '' : location.pathname) + folder.split('/').map(encodeURIComponent).join('/') + '/',
82 + to: (folder.startsWith('/') ? '' : location.pathname) + pathEncode(folder) + '/',
83 onClick: () => closeDialog(null, true)
84 }, folder.replaceAll('/', ' / '))
85 },
frontend/src/upload.ts
+2 -2
@@ -5,7 +5,7 @@ import { Btn, Flex, FlexV, iconBtn, Select } from './components'
5 import {
6 basename, closeDialog, formatBytes, formatPerc, hIcon, useIsMobile, newDialog, prefix, selectFiles, working,
7 HTTP_CONFLICT, HTTP_PAYLOAD_TOO_LARGE, formatSpeed, dirname, getHFS, onlyTruthy, with_, cpuSpeedIndex,
8 - buildUrlQueryString, randomId, HTTP_MESSAGES,
8 + buildUrlQueryString, randomId, HTTP_MESSAGES, pathEncode,
9 } from './misc'
10 import _ from 'lodash'
11 import { INTERNAL_Snapshot, proxy, ref, snapshot, subscribe, useSnapshot } from 'valtio'
@@ -335,7 +335,7 @@ async function startUpload(toUpload: ToUpload, to: string, resume=0) {
335 let uploadPath = path(toUpload.file)
336 if (toUpload.name)
337 uploadPath = prefix('', dirname(uploadPath), '/') + toUpload.name
338 - req.open('PUT', to + encodeURI(uploadPath) + buildUrlQueryString({
338 + req.open('PUT', to + pathEncode(uploadPath) + buildUrlQueryString({
339 notificationChannel,
340 ...resume && { resume: String(resume) },
341 ...toUpload.comment && { comment: toUpload.comment },
src/cross.ts
+1
@@ -398,6 +398,7 @@ export async function promiseBestEffort<T>(promises: Promise<T>[]) {
398 return res.filter(x => x.status === 'fulfilled').map((x: any) => x.value as T)
399 }
400
401 +// encode paths leaving / separator unencoded (not like encodeURIComponent), but still encode #
402 export function pathEncode(s: string) {
403 return encodeURI(s).replace(/#/g, encodeURIComponent)
404 }