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
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@
"@sentry/react": "7.119.0",
"classnames": "2.3.1",
"cozy-bar": "^29.3.0",
"cozy-client": "^60.23.0",
"cozy-client": "^60.23.1",
"cozy-dataproxy-lib": "^4.13.0",
"cozy-device-helper": "^4.0.1",
"cozy-devtools": "^1.2.1",
Expand Down
11 changes: 8 additions & 3 deletions src/modules/navigation/PublicNoteRedirect.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import React, { FC, useEffect, useState } from 'react'
import { useParams } from 'react-router-dom'
import { useLocation, useParams } from 'react-router-dom'
import { useI18n } from 'twake-i18n'

import { useClient } from 'cozy-client'
Expand All @@ -15,6 +15,7 @@ import { DummyLayout } from '@/modules/layout/DummyLayout'
const PublicNoteRedirect: FC = () => {
const { t } = useI18n()
const { fileId, driveId } = useParams()
const { search } = useLocation()
const client = useClient()

const [noteUrl, setNoteUrl] = useState<string | null>(null)
Expand All @@ -28,6 +29,9 @@ const PublicNoteRedirect: FC = () => {

try {
// Inside notes, we need to add / at the end of /public/ or /preview/ to avoid 409 error
const searchParams = new URLSearchParams(search)
const returnUrl = searchParams.get('returnUrl')

const pathname =
location.pathname === '/'
? '/public/'
Expand All @@ -39,7 +43,8 @@ const PublicNoteRedirect: FC = () => {
},
{
driveId,
pathname
pathname,
returnUrl
}
)
setNoteUrl(url)
Expand All @@ -52,7 +57,7 @@ const PublicNoteRedirect: FC = () => {
if (fileId) {
void fetchNoteUrl(fileId)
}
}, [fileId, driveId, client])
}, [search, fileId, driveId, client])

if (noteUrl) {
window.location.href = noteUrl
Expand Down
2 changes: 1 addition & 1 deletion src/modules/navigation/hooks/helpers.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -238,7 +238,7 @@ describe('computePath', () => {
const file = { _id: 'note123', driveId: 'drive456' }
expect(
computePath(file, { type: 'public-note', pathname: '/public' })
).toBe('/note/drive456/note123')
).toBe('/note/drive456/note123?returnUrl=')
})

it('should return correct path for public-note-same-instance', () => {
Expand Down
17 changes: 15 additions & 2 deletions src/modules/navigation/hooks/helpers.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import CozyClient from 'cozy-client'
import {
isShortcut,
isNote,
Expand All @@ -14,6 +15,7 @@ import {
isNextcloudShortcut,
isNextcloudFile
} from '@/modules/nextcloud/helpers'
import { makeSharedDriveNoteReturnUrl } from '@/modules/shareddrives/helpers'
import { makeOnlyOfficeFileRoute } from '@/modules/views/OnlyOffice/helpers'

interface ComputeFileTypeOptions {
Expand All @@ -26,6 +28,7 @@ interface ComputePathOptions {
type: string
pathname: string
isPublic: boolean
client: CozyClient | null
}

export const computeFileType = (
Expand Down Expand Up @@ -92,7 +95,7 @@ export const computeApp = (type: string): string => {

export const computePath = (
file: File,
{ type, pathname, isPublic }: ComputePathOptions
{ type, pathname, isPublic, client }: ComputePathOptions
): string => {
const paths = pathname.split('/').slice(1)
const driveId = file.driveId as string | undefined
Expand All @@ -114,7 +117,17 @@ export const computePath = (
case 'public-note-same-instance':
return `/?id=${file._id}`
case 'public-note':
return driveId ? `/note/${driveId}/${file._id}` : `/note/${file._id}`
if (driveId) {
const returnUrl = client
? makeSharedDriveNoteReturnUrl(client, file as IOCozyFile)
: ''

return `/note/${driveId}/${file._id}?returnUrl=${encodeURIComponent(
returnUrl
)}`
} else {
return `/note/${file._id}`
}
Comment on lines +120 to +130
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Empty returnUrl query parameter when client is null.

When driveId exists but client is null, returnUrl becomes an empty string, resulting in a URL like /note/{driveId}/{fileId}?returnUrl=. This empty query parameter may be unintended and could cause issues in the notes app when parsing.

Consider only appending the returnUrl parameter when it has a value.

🔧 Conditionally append returnUrl
     case 'public-note':
       if (driveId) {
         const returnUrl = client
           ? makeSharedDriveNoteReturnUrl(client, file as IOCozyFile)
           : ''

-        return `/note/${driveId}/${file._id}?returnUrl=${encodeURIComponent(
-          returnUrl
-        )}`
+        const basePath = `/note/${driveId}/${file._id}`
+        return returnUrl
+          ? `${basePath}?returnUrl=${encodeURIComponent(returnUrl)}`
+          : basePath
       } else {
         return `/note/${file._id}`
       }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if (driveId) {
const returnUrl = client
? makeSharedDriveNoteReturnUrl(client, file as IOCozyFile)
: ''
return `/note/${driveId}/${file._id}?returnUrl=${encodeURIComponent(
returnUrl
)}`
} else {
return `/note/${file._id}`
}
if (driveId) {
const returnUrl = client
? makeSharedDriveNoteReturnUrl(client, file as IOCozyFile)
: ''
const basePath = `/note/${driveId}/${file._id}`
return returnUrl
? `${basePath}?returnUrl=${encodeURIComponent(returnUrl)}`
: basePath
} else {
return `/note/${file._id}`
}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/modules/navigation/hooks/helpers.ts` around lines 120 - 130, The URL
builder in the block referencing driveId, client, makeSharedDriveNoteReturnUrl
and file currently always appends a returnUrl query parameter (empty when client
is null); change the logic so you only add ?returnUrl=... when returnUrl is a
non-empty string: compute returnUrl via makeSharedDriveNoteReturnUrl(client,
file) only if client exists, then build `/note/${driveId}/${file._id}` and
append `?returnUrl=${encodeURIComponent(returnUrl)}` only when returnUrl is
truthy (omit the entire query string when it is empty or undefined).

case 'docs':
// eslint-disable-next-line no-case-declarations, @typescript-eslint/restrict-template-expressions
return `/bridge/docs/${(file as IOCozyFile).metadata.externalId}`
Expand Down
3 changes: 2 additions & 1 deletion src/modules/navigation/hooks/useFileLink.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,8 @@ const useFileLink = (
const path = computePath(file, {
type,
pathname,
isPublic
isPublic,
client
})

const shouldBeOpenedInNewTab =
Expand Down
17 changes: 17 additions & 0 deletions src/modules/shareddrives/helpers.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import CozyClient, { generateWebLink } from 'cozy-client'
import { IOCozyFile } from 'cozy-client/types/types'

// Temporary type, need to be completed and then put in cozy-client
Expand Down Expand Up @@ -37,4 +38,20 @@
}

export const isFromSharedDriveRecipient = (folder: IOCozyFile): boolean =>
folder && Boolean(folder.driveId)

Check warning on line 41 in src/modules/shareddrives/helpers.ts

View workflow job for this annotation

GitHub Actions / Build and publish

Unnecessary conditional, value is always truthy

export const makeSharedDriveNoteReturnUrl = (
client: CozyClient,
file: IOCozyFile
): string => {
return generateWebLink({
slug: 'drive',
searchParams: [],
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
cozyUrl: client.getStackClient().uri as string,
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
subDomainType: client.getInstanceOptions().subdomain,
pathname: '',
hash: `/shareddrive/${file.driveId!}/${file.dir_id}`

Check warning on line 55 in src/modules/shareddrives/helpers.ts

View workflow job for this annotation

GitHub Actions / Build and publish

Forbidden non-null assertion
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

file.dir_id is used without validation.

Similar to driveId, dir_id could be undefined (e.g., for root-level items), which would result in a malformed URL containing the literal string "undefined".

🛡️ Add validation for dir_id
 export const makeSharedDriveNoteReturnUrl = (
   client: CozyClient,
   file: IOCozyFile
 ): string => {
+  if (!file.driveId || !file.dir_id) {
+    throw new Error('driveId and dir_id are required to generate shared drive return URL')
+  }
   return generateWebLink({
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/modules/shareddrives/helpers.ts` at line 55, The hash generation uses
file.dir_id directly which can be undefined and produce "undefined" in the URL;
update the code that builds the hash (the template literal where hash:
`/shareddrive/${file.driveId!}/${file.dir_id}`) to validate file.dir_id first
and use a safe fallback (e.g., empty string or a designated "root" token) or
conditionally omit the segment so the produced path never contains the literal
"undefined"; ensure the same validation pattern is applied wherever file.dir_id
is used for URL/path construction.

})
}
8 changes: 4 additions & 4 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -5861,10 +5861,10 @@ cozy-client@^60.20.0:
sift "^6.0.0"
url-search-params-polyfill "^8.0.0"

cozy-client@^60.23.0:
version "60.23.0"
resolved "https://registry.yarnpkg.com/cozy-client/-/cozy-client-60.23.0.tgz#fa91e9bfee9bf0c56c2b49300c0d6ba628544321"
integrity sha512-JuoJRTbjwwMpmnLnSWGa0ZFekOcr3nwXieG5T5M9M/ISmAYI3ypR474zkNPbhq0J1OjYCSGxThBBpv45HPKBDA==
cozy-client@^60.23.1:
version "60.23.1"
resolved "https://registry.yarnpkg.com/cozy-client/-/cozy-client-60.23.1.tgz#009d056973769af69c0e9fe7386cda6c3d0aea3c"
integrity sha512-6Kw3exQxvfKCgmemdh8NqX9IZECj/W+QP+DYF8E4lniadXGWsY3drg2oNhyKwHHea+lRU2fEt776Pr0de6ZjTg==
dependencies:
"@cozy/minilog" "1.0.0"
"@fastify/deepmerge" "^2.0.2"
Expand Down
Loading