Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,14 @@ import { FileAction, FileActionOptions } from '../types'
import { useGettext } from 'vue3-gettext'
import { useArchiverService } from '../../archiverService'
import { formatFileSize } from '../../../helpers/filesize'
import { useMessages } from '../../piniaStores'
import { useAuthStore, useMessages } from '../../piniaStores'

export const useFileActionsDownloadArchive = () => {
const { showErrorMessage } = useMessages()
const router = useRouter()
const archiverService = useArchiverService()
const { $ngettext, $gettext, current } = useGettext()
const authStore = useAuthStore()
const isFilesAppActive = useIsFilesAppActive()

const handler = ({ space, resources }: FileActionOptions) => {
Expand All @@ -34,7 +35,8 @@ export const useFileActionsDownloadArchive = () => {
fileIds: resources.map((resource) => resource.fileId),
...(space &&
isPublicSpaceResource(space) && {
publicToken: space.id
publicToken: space.id,
publicLinkPassword: authStore.publicLinkPassword
})
})
.catch((e) => {
Expand Down
31 changes: 28 additions & 3 deletions packages/web-pkg/src/services/archiver.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { RuntimeError } from '../errors'
import { urlJoin } from '@opencloud-eu/web-client'
import { HttpError, urlJoin } from '@opencloud-eu/web-client'
import { ClientService } from '../services'
import { triggerDownloadWithFilename } from '../helpers/download'
import { Ref, ref, computed, unref } from 'vue'
Expand All @@ -11,6 +11,7 @@ interface TriggerDownloadOptions {
files?: string[]
fileIds?: string[]
publicToken?: string
publicLinkPassword?: string
}

export class ArchiverService {
Expand Down Expand Up @@ -55,14 +56,38 @@ export class ArchiverService {
throw new RuntimeError('download url could not be built')
}

const url = options.publicToken
let url = options.publicToken
? downloadUrl
: await this.clientService.ocs.signUrl(
downloadUrl,
this.userStore.user?.onPremisesSamAccountName
)

triggerDownloadWithFilename(url)
let fileName: string
if (options.publicLinkPassword) {
// FIXME: remove as soon as we remove client-side URL signing https://github.com/opencloud-eu/opencloud/issues/1197
try {
const response = await fetch(url, {
headers: {
...this.clientService.getRequestHeaders({ useAuth: false }),
Authorization:
'Basic ' +
Buffer.from(['public', options.publicLinkPassword].join(':')).toString('base64')
}
})

if (!response.ok) {
throw new HttpError('', response)
}

const blob = await response.blob()
url = URL.createObjectURL(blob)
fileName = decodeURI(response.headers.get('content-disposition')?.split('"')[1])
Copy link

Copilot AI Nov 5, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This line will throw a TypeError if content-disposition header is missing or doesn't contain quotes. The optional chaining stops at get(), but split('"')[1] will fail if the header is null/undefined or doesn't have the expected format. Consider adding proper null checks: const contentDisposition = response.headers.get('content-disposition'); fileName = contentDisposition?.split('\"')[1] ? decodeURI(contentDisposition.split('\"')[1]) : 'archive';

Suggested change
fileName = decodeURI(response.headers.get('content-disposition')?.split('"')[1])
{
const contentDisposition = response.headers.get('content-disposition');
// Try to extract filename from header (handles quoted and unquoted)
const match = contentDisposition && contentDisposition.match(/filename\*?=(?:UTF-8'')?("?)([^";]+)\1/);
fileName = match ? decodeURI(match[2]) : 'archive';
}

Copilot uses AI. Check for mistakes.
} catch (e) {
throw new Error('archive could not be fetched')
}
}
triggerDownloadWithFilename(url, fileName)
return url
}

Expand Down