feat(collaboration): send DownloadUrl outside of secure view

This commit is contained in:
Florian Schade committed 2026-10-16 11:29:07 +02:00
1 parent a4cf381fbb
commit e1cfacb2dd
3 files changed
+44

No files matched your search

@@ -1375,6 +1375,15 @@ func (f *FileConnector) CheckFileInfo(ctx context.Context) (*ConnectorResponse,
infoMap[fileinfo.KeyUserExtraInfo] = extraInfo
}
// secure view exists to keep the original file from the user, so it gets no download link
if wopiContext.ViewOnlyToken == "" {
if du, err := f.createFileDownloadURL(wopiContext, collaborationURL); err == nil {
infoMap[fileinfo.KeyDownloadURL] = du
} else {
logger.Error().Err(err).Msg("CheckFileInfo: failed to create the download URL")
}
}
// if the file content is empty and a template reference is set, add the template source URL
if wopiContext.TemplateReference != nil && statRes.GetInfo().GetSize() == 0 {
if tu, err := f.createDownloadURL(wopiContext, collaborationURL); err == nil {
@@ -1412,6 +1421,25 @@ func (f *FileConnector) createDownloadURL(wopiContext middleware.WopiContext, co
return downloadURL.String(), nil
}
// createFileDownloadURL builds a URL to the WOPI contents of the file, authorized by a WOPI token.
func (f *FileConnector) createFileDownloadURL(wopiContext middleware.WopiContext, collaborationURL *url.URL) (string, error) {
token, _, err := middleware.GenerateWopiToken(wopiContext, f.cfg, f.store)
if err != nil {
return "", err
}
downloadURL := *collaborationURL
downloadURL.Path = path.Join(
collaborationURL.Path,
"wopi/files/",
helpers.HashResourceId(wopiContext.FileReference.GetResourceId()),
"contents",
)
q := downloadURL.Query()
q.Add("access_token", token)
downloadURL.RawQuery = q.Encode()
return downloadURL.String(), nil
}
// createAvatarURL builds a WOPI-proxied avatar URL for the given user.
// The collaboration service's /wopi/avatars/ endpoint will fetch the avatar
// from the Graph API using the WOPI token for authentication.
@@ -1768,6 +1768,10 @@ var _ = Describe("FileConnector", func() {
response, err := fc.CheckFileInfo(ctx)
Expect(err).ToNot(HaveOccurred())
Expect(response.Status).To(Equal(200))
// DownloadURL carries a fresh WOPI token, so check its shape separately
Expect(response.Body.(*fileinfo.Microsoft).DownloadURL).To(HavePrefix("https://wopi.opencloud.test/wopi/files/"))
Expect(response.Body.(*fileinfo.Microsoft).DownloadURL).To(ContainSubstring("/contents?access_token="))
response.Body.(*fileinfo.Microsoft).DownloadURL = ""
Expect(response.Body.(*fileinfo.Microsoft)).To(Equal(expectedFileInfo))
})
@@ -1862,6 +1866,10 @@ var _ = Describe("FileConnector", func() {
// overwrite UserID and UserFriendlyName here for easier matching
response.Body.(*fileinfo.Collabora).UserID = "guest-zzz000"
response.Body.(*fileinfo.Collabora).UserFriendlyName = "guest zzz000"
// DownloadURL carries a fresh WOPI token, so check its shape separately
Expect(response.Body.(*fileinfo.Collabora).DownloadURL).To(HavePrefix("https://wopi.opencloud.test/wopi/files/"))
Expect(response.Body.(*fileinfo.Collabora).DownloadURL).To(ContainSubstring("/contents?access_token="))
response.Body.(*fileinfo.Collabora).DownloadURL = ""
Expect(err).ToNot(HaveOccurred())
Expect(response.Status).To(Equal(200))
@@ -2182,6 +2190,10 @@ var _ = Describe("FileConnector", func() {
Expect(body.UserExtraInfo).ToNot(BeNil())
Expect(body.UserExtraInfo.Avatar).To(ContainSubstring("/wopi/avatars/aabbcc?access_token="))
Expect(body.UserExtraInfo.Mail).To(Equal("shaft@example.com"))
// DownloadURL carries a fresh WOPI token, so check its shape separately
Expect(body.DownloadURL).To(HavePrefix("https://wopi.opencloud.test/wopi/files/"))
Expect(body.DownloadURL).To(ContainSubstring("/contents?access_token="))
body.DownloadURL = ""
// Clear dynamic fields for struct comparison
body.UserExtraInfo.Avatar = ""
expectedFileInfo.UserExtraInfo.Avatar = ""
@@ -52,6 +52,8 @@ type Collabora struct {
// The page to navigate to when the editor closes or fails unrecoverably.
CloseURL string `json:"CloseUrl,omitempty"`
// A link to download the original file.
DownloadURL string `json:"DownloadUrl,omitempty"`
// The page that lets the user share the file.
FileSharingURL string `json:"FileSharingUrl,omitempty"`
// The page that shows the version history of the file.
@@ -170,6 +172,8 @@ func (cinfo *Collabora) SetProperties(props map[string]any) {
case KeyCloseURL:
cinfo.CloseURL = value.(string)
case KeyDownloadURL:
cinfo.DownloadURL = value.(string)
case KeyFileSharingURL:
cinfo.FileSharingURL = value.(string)
case KeyFileVersionURL: