From 13dea10afceaa08d6ec526b26978bda344a6210d Mon Sep 17 00:00:00 2001 From: Alexander Ackermann Date: Wed, 7 Oct 2026 22:08:02 +0200 Subject: [PATCH 1/2] fix(web-runtime): keep the public link context when unlocking a vault --- .../src/router/setupVaultUnlockGuard.ts | 4 +++ .../unit/router/setupVaultUnlockGuard.spec.ts | 29 ++++++++++++++++++- 2 files changed, 32 insertions(+), 1 deletion(-) diff --git a/packages/web-runtime/src/router/setupVaultUnlockGuard.ts b/packages/web-runtime/src/router/setupVaultUnlockGuard.ts index 8dc1426ebdd..e0dd237672f 100644 --- a/packages/web-runtime/src/router/setupVaultUnlockGuard.ts +++ b/packages/web-runtime/src/router/setupVaultUnlockGuard.ts @@ -5,6 +5,7 @@ import { getVaultClaim, queryItemAsString, resolveVaultEngine, + routeToContextQuery, useExtensionRegistry, useSpacesLoading, useSpacesStore, @@ -129,11 +130,14 @@ export const setupVaultUnlockGuard = (router: Router, clientService: ClientServi // Where the user set off from, so cancelling the unlock returns them there // instead of somewhere merely adjacent to the vault. const cancelUrl = getCancelUrl(from, space, claim) + const isPublicLink = + driveAliasAndItem.startsWith('public/') || driveAliasAndItem.startsWith('ocm/') return { ...claim.unlockRoute, query: { ...(claim.unlockRoute.query || {}), + ...(isPublicLink && routeToContextQuery(to)), redirectUrl: to.fullPath, ...(cancelUrl && { cancelUrl }) } diff --git a/packages/web-runtime/tests/unit/router/setupVaultUnlockGuard.spec.ts b/packages/web-runtime/tests/unit/router/setupVaultUnlockGuard.spec.ts index 33fce51e435..22d95317d94 100644 --- a/packages/web-runtime/tests/unit/router/setupVaultUnlockGuard.spec.ts +++ b/packages/web-runtime/tests/unit/router/setupVaultUnlockGuard.spec.ts @@ -10,11 +10,12 @@ import { vi.mock('@opencloud-eu/web-pkg', async () => { const { getSpaceForDriveAliasAndItem } = await import('../../../../web-pkg/src/helpers/spaces/driveAlias') - const { queryItemAsString } = + const { queryItemAsString, routeToContextQuery } = await import('../../../../web-pkg/src/composables/appDefaults/useAppNavigation') return { getSpaceForDriveAliasAndItem, queryItemAsString, + routeToContextQuery, getVaultClaim: vi.fn(), resolveVaultEngine: vi.fn(), useExtensionRegistry: vi.fn(() => ({})), @@ -149,6 +150,32 @@ describe('setupVaultUnlockGuard', () => { }) }) + it('keeps the public link context, so anonymous visitors are not sent to the login', async () => { + const publicSpace = { id: 'token', driveAlias: 'public/token' } + const guard = installGuard({ + spaces: [publicSpace], + claim: { vaultRoot: '/my.vault', unlockRoute }, + engine: null + }) + + const result = await guard( + { + name: 'files-public-link', + params: { driveAliasAndItem: 'public/token/my.vault' }, + query: {}, + fullPath: '/files/link/public/token/my.vault' + }, + coldStart + ) + + expect(result).toMatchObject({ + query: { + contextRouteName: 'files-public-link', + contextRouteParams: { driveAliasAndItem: 'public/token/my.vault' } + } + }) + }) + it('carries where the user came from, so cancelling can return there', async () => { // e.g. opening a vault from the search results: cancelling the unlock has to // land back on the results, not next to the vault. From 57e0077fa1b7d6fda3c4b248ae6d50d159fc3f74 Mon Sep 17 00:00:00 2001 From: Alexander Ackermann Date: Wed, 7 Oct 2026 22:11:19 +0200 Subject: [PATCH 2/2] refactor(web-runtime): use isPublicSpaceResource for the vault unlock context --- packages/web-runtime/src/router/setupVaultUnlockGuard.ts | 6 ++---- .../tests/unit/router/setupVaultUnlockGuard.spec.ts | 2 +- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/packages/web-runtime/src/router/setupVaultUnlockGuard.ts b/packages/web-runtime/src/router/setupVaultUnlockGuard.ts index e0dd237672f..49975c6d0f6 100644 --- a/packages/web-runtime/src/router/setupVaultUnlockGuard.ts +++ b/packages/web-runtime/src/router/setupVaultUnlockGuard.ts @@ -11,7 +11,7 @@ import { useSpacesStore, VaultClaim } from '@opencloud-eu/web-pkg' -import { SpaceResource } from '@opencloud-eu/web-client' +import { isPublicSpaceResource, SpaceResource } from '@opencloud-eu/web-client' /** Space-relative, absolute path a `driveAliasAndItem` points at within `space`. */ function spaceRelativePath(driveAliasAndItem: string, space: SpaceResource): string { @@ -130,14 +130,12 @@ export const setupVaultUnlockGuard = (router: Router, clientService: ClientServi // Where the user set off from, so cancelling the unlock returns them there // instead of somewhere merely adjacent to the vault. const cancelUrl = getCancelUrl(from, space, claim) - const isPublicLink = - driveAliasAndItem.startsWith('public/') || driveAliasAndItem.startsWith('ocm/') return { ...claim.unlockRoute, query: { ...(claim.unlockRoute.query || {}), - ...(isPublicLink && routeToContextQuery(to)), + ...(isPublicSpaceResource(space) && routeToContextQuery(to)), redirectUrl: to.fullPath, ...(cancelUrl && { cancelUrl }) } diff --git a/packages/web-runtime/tests/unit/router/setupVaultUnlockGuard.spec.ts b/packages/web-runtime/tests/unit/router/setupVaultUnlockGuard.spec.ts index 22d95317d94..9d432bfea7d 100644 --- a/packages/web-runtime/tests/unit/router/setupVaultUnlockGuard.spec.ts +++ b/packages/web-runtime/tests/unit/router/setupVaultUnlockGuard.spec.ts @@ -151,7 +151,7 @@ describe('setupVaultUnlockGuard', () => { }) it('keeps the public link context, so anonymous visitors are not sent to the login', async () => { - const publicSpace = { id: 'token', driveAlias: 'public/token' } + const publicSpace = { id: 'token', driveAlias: 'public/token', driveType: 'public' } const guard = installGuard({ spaces: [publicSpace], claim: { vaultRoot: '/my.vault', unlockRoute },