From bfa69ca4f78481ca50a8ce5801c179c1abda97ec Mon Sep 17 00:00:00 2001 From: Dominik Schmidt Date: Wed, 12 Nov 2025 16:35:17 +0100 Subject: [PATCH 1/6] feat: share links and passwords in embed mode --- .../src/components/CreateLinkModal.vue | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/packages/web-pkg/src/components/CreateLinkModal.vue b/packages/web-pkg/src/components/CreateLinkModal.vue index 6c01302f0a1..e94de6f52e6 100644 --- a/packages/web-pkg/src/components/CreateLinkModal.vue +++ b/packages/web-pkg/src/components/CreateLinkModal.vue @@ -106,7 +106,7 @@ isFolder }) " - >{{ $gettext('Copy link and password') }} + >{{ confirmPasswordButtonText }} @@ -193,6 +193,13 @@ export default defineComponent({ return $gettext('Copy link') }) + const confirmPasswordButtonText = computed(() => { + if (unref(isEmbedEnabled)) { + return $gettext('Share link(s) and password(s)') + } + return $gettext('Copy link and password') + }) + const passwordInputKey = ref(uuidV4()) const roleRefs = ref>({}) @@ -265,12 +272,21 @@ export default defineComponent({ const result = await createLinks() const succeeded = result.filter(({ status }) => status === 'fulfilled') + // **DEPRECATED**: Always emit the share url for backwards compatibility if (succeeded.length && unref(isEmbedEnabled)) { postMessage( 'owncloud-embed:share', (succeeded as PromiseFulfilledResult[]).map(({ value }) => value.webUrl) ) } + // Always emit new event with objects, include password only when copyPassword is enabled + postMessage>( + 'owncloud-embed:share-links', + (succeeded as PromiseFulfilledResult[]).map(({ value }) => ({ + url: value.webUrl, + ...(options.copyPassword && { password: password.value }) + })) + ) const userFacingErrors: Error[] = [] const failed = result.filter(({ status }) => status === 'rejected') @@ -350,6 +366,7 @@ export default defineComponent({ updatePassword, getLinkRoleByType, confirmButtonText, + confirmPasswordButtonText, isAdvancedMode, setAdvancedMode, onExpiryDateChanged, From 5d4052dc93cb19a107b2e23cdfd5e3fa6d64e919 Mon Sep 17 00:00:00 2001 From: Rodrigo Date: Mon, 2 Feb 2026 10:22:52 +0100 Subject: [PATCH 2/6] feat: embed messages origin configurable via URI --- packages/web-pkg/src/composables/embedMode/useEmbedMode.ts | 4 +++- packages/web-runtime/src/container/bootstrap.ts | 6 ++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/packages/web-pkg/src/composables/embedMode/useEmbedMode.ts b/packages/web-pkg/src/composables/embedMode/useEmbedMode.ts index f7c5ce2ceda..fc631d0f384 100644 --- a/packages/web-pkg/src/composables/embedMode/useEmbedMode.ts +++ b/packages/web-pkg/src/composables/embedMode/useEmbedMode.ts @@ -39,7 +39,9 @@ export const useEmbedMode = () => { return configStore.options.embed?.fileTypes }) - const messagesTargetOrigin = computed(() => configStore.options.embed?.messagesOrigin) + const messagesTargetOrigin = computed(() => { + return configStore.options.embed?.messagesOrigin + }) const isDelegatingAuthentication = computed( () => unref(isEnabled) && configStore.options.embed?.delegateAuthentication diff --git a/packages/web-runtime/src/container/bootstrap.ts b/packages/web-runtime/src/container/bootstrap.ts index 7514ed345c3..2715247c645 100644 --- a/packages/web-runtime/src/container/bootstrap.ts +++ b/packages/web-runtime/src/container/bootstrap.ts @@ -125,6 +125,12 @@ const getEmbedConfigFromQuery = ( config.delegateAuthenticationOrigin = delegateAuthenticationOrigin } + const messagesOrigin = getQueryParam('embed-messages-origin') + + if (messagesOrigin) { + config.messagesOrigin = messagesOrigin + } + return config } From 221fad963c4a045c1f6687c86f351ab61776478e Mon Sep 17 00:00:00 2001 From: Diogo Castro Date: Wed, 13 May 2026 15:34:27 +0200 Subject: [PATCH 3/6] Returns signed urls on embed mode file picker To allow them to be downloaded without the user token. --- .../components/EmbedActions/EmbedActions.vue | 66 +++++++++++++++---- 1 file changed, 52 insertions(+), 14 deletions(-) diff --git a/packages/web-app-files/src/components/EmbedActions/EmbedActions.vue b/packages/web-app-files/src/components/EmbedActions/EmbedActions.vue index ca7eece48fb..74748f35b07 100644 --- a/packages/web-app-files/src/components/EmbedActions/EmbedActions.vue +++ b/packages/web-app-files/src/components/EmbedActions/EmbedActions.vue @@ -36,9 +36,9 @@ data-testid="button-select" variation="inverse" appearance="filled" - :disabled="areSelectActionsDisabled" + :disabled="areSelectActionsDisabled || signing" @click="emitSelect" - >{{ selectLabel }} + >{{ signing ? $gettext('Preparing…') : selectLabel }} @@ -51,11 +51,14 @@ import { FileAction, routeToContextQuery, useAbility, + useCapabilityStore, + useClientService, useEmbedMode, useFileActionsCreateLink, useResourcesStore, useRouter, - useSpacesStore + useSpacesStore, + useUserStore } from '@ownclouders/web-pkg' import { Resource } from '@ownclouders/web-client' import { useGettext } from 'vue3-gettext' @@ -87,6 +90,11 @@ export default defineComponent({ return unref(selectedResources) }) + const capabilityStore = useCapabilityStore() + const clientService = useClientService() + const userStore = useUserStore() + const signing = ref(false) + const { actions: createLinkActions } = useFileActionsCreateLink({ enforceModal: true }) const createLinkAction = computed(() => unref(createLinkActions)[0]) @@ -102,22 +110,51 @@ export default defineComponent({ return [0, unref(fileName).split('.')[0].length] as [number, number] }) - const emitSelect = (): void => { - if (unref(chooseFileName)) { - postMessage('owncloud-embed:select', { - resources: JSON.parse(JSON.stringify(selectedFiles.value)), - fileName: unref(fileName), - locationQuery: JSON.parse(JSON.stringify(routeToContextQuery(unref(router.currentRoute)))) - }) + const withSignedUrls = async (resources: Resource[]): Promise => { + if (!capabilityStore.supportUrlSigning || !unref(space)) { + return resources } - // TODO: adjust type to embedModeLocationPickMessageData later (breaking) - postMessage( - 'owncloud-embed:select', - JSON.parse(JSON.stringify(selectedFiles.value)) + return Promise.all( + resources.map(async (resource) => { + if (resource.type === 'folder') { + return resource + } + try { + const signedUrl = await clientService.webdav.getFileUrl(unref(space), resource, { + isUrlSigningEnabled: true, + username: userStore.user?.onPremisesSamAccountName + }) + return { ...resource, downloadURL: signedUrl } + } catch { + return resource + } + }) ) } + const emitSelect = async (): Promise => { + signing.value = true + try { + const resources = await withSignedUrls(JSON.parse(JSON.stringify(selectedFiles.value))) + + if (unref(chooseFileName)) { + postMessage('owncloud-embed:select', { + resources, + fileName: unref(fileName), + locationQuery: JSON.parse( + JSON.stringify(routeToContextQuery(unref(router.currentRoute))) + ) + }) + } + + // TODO: adjust type to embedModeLocationPickMessageData later (breaking) + postMessage('owncloud-embed:select', resources) + } finally { + signing.value = false + } + } + const emitCancel = (): void => { postMessage('owncloud-embed:cancel', null) } @@ -133,6 +170,7 @@ export default defineComponent({ selectLabel, emitCancel, emitSelect, + signing, space, createLinkAction, fileName, From fb698635e62fcbb8d894003f2000f375b42e4b9b Mon Sep 17 00:00:00 2001 From: Diogo Castro Date: Wed, 13 May 2026 15:55:04 +0200 Subject: [PATCH 4/6] Inline attach embed mode Allows embeding the UI and delegating the attach action (via a post message). Users have to select files, and the application will then ask cernbox to return the list of files selected with the respective download urls. --- .../components/EmbedActions/EmbedActions.vue | 26 ++++++++++++++++--- .../src/composables/embedMode/useEmbedMode.ts | 5 ++++ 2 files changed, 28 insertions(+), 3 deletions(-) diff --git a/packages/web-app-files/src/components/EmbedActions/EmbedActions.vue b/packages/web-app-files/src/components/EmbedActions/EmbedActions.vue index 74748f35b07..5f5696d0abe 100644 --- a/packages/web-app-files/src/components/EmbedActions/EmbedActions.vue +++ b/packages/web-app-files/src/components/EmbedActions/EmbedActions.vue @@ -1,5 +1,5 @@