diff --git a/assets/js/definitions/index.d.ts b/assets/js/definitions/index.d.ts index a40653f..5fb9b97 100644 --- a/assets/js/definitions/index.d.ts +++ b/assets/js/definitions/index.d.ts @@ -2,3 +2,8 @@ type IntendedUser = { name: string; emails: string[]; }; + +type IntendedLink = { + filename: string | null, + filetype: string | null +}; diff --git a/assets/js/pages/AuthPage.tsx b/assets/js/pages/AuthPage.tsx index e3eda6c..7dbde20 100644 --- a/assets/js/pages/AuthPage.tsx +++ b/assets/js/pages/AuthPage.tsx @@ -27,15 +27,18 @@ interface Keys { iv: string; } -interface Link { +interface LinkFiles { text: Blob | null; file: Blob | null; + filename: string | null; + filetype: string | null; } const AuthPage = (props: AuthPageProps) => { const { service, recipient, user } = props; - const [secretFileUrl, _setsecretFileUrl] = useState("#"); + const [secretFileUrl, setSecretFileUrl] = useState("#"); + const [secretFileName, setSecretFileName] = useState(""); const [secretMessage, setSecretMessage] = useState("Decrypting..."); useEffect(() => { @@ -45,14 +48,14 @@ const AuthPage = (props: AuthPageProps) => { }, []); const init = async (): Promise => { + const link: LinkFiles | null = await retrieveLink(); const keys: Keys | null = await retrieveKeys(); - const link: Link | null = await retrieveLink(); if (link && keys) { await decrypt(link, keys); } }; - const retrieveLink = async (): Promise => { + const retrieveLink = async (): Promise => { const urlSegments = new URL(document.URL).pathname.split("/"); const linkId = urlSegments.pop() || urlSegments.pop(); if (!linkId) { @@ -60,14 +63,26 @@ const AuthPage = (props: AuthPageProps) => { return null; } - const textResponse = await fetch(`/uploads/links/${linkId}/text`); + const linkResponse = await fetch(`/links/${linkId}`); + const linkData: IntendedLink = await linkResponse.json(); + const textResponse = await fetch( + `/uploads/links/${linkId}/secret_message.txt` + ); const textData = await textResponse.blob(); - const fileResponse = await fetch(`/uploads/links/${linkId}/file`); + const fileResponse = await fetch( + `/uploads/links/${linkId}/${linkData.filename}` + ); const fileData = await fileResponse.blob(); + if (linkData.filename) { + await setSecretFileName(linkData.filename); + } + return { text: textData.size > 0 ? textData : null, file: fileData.size > 0 ? fileData : null, + filename: linkData.filename, + filetype: linkData.filetype, }; }; @@ -96,7 +111,7 @@ const AuthPage = (props: AuthPageProps) => { } }; - const decrypt = async (link: Link, keys: Keys) => { + const decrypt = async (link: LinkFiles, keys: Keys) => { const convertedKey = HexMix.hexToUint8(keys.key); const convertedIv = HexMix.hexToUint8(keys.iv); const importedKey = await window.crypto.subtle.importKey( @@ -123,6 +138,21 @@ const AuthPage = (props: AuthPageProps) => { }); } if (link?.file) { + const uploadedFile = await link.file.arrayBuffer(); + const encodedFile = await window.crypto.subtle.decrypt( + { + name: "AES-GCM", + length: 256, + iv: convertedIv, + }, + importedKey, + uploadedFile + ); + + const blob = new Blob([encodedFile], { + type: link.filetype ? link.filetype : "text/plain", + }); + setSecretFileUrl(window.URL.createObjectURL(blob)); } }; @@ -193,12 +223,14 @@ const AuthPage = (props: AuthPageProps) => { - {}} - /> + + {}} + /> +