From fb92abc5810f33b4aa915242a28954743cfecbc1 Mon Sep 17 00:00:00 2001 From: Stefan Dej Date: Tue, 3 Dec 2024 22:16:34 +0100 Subject: [PATCH] fix: escape all file URLs to support all kind of special chars Signed-off-by: Stefan Dej --- src/components/gcodeviewer/Viewer.vue | 4 ++-- src/components/panels/GcodefilesPanel.vue | 6 +++--- .../panels/History/HistoryListEntryJob.vue | 4 ++-- .../panels/Machine/ConfigFilesPanel.vue | 4 ++-- src/components/panels/Status/GcodefilesEntry.vue | 4 ++-- src/components/panels/Status/HistoryEntry.vue | 4 ++-- .../panels/Status/PrintstatusThumbnail.vue | 5 +++-- .../panels/Timelapse/TimelapseFilesPanel.vue | 8 ++++---- src/plugins/helpers.ts | 7 +++++++ src/store/editor/actions.ts | 4 ++-- src/store/files/getters.ts | 15 ++++++--------- src/store/server/jobQueue/getters.ts | 9 +++++---- 12 files changed, 40 insertions(+), 34 deletions(-) diff --git a/src/components/gcodeviewer/Viewer.vue b/src/components/gcodeviewer/Viewer.vue index a7257a165..8a1d3b59c 100644 --- a/src/components/gcodeviewer/Viewer.vue +++ b/src/components/gcodeviewer/Viewer.vue @@ -278,7 +278,7 @@ import { Component, Mixins, Prop, Ref, Watch } from 'vue-property-decorator' import BaseMixin from '../mixins/base' import GCodeViewer from '@sindarius/gcodeviewer' import axios, { AxiosProgressEvent } from 'axios' -import { formatFilesize } from '@/plugins/helpers' +import { escapePath, formatFilesize } from '@/plugins/helpers' import Panel from '@/components/ui/Panel.vue' import CodeStream from '@/components/gcodeviewer/CodeStream.vue' import { @@ -630,7 +630,7 @@ export default class Viewer extends Mixins(BaseMixin) { const CancelToken = axios.CancelToken this.downloadSnackbar.cancelTokenSource = CancelToken.source() const text = await axios - .get(this.apiUrl + '/server/files/' + encodeURI(filename), { + .get(this.apiUrl + '/server/files/' + escapePath(filename), { cancelToken: this.downloadSnackbar.cancelTokenSource.token, responseType: 'blob', onDownloadProgress: (progressEvent: AxiosProgressEvent) => { diff --git a/src/components/panels/GcodefilesPanel.vue b/src/components/panels/GcodefilesPanel.vue index 5cc63279a..990e82cfe 100644 --- a/src/components/panels/GcodefilesPanel.vue +++ b/src/components/panels/GcodefilesPanel.vue @@ -579,7 +579,7 @@ import { Component, Mixins, Watch } from 'vue-property-decorator' import BaseMixin from '@/components/mixins/base' import { defaultBigThumbnailBackground, validGcodeExtensions } from '@/store/variables' -import { formatFilesize, formatPrintTime, sortFiles } from '@/plugins/helpers' +import { escapePath, formatFilesize, formatPrintTime, sortFiles } from '@/plugins/helpers' import { FileStateFile, FileStateGcodefile } from '@/store/files/types' import Panel from '@/components/ui/Panel.vue' import SettingsRow from '@/components/settings/SettingsRow.vue' @@ -1258,7 +1258,7 @@ export default class GcodefilesPanel extends Mixins(BaseMixin, ControlMixin) { downloadFile() { const filename = this.currentPath + '/' + this.contextMenu.item.filename - const href = this.apiUrl + '/server/files/gcodes' + encodeURI(filename) + const href = this.apiUrl + '/server/files/gcodes' + escapePath(filename) window.open(href) } @@ -1268,7 +1268,7 @@ export default class GcodefilesPanel extends Mixins(BaseMixin, ControlMixin) { const addElementToItems = async (absolutPath: string, directory: FileStateFile[]) => { for (const file of directory) { - const filePath = `${absolutPath}/${file.filename}` + const filePath = `${absolutPath}/${escapePath(file.filename)}` if (file.isDirectory && file.childrens) { await addElementToItems(filePath, file.childrens) diff --git a/src/components/panels/History/HistoryListEntryJob.vue b/src/components/panels/History/HistoryListEntryJob.vue index d6444cfc4..ee5c739be 100644 --- a/src/components/panels/History/HistoryListEntryJob.vue +++ b/src/components/panels/History/HistoryListEntryJob.vue @@ -149,7 +149,7 @@ import { mdiPrinter, mdiTextBoxSearch, } from '@mdi/js' -import { formatFilesize, formatPrintTime } from '@/plugins/helpers' +import { escapePath, formatFilesize, formatPrintTime } from '@/plugins/helpers' import { HistoryListPanelCol } from '@/components/panels/HistoryListPanel.vue' import HistoryListPanelNoteDialog from '@/components/dialogs/HistoryListPanelNoteDialog.vue' import AddBatchToQueueDialog from '@/components/dialogs/AddBatchToQueueDialog.vue' @@ -321,7 +321,7 @@ export default class HistoryListPanel extends Mixins(BaseMixin) { relative_url = this.item.filename.substring(0, this.item.filename.lastIndexOf('/') + 1) } - return `${this.apiUrl}/server/files/gcodes/${encodeURI(relative_url + thumbnail.relative_path)}?timestamp=${ + return `${this.apiUrl}/server/files/gcodes/${escapePath(relative_url + thumbnail.relative_path)}?timestamp=${ this.item.metadata.modified }` } diff --git a/src/components/panels/Machine/ConfigFilesPanel.vue b/src/components/panels/Machine/ConfigFilesPanel.vue index db3c9153c..59cba3f5f 100644 --- a/src/components/panels/Machine/ConfigFilesPanel.vue +++ b/src/components/panels/Machine/ConfigFilesPanel.vue @@ -537,7 +537,7 @@ import { Component, Mixins } from 'vue-property-decorator' import BaseMixin from '@/components/mixins/base' import ThemeMixin from '@/components/mixins/theme' -import { formatFilesize, sortFiles } from '@/plugins/helpers' +import { escapePath, formatFilesize, sortFiles } from '@/plugins/helpers' import { FileStateFile, FileStateGcodefile } from '@/store/files/types' import axios from 'axios' import Panel from '@/components/ui/Panel.vue' @@ -1033,7 +1033,7 @@ export default class ConfigFilesPanel extends Mixins(BaseMixin, ThemeMixin) { downloadFile() { const filename = this.absolutePath + '/' + this.contextMenu.item.filename - const href = `${this.apiUrl}/server/files${encodeURI(filename)}` + const href = `${this.apiUrl}/server/files${escapePath(filename)}` window.open(href) } diff --git a/src/components/panels/Status/GcodefilesEntry.vue b/src/components/panels/Status/GcodefilesEntry.vue index 40ec4837a..cc400a0c6 100644 --- a/src/components/panels/Status/GcodefilesEntry.vue +++ b/src/components/panels/Status/GcodefilesEntry.vue @@ -173,7 +173,7 @@ import { import Panel from '@/components/ui/Panel.vue' import { defaultBigThumbnailBackground } from '@/store/variables' import AddBatchToQueueDialog from '@/components/dialogs/AddBatchToQueueDialog.vue' -import { formatPrintTime } from '@/plugins/helpers' +import { escapePath, formatPrintTime } from '@/plugins/helpers' @Component({ components: { @@ -295,7 +295,7 @@ export default class StatusPanelGcodefilesEntry extends Mixins(BaseMixin, Contro } downloadFile() { - const href = this.apiUrl + '/server/files/gcodes/' + encodeURI(this.item.filename) + const href = this.apiUrl + '/server/files/gcodes/' + escapePath(this.item.filename) window.open(href) } diff --git a/src/components/panels/Status/HistoryEntry.vue b/src/components/panels/Status/HistoryEntry.vue index 7d5af2cb7..e3ab2f5c3 100644 --- a/src/components/panels/Status/HistoryEntry.vue +++ b/src/components/panels/Status/HistoryEntry.vue @@ -87,7 +87,7 @@ import { mdiCloseThick, mdiDelete, mdiFile, mdiPlaylistPlus, mdiPrinter } from ' import { defaultBigThumbnailBackground, thumbnailBigMin, thumbnailSmallMax, thumbnailSmallMin } from '@/store/variables' import { ServerHistoryStateJobWithCount } from '@/store/server/history/types' import { FileStateFileThumbnail } from '@/store/files/types' -import { formatPrintTime } from '@/plugins/helpers' +import { escapePath, formatPrintTime } from '@/plugins/helpers' @Component export default class StatusPanelHistoryEntry extends Mixins(BaseMixin) { mdiCloseThick = mdiCloseThick @@ -250,7 +250,7 @@ export default class StatusPanelHistoryEntry extends Mixins(BaseMixin) { relative_url = this.job.filename.substring(0, this.job.filename.lastIndexOf('/') + 1) } - return `${this.apiUrl}/server/files/gcodes/${encodeURI(relative_url + thumbnail.relative_path)}?timestamp=${ + return `${this.apiUrl}/server/files/gcodes/${escapePath(relative_url + thumbnail.relative_path)}?timestamp=${ this.job.metadata.modified }` } diff --git a/src/components/panels/Status/PrintstatusThumbnail.vue b/src/components/panels/Status/PrintstatusThumbnail.vue index 11207d17b..47a6fb8da 100644 --- a/src/components/panels/Status/PrintstatusThumbnail.vue +++ b/src/components/panels/Status/PrintstatusThumbnail.vue @@ -87,6 +87,7 @@ import BaseMixin from '@/components/mixins/base' import { defaultBigThumbnailBackground, thumbnailBigMin, thumbnailSmallMax, thumbnailSmallMin } from '@/store/variables' import { mdiFileOutline, mdiFile } from '@mdi/js' import { Debounce } from 'vue-debounce-decorator' +import { escapePath } from '@/plugins/helpers' @Component({}) export default class StatusPanelPrintstatusThumbnail extends Mixins(BaseMixin) { @@ -119,7 +120,7 @@ export default class StatusPanelPrintstatusThumbnail extends Mixins(BaseMixin) { } if (thumbnail && 'relative_path' in thumbnail) { - return `${this.apiUrl}/server/files/gcodes/${encodeURI( + return `${this.apiUrl}/server/files/gcodes/${escapePath( relative_url + thumbnail.relative_path )}?timestamp=${this.current_file.modified}` } @@ -170,7 +171,7 @@ export default class StatusPanelPrintstatusThumbnail extends Mixins(BaseMixin) { } if (thumbnail && 'relative_path' in thumbnail) { - return `${this.apiUrl}/server/files/gcodes/${encodeURI( + return `${this.apiUrl}/server/files/gcodes/${escapePath( relative_url + thumbnail.relative_path )}?timestamp=${this.current_file.modified}` } diff --git a/src/components/panels/Timelapse/TimelapseFilesPanel.vue b/src/components/panels/Timelapse/TimelapseFilesPanel.vue index 51960df24..3121f1a73 100644 --- a/src/components/panels/Timelapse/TimelapseFilesPanel.vue +++ b/src/components/panels/Timelapse/TimelapseFilesPanel.vue @@ -423,7 +423,7 @@