Skip to content

Commit c621c41

Browse files
committed
fix: security issues with programatic download
adds fetch and blob so that the browser can explicitly fetch the file before download
1 parent 7513a9d commit c621c41

File tree

2 files changed

+20
-9
lines changed

2 files changed

+20
-9
lines changed

app/(dashboard)/dashboard/interviews/_components/ExportInterviewsDialog.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ export const ExportInterviewsDialog = ({
7575
}
7676

7777
// Download the zip file
78-
download(result.data.url, result.data.name);
78+
await download(result.data.url, result.data.name);
7979
} catch (error) {
8080
toast({
8181
icon: <XCircle />,

hooks/useDownload.ts

Lines changed: 19 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,25 @@
11
import { useCallback } from 'react';
22

33
export const useDownload = () => {
4-
const download = useCallback((url: string, nameWithExtension: string) => {
5-
const link = document.createElement('a');
6-
link.href = url;
7-
link.download = nameWithExtension;
8-
document.body.appendChild(link);
9-
link.click();
10-
document.body.removeChild(link);
11-
}, []);
4+
const download = useCallback(
5+
async (url: string, nameWithExtension: string) => {
6+
try {
7+
const response = await fetch(url);
8+
const blob = await response.blob();
9+
const blobUrl = URL.createObjectURL(blob);
10+
const link = document.createElement('a');
11+
link.href = blobUrl;
12+
link.download = nameWithExtension;
13+
document.body.appendChild(link);
14+
link.click();
15+
URL.revokeObjectURL(blobUrl);
16+
document.body.removeChild(link);
17+
} catch (error) {
18+
throw new Error('Failed to download file');
19+
}
20+
},
21+
[],
22+
);
1223

1324
return download;
1425
};

0 commit comments

Comments
 (0)