diff --git a/packages/web-client/src/helpers/space/functions.ts b/packages/web-client/src/helpers/space/functions.ts index be3abc03cd5..0200b19a386 100644 --- a/packages/web-client/src/helpers/space/functions.ts +++ b/packages/web-client/src/helpers/space/functions.ts @@ -68,6 +68,7 @@ export function buildPublicSpaceResource( const publicLinkShareDate = data.props?.[DavProperty.PublicLinkShareDate] const publicLinkShareOwner = data.props?.[DavProperty.PublicLinkShareOwner] const publicLinkShareOwnerDisplayName = data.props?.[DavProperty.OwnerDisplayName] + const spaceId = data.props?.[DavProperty.SpaceId] let driveAlias let webDavPath @@ -97,7 +98,8 @@ export function buildPublicSpaceResource( ...(publicLinkExpiration && { publicLinkExpiration }), ...(publicLinkShareDate && { publicLinkShareDate }), ...(publicLinkShareOwner && { publicLinkShareOwner }), - ...(publicLinkShareOwnerDisplayName && { publicLinkShareOwnerDisplayName }) + ...(publicLinkShareOwnerDisplayName && { publicLinkShareOwnerDisplayName }), + ...(spaceId && { spaceId }) } ) } diff --git a/packages/web-client/src/helpers/space/types.ts b/packages/web-client/src/helpers/space/types.ts index 4782ce3f2ac..364624026d4 100644 --- a/packages/web-client/src/helpers/space/types.ts +++ b/packages/web-client/src/helpers/space/types.ts @@ -95,6 +95,7 @@ export interface PublicSpaceResource extends SpaceResource { publicLinkShareDate?: string publicLinkShareOwner?: string publicLinkShareOwnerDisplayName?: string + spaceId?: string } export const isPublicSpaceResource = (resource: Resource): resource is PublicSpaceResource => { return (resource as SpaceResource)?.driveType === 'public' diff --git a/packages/web-client/src/webdav/constants/dav.ts b/packages/web-client/src/webdav/constants/dav.ts index eac88f5e979..4078bd0c1c6 100644 --- a/packages/web-client/src/webdav/constants/dav.ts +++ b/packages/web-client/src/webdav/constants/dav.ts @@ -105,7 +105,8 @@ const DavPropertyMapping = { PublicLinkPermission: defString('public-link-permission' as const), PublicLinkExpiration: defString('public-link-expiration' as const), PublicLinkShareDate: defString('public-link-share-datetime' as const), - PublicLinkShareOwner: defString('public-link-share-owner' as const) + PublicLinkShareOwner: defString('public-link-share-owner' as const), + SpaceId: defString('spaceid' as const) } as const satisfies Record> type DavPropertyMappingType = typeof DavPropertyMapping @@ -156,7 +157,10 @@ export abstract class DavProperties { DavProperty.PublicLinkPermission, DavProperty.PublicLinkExpiration, DavProperty.PublicLinkShareDate, - DavProperty.PublicLinkShareOwner + DavProperty.PublicLinkShareOwner, + DavProperty.SpaceId, + DavProperty.FileId, + DavProperty.FileParent ]) static readonly Trashbin: DavPropertyValue[] = [ diff --git a/packages/web-pkg/src/services/client/client.ts b/packages/web-pkg/src/services/client/client.ts index 0ce9300fbe0..5ca6be69ee9 100644 --- a/packages/web-pkg/src/services/client/client.ts +++ b/packages/web-pkg/src/services/client/client.ts @@ -48,6 +48,8 @@ export class ClientService { 'X-Requested-With': 'XMLHttpRequest' } + public sseUnAuthenticated?: EventSource + constructor(options: ClientServiceOptions) { this.configStore = options.configStore this.language = options.language @@ -188,4 +190,19 @@ export class ClientService { return Promise.reject(error) } + + initSseUnAuthenticated(publicLinkToken: string, publicLinkPassword?: string) { + this.sseUnAuthenticated = sse(this.configStore.serverUrl, { + headers: { + 'Accept-Language': this.currentLanguage, + 'X-Request-ID': uuidV4(), + 'X-Requested-With': 'XMLHttpRequest', + 'public-token': publicLinkToken, + ...(publicLinkPassword && { + Authorization: + 'Basic ' + Buffer.from(['public', publicLinkPassword].join(':')).toString('base64') + }) + } + }) + } } diff --git a/packages/web-runtime/src/container/bootstrap.ts b/packages/web-runtime/src/container/bootstrap.ts index c2ea9e4133c..d0aa12a4d14 100644 --- a/packages/web-runtime/src/container/bootstrap.ts +++ b/packages/web-runtime/src/container/bootstrap.ts @@ -740,7 +740,9 @@ export const registerSSEEventListeners = ({ previewService, configStore, userStore, - router + router, + publicLinkToken, + publicLinkPassword }: { language: Language resourcesStore: ResourcesStore @@ -752,6 +754,8 @@ export const registerSSEEventListeners = ({ configStore: ConfigStore userStore: UserStore router: Router + publicLinkToken?: string + publicLinkPassword?: string }): void => { const resourceQueue = new PQueue({ concurrency: configStore.options.concurrentRequests.sse @@ -778,7 +782,16 @@ export const registerSSEEventListeners = ({ resourceQueue } satisfies Partial - clientService.sseAuthenticated.addEventListener(MESSAGE_TYPE.ITEM_RENAMED, (msg) => + let sse: EventSource + + if (publicLinkToken) { + clientService.initSseUnAuthenticated(publicLinkToken, publicLinkPassword) + sse = clientService.sseUnAuthenticated + } else { + sse = clientService.sseAuthenticated + } + + sse.addEventListener(MESSAGE_TYPE.ITEM_RENAMED, (msg) => sseEventWrapper({ topic: MESSAGE_TYPE.ITEM_RENAMED, msg, @@ -787,7 +800,7 @@ export const registerSSEEventListeners = ({ }) ) - clientService.sseAuthenticated.addEventListener(MESSAGE_TYPE.POSTPROCESSING_FINISHED, (msg) => + sse.addEventListener(MESSAGE_TYPE.POSTPROCESSING_FINISHED, (msg) => sseEventWrapper({ topic: MESSAGE_TYPE.POSTPROCESSING_FINISHED, msg, @@ -796,7 +809,7 @@ export const registerSSEEventListeners = ({ }) ) - clientService.sseAuthenticated.addEventListener(MESSAGE_TYPE.FILE_LOCKED, (msg) => + sse.addEventListener(MESSAGE_TYPE.FILE_LOCKED, (msg) => sseEventWrapper({ topic: MESSAGE_TYPE.FILE_LOCKED, msg, @@ -805,7 +818,7 @@ export const registerSSEEventListeners = ({ }) ) - clientService.sseAuthenticated.addEventListener(MESSAGE_TYPE.FILE_UNLOCKED, (msg) => + sse.addEventListener(MESSAGE_TYPE.FILE_UNLOCKED, (msg) => sseEventWrapper({ topic: MESSAGE_TYPE.FILE_UNLOCKED, msg, @@ -814,7 +827,7 @@ export const registerSSEEventListeners = ({ }) ) - clientService.sseAuthenticated.addEventListener(MESSAGE_TYPE.ITEM_TRASHED, (msg) => + sse.addEventListener(MESSAGE_TYPE.ITEM_TRASHED, (msg) => sseEventWrapper({ topic: MESSAGE_TYPE.ITEM_TRASHED, msg, @@ -823,7 +836,7 @@ export const registerSSEEventListeners = ({ }) ) - clientService.sseAuthenticated.addEventListener(MESSAGE_TYPE.ITEM_RESTORED, (msg) => + sse.addEventListener(MESSAGE_TYPE.ITEM_RESTORED, (msg) => sseEventWrapper({ topic: MESSAGE_TYPE.ITEM_RESTORED, msg, @@ -832,7 +845,7 @@ export const registerSSEEventListeners = ({ }) ) - clientService.sseAuthenticated.addEventListener(MESSAGE_TYPE.ITEM_MOVED, (msg) => + sse.addEventListener(MESSAGE_TYPE.ITEM_MOVED, (msg) => sseEventWrapper({ topic: MESSAGE_TYPE.ITEM_MOVED, msg, @@ -841,7 +854,7 @@ export const registerSSEEventListeners = ({ }) ) - clientService.sseAuthenticated.addEventListener(MESSAGE_TYPE.FOLDER_CREATED, (msg) => + sse.addEventListener(MESSAGE_TYPE.FOLDER_CREATED, (msg) => sseEventWrapper({ topic: MESSAGE_TYPE.FOLDER_CREATED, msg, @@ -850,7 +863,7 @@ export const registerSSEEventListeners = ({ }) ) - clientService.sseAuthenticated.addEventListener(MESSAGE_TYPE.FILE_TOUCHED, (msg) => + sse.addEventListener(MESSAGE_TYPE.FILE_TOUCHED, (msg) => sseEventWrapper({ topic: MESSAGE_TYPE.FILE_TOUCHED, msg, @@ -859,7 +872,7 @@ export const registerSSEEventListeners = ({ }) ) - clientService.sseAuthenticated.addEventListener(MESSAGE_TYPE.SPACE_MEMBER_ADDED, (msg) => + sse.addEventListener(MESSAGE_TYPE.SPACE_MEMBER_ADDED, (msg) => sseEventWrapper({ topic: MESSAGE_TYPE.SPACE_MEMBER_ADDED, msg, @@ -868,7 +881,7 @@ export const registerSSEEventListeners = ({ }) ) - clientService.sseAuthenticated.addEventListener(MESSAGE_TYPE.SPACE_MEMBER_REMOVED, (msg) => + sse.addEventListener(MESSAGE_TYPE.SPACE_MEMBER_REMOVED, (msg) => sseEventWrapper({ topic: MESSAGE_TYPE.SPACE_MEMBER_REMOVED, msg, @@ -877,7 +890,7 @@ export const registerSSEEventListeners = ({ }) ) - clientService.sseAuthenticated.addEventListener(MESSAGE_TYPE.SPACE_SHARE_UPDATED, (msg) => + sse.addEventListener(MESSAGE_TYPE.SPACE_SHARE_UPDATED, (msg) => sseEventWrapper({ topic: MESSAGE_TYPE.SPACE_SHARE_UPDATED, msg, @@ -886,7 +899,7 @@ export const registerSSEEventListeners = ({ }) ) - clientService.sseAuthenticated.addEventListener(MESSAGE_TYPE.SHARE_CREATED, (msg) => + sse.addEventListener(MESSAGE_TYPE.SHARE_CREATED, (msg) => sseEventWrapper({ topic: MESSAGE_TYPE.SHARE_CREATED, msg, @@ -895,7 +908,7 @@ export const registerSSEEventListeners = ({ }) ) - clientService.sseAuthenticated.addEventListener(MESSAGE_TYPE.SHARE_REMOVED, (msg) => + sse.addEventListener(MESSAGE_TYPE.SHARE_REMOVED, (msg) => sseEventWrapper({ topic: MESSAGE_TYPE.SHARE_REMOVED, msg, @@ -904,7 +917,7 @@ export const registerSSEEventListeners = ({ }) ) - clientService.sseAuthenticated.addEventListener(MESSAGE_TYPE.SHARE_UPDATED, (msg) => + sse.addEventListener(MESSAGE_TYPE.SHARE_UPDATED, (msg) => sseEventWrapper({ topic: MESSAGE_TYPE.SHARE_UPDATED, msg, @@ -913,7 +926,7 @@ export const registerSSEEventListeners = ({ }) ) - clientService.sseAuthenticated.addEventListener(MESSAGE_TYPE.LINK_CREATED, (msg) => + sse.addEventListener(MESSAGE_TYPE.LINK_CREATED, (msg) => sseEventWrapper({ topic: MESSAGE_TYPE.LINK_CREATED, msg, @@ -922,7 +935,7 @@ export const registerSSEEventListeners = ({ }) ) - clientService.sseAuthenticated.addEventListener(MESSAGE_TYPE.LINK_REMOVED, (msg) => + sse.addEventListener(MESSAGE_TYPE.LINK_REMOVED, (msg) => sseEventWrapper({ topic: MESSAGE_TYPE.LINK_REMOVED, msg, @@ -931,7 +944,7 @@ export const registerSSEEventListeners = ({ }) ) - clientService.sseAuthenticated.addEventListener(MESSAGE_TYPE.LINK_UPDATED, (msg) => + sse.addEventListener(MESSAGE_TYPE.LINK_UPDATED, (msg) => sseEventWrapper({ topic: MESSAGE_TYPE.LINK_UPDATED, msg, @@ -940,7 +953,7 @@ export const registerSSEEventListeners = ({ }) ) - clientService.sseAuthenticated.addEventListener(MESSAGE_TYPE.BACKCHANNEL_LOGOUT, (msg) => + sse.addEventListener(MESSAGE_TYPE.BACKCHANNEL_LOGOUT, (msg) => sseEventWrapper({ topic: MESSAGE_TYPE.BACKCHANNEL_LOGOUT, msg, diff --git a/packages/web-runtime/src/container/sse/files.ts b/packages/web-runtime/src/container/sse/files.ts index 5c25ed8d9e9..7e91f357e6e 100644 --- a/packages/web-runtime/src/container/sse/files.ts +++ b/packages/web-runtime/src/container/sse/files.ts @@ -1,6 +1,7 @@ import { createFileRouteOptions, ImageDimension } from '@ownclouders/web-pkg' import { SSEEventOptions } from './types' import { isItemInCurrentFolder } from './helpers' +import { isPublicSpaceResource } from '@ownclouders/web-client' export const onSSEItemRenamedEvent = async ({ sseData, @@ -23,7 +24,13 @@ export const onSSEItemRenamedEvent = async ({ if (!resource) { return } - const space = spacesStore.spaces.find((s) => s.id === resource.storageId) + const space = spacesStore.spaces.find((s) => { + if (isPublicSpaceResource(s)) { + return s.spaceId === resource.storageId + } + + return s.id === resource.storageId + }) if (!space) { return @@ -54,7 +61,12 @@ export const onSSEFileLockingEvent = async ({ clientService }: SSEEventOptions) => { const resource = resourcesStore.resources.find((f) => f.id === sseData.itemid) - const space = spacesStore.spaces.find((s) => s.id === resource?.storageId) + const space = spacesStore.spaces.find((s) => { + if (isPublicSpaceResource(s)) { + return s.spaceId === resource?.storageId + } + return s.id === resource?.storageId + }) if (!resource || !space) { return @@ -80,7 +92,12 @@ export const onSSEProcessingFinishedEvent = async ({ return false } const resource = resourcesStore.resources.find((f) => f.id === sseData.itemid) - const space = spacesStore.spaces.find((s) => s.id === sseData.spaceid) + const space = spacesStore.spaces.find((s) => { + if (isPublicSpaceResource(s)) { + return s.spaceId === sseData.spaceid + } + return s.id === sseData.spaceid + }) if (!space) { return } @@ -187,7 +204,12 @@ export const onSSEItemRestoredEvent = async ({ return } - const space = spacesStore.spaces.find((space) => space.id === sseData.spaceid) + const space = spacesStore.spaces.find((space) => { + if (isPublicSpaceResource(space)) { + return space.spaceId === sseData.spaceid + } + return space.id === sseData.spaceid + }) if (!space) { return } @@ -257,7 +279,12 @@ export const onSSEFileTouchedEvent = async ({ return } - const space = spacesStore.spaces.find((space) => space.id === sseData.spaceid) + const space = spacesStore.spaces.find((space) => { + if (isPublicSpaceResource(space)) { + return space.spaceId === sseData.spaceid + } + return space.id === sseData.spaceid + }) if (!space) { return } @@ -289,7 +316,12 @@ export const onSSEFolderCreatedEvent = async ({ return } - const space = spacesStore.spaces.find((space) => space.id === sseData.spaceid) + const space = spacesStore.spaces.find((space) => { + if (isPublicSpaceResource(space)) { + return space.spaceId === sseData.spaceid + } + return space.id === sseData.spaceid + }) if (!space) { return } @@ -298,7 +330,6 @@ export const onSSEFolderCreatedEvent = async ({ path: '', fileId: sseData.itemid }) - if (!resource) { return } diff --git a/packages/web-runtime/src/index.ts b/packages/web-runtime/src/index.ts index eb980dea4d2..780ccab68c5 100644 --- a/packages/web-runtime/src/index.ts +++ b/packages/web-runtime/src/index.ts @@ -257,6 +257,25 @@ export const bootstrapApp = async (configurationPath: string, appsReadyCallback: const publicLinkPassword = authStore.publicLinkPassword const publicLinkType = authStore.publicLinkType + const previewService = app.config.globalProperties.$previewService + + if (capabilityStore.supportSSE) { + registerSSEEventListeners({ + language: gettext, + resourcesStore, + spacesStore, + messageStore: messagesStore, + sharesStore, + clientService, + userStore, + previewService, + configStore, + router, + publicLinkToken, + publicLinkPassword + }) + } + const space = buildPublicSpaceResource({ id: publicLinkToken, name: app.config.globalProperties.$gettext('Public files'),