From 2ccb3d0053978f9a733551c3c5c99b57a45ac042 Mon Sep 17 00:00:00 2001 From: Silas Date: Thu, 24 Feb 2022 01:15:44 -0500 Subject: [PATCH] bug fixes, add logo, mobile styling --- assets/css/app.css | 41 ++++++++++-- assets/js/definitions/index.d.ts | 4 +- assets/js/pages/AuthPage.tsx | 62 +++++++++++------- assets/js/pages/ForPage.tsx | 46 ++++++++----- assets/js/pages/JustPage.tsx | 22 +++++-- assets/js/pages/SplashPage.tsx | 23 +++++-- assets/js/pages/YouPage.tsx | 2 +- assets/package-lock.json | 18 ++--- assets/package.json | 2 +- assets/static/images/logo.png | Bin 0 -> 4472 bytes .../controllers/auth_controller.ex | 8 +-- .../controllers/link_controller.ex | 5 +- .../controllers/page_controller.ex | 4 +- lib/entendu_web/templates/layout/app.html.eex | 5 +- .../templates/layout/root.html.leex | 2 +- lib/entendu_web/templates/page/index.html.eex | 41 ------------ 16 files changed, 163 insertions(+), 122 deletions(-) create mode 100644 assets/static/images/logo.png diff --git a/assets/css/app.css b/assets/css/app.css index 0ae2a25..c32ee07 100644 --- a/assets/css/app.css +++ b/assets/css/app.css @@ -12,15 +12,15 @@ transition: opacity 1s ease-out; } -.phx-disconnected{ +.phx-disconnected { cursor: wait; } -.phx-disconnected *{ +.phx-disconnected * { pointer-events: none; } .phx-modal { - opacity: 1!important; + opacity: 1 !important; position: fixed; z-index: 1; left: 0; @@ -28,8 +28,8 @@ width: 100%; height: 100%; overflow: auto; - background-color: rgb(0,0,0); - background-color: rgba(0,0,0,0.4); + background-color: rgb(0, 0, 0); + background-color: rgba(0, 0, 0, 0.4); } .phx-modal-content { @@ -54,7 +54,6 @@ cursor: pointer; } - /* Alerts and form errors */ .alert { padding: 15px; @@ -88,3 +87,33 @@ display: block; margin: -1rem 0 2rem; } + +.logo { + width: 200px; + padding: 20px; + border-right: 1px #efefef solid; +} + +.centered-container { + margin-top: 3rem; + background: none !important; +} + +@media screen and (max-width: 800px) { + .logo { + display: block; + margin-left: auto; + margin-right: auto; + border-right: none; + border-bottom: 1px #efefef solid; + } + + .splashHeader { + font-size: 1.9rem; + } + + .splashSubheader { + font-size: 1.4rem; + font-weight: 200; + } +} diff --git a/assets/js/definitions/index.d.ts b/assets/js/definitions/index.d.ts index 018b963..0230cea 100644 --- a/assets/js/definitions/index.d.ts +++ b/assets/js/definitions/index.d.ts @@ -12,5 +12,7 @@ type OAuthEmail = { type IntendedLink = { filename: string | null, - filetype: string | null + filetype: string | null, + text_content: string | null, + file_content: string | null }; diff --git a/assets/js/pages/AuthPage.tsx b/assets/js/pages/AuthPage.tsx index 0f7541f..2a9f1cd 100644 --- a/assets/js/pages/AuthPage.tsx +++ b/assets/js/pages/AuthPage.tsx @@ -40,12 +40,12 @@ const AuthPage = (props: AuthPageProps) => { const [secretFileUrl, setSecretFileUrl] = useState("#"); const [secretFileName, setSecretFileName] = useState(""); - const [secretMessage, setSecretMessage] = useState("Decrypting..."); + const [secretMessage, setSecretMessage] = useState(""); const [messageRevealed, setMessageRevealed] = useState(false); useEffect(() => { init().catch((reason) => { - alert(reason); + console.log(reason); }); }, []); @@ -55,7 +55,7 @@ const AuthPage = (props: AuthPageProps) => { const init = async (): Promise => { const link: LinkFiles | null = await retrieveLink(); const keys: Keys | null = await retrieveKeys(); - if (link && keys) { + if (link && keys && user) { await decrypt(link, keys); } }; @@ -77,25 +77,36 @@ const AuthPage = (props: AuthPageProps) => { } 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}/${linkData.filename}` - ); - const fileData = await fileResponse.blob(); + let linkData: IntendedLink | null; + let textData = null; + let fileData = null; + if (linkResponse.status !== 200) { + throw new Error(linkResponse.statusText); + return null; + } + linkData = await linkResponse.json(); - if (linkData.filename) { - await setSecretFileName(linkData.filename); + if (linkData) { + const textResponse = linkData.text_content + ? await fetch(`/uploads/links/${linkId}/secret_message.txt`) + : null; + textData = textResponse ? await textResponse.blob() : null; + + const fileResponse = linkData.file_content + ? await fetch(`/uploads/links/${linkId}/${linkData.filename}`) + : null; + fileData = fileResponse ? await fileResponse.blob() : null; + + 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, + text: textData, + file: fileData, + filename: linkData ? linkData.filename : null, + filetype: linkData ? linkData.filetype : null, }; }; @@ -107,13 +118,13 @@ const AuthPage = (props: AuthPageProps) => { fragmentData[0] = fragmentData[0].slice(1); if (fragmentData.length <= 1) { - key = sessionStorage.getItem("link_key"); - iv = sessionStorage.getItem("link_iv"); + key = sessionStorage.getItem("key_hex"); + iv = sessionStorage.getItem("iv_hex"); } else { key = fragmentData[0]; iv = fragmentData[1]; - sessionStorage.setItem("link_key", key); - sessionStorage.setItem("link_iv", iv); + sessionStorage.setItem("key_hex", key); + sessionStorage.setItem("iv_hex", iv); } if (key && iv) { @@ -134,6 +145,7 @@ const AuthPage = (props: AuthPageProps) => { true, ["encrypt", "decrypt"] ); + if (link?.text) { const textFile = await link.text.arrayBuffer(); const encodedText = await window.crypto.subtle.decrypt( @@ -201,7 +213,7 @@ const AuthPage = (props: AuthPageProps) => { const renderHeader = (): JSX.Element => { return (
- + {user ? "You have been identified!" : "Someone sent you a secret"} {user ? ( @@ -226,7 +238,7 @@ const AuthPage = (props: AuthPageProps) => { const renderAuth = (): JSX.Element => { return ( - + {renderHeader()} @@ -256,7 +268,7 @@ const AuthPage = (props: AuthPageProps) => { const renderReveal = (): JSX.Element => { return ( - + {renderHeader()} diff --git a/assets/js/pages/ForPage.tsx b/assets/js/pages/ForPage.tsx index 852cee7..6d15305 100644 --- a/assets/js/pages/ForPage.tsx +++ b/assets/js/pages/ForPage.tsx @@ -1,11 +1,23 @@ import React, { useState } from "react"; -import { ProgressIndicator, Header2, Button, IconArrow, Label, Input, Select, CenteredContainer, SpaceBetweenContainer, Spacer, TextAlignWrapper, GlobalStyle } from "@intended/intended-ui"; - +import { + ProgressIndicator, + Header2, + Button, + IconArrow, + Label, + Input, + Select, + CenteredContainer, + SpaceBetweenContainer, + Spacer, + TextAlignWrapper, + GlobalStyle, +} from "@intended/intended-ui"; type ForPageProps = { - csrf: string -} + csrf: string; +}; const ForPage = (props: ForPageProps) => { const [recipientInput, setRecipientInput] = useState(""); @@ -35,20 +47,20 @@ const ForPage = (props: ForPageProps) => { } const formData = new FormData(); - formData.append('recipient', recipientInput); - formData.append('service', serviceSelect); + formData.append("recipient", recipientInput); + formData.append("service", serviceSelect); formData.append("link_id", linkId); try { - const results = await fetch(`${window.location.origin}/just/for`, { + const results = await fetch(`${window.location.origin}/just/for`, { headers: { - "X-CSRF-Token": props.csrf + "X-CSRF-Token": props.csrf, }, body: formData, - method: "POST" + method: "POST", }); if (!results.ok) { - throw new Error('Network response was not OK'); + throw new Error("Network response was not OK"); } await results.json(); @@ -61,7 +73,7 @@ const ForPage = (props: ForPageProps) => { return ( - + Tell Someone @@ -79,7 +91,8 @@ const ForPage = (props: ForPageProps) => { + + - diff --git a/assets/js/pages/JustPage.tsx b/assets/js/pages/JustPage.tsx index 9decfc7..3208b4c 100644 --- a/assets/js/pages/JustPage.tsx +++ b/assets/js/pages/JustPage.tsx @@ -74,7 +74,11 @@ const JustPage = (props: JustPageProps) => { } }; - const fileFormData = async (form: FormData, aesKey: AESKey) => { + const fileFormData = async ( + form: FormData, + aesKey: AESKey + ): Promise => { + if (!fileInput) return form; const encoded = HexMix.stringToArrayBuffer(fileInput as string); const encrypted = await window.crypto.subtle.encrypt( { @@ -91,9 +95,14 @@ const JustPage = (props: JustPageProps) => { HexMix.arrayBufferToString(encrypted, (result: string) => { sessionStorage.setItem("encoded_file", result); }); + return form; }; - const textFormData = async (form: FormData, aesKey: AESKey) => { + const textFormData = async ( + form: FormData, + aesKey: AESKey + ): Promise => { + if (!secretInput) return form; const encoded = HexMix.stringToArrayBuffer(secretInput); const encrypted = await window.crypto.subtle.encrypt( { @@ -108,6 +117,7 @@ const JustPage = (props: JustPageProps) => { HexMix.arrayBufferToString(encrypted, (result: string) => { sessionStorage.setItem("encoded_message", result); }); + return form; }; const createKey = async (): Promise => { @@ -141,9 +151,9 @@ const JustPage = (props: JustPageProps) => { } const key = await createKey(); - const formData = new FormData(); - await fileFormData(formData, key); - await textFormData(formData, key); + let formData = new FormData(); + formData = await fileFormData(formData, key); + formData = await textFormData(formData, key); try { const link: Response = await fetch(`${window.location.origin}/just`, { @@ -167,7 +177,7 @@ const JustPage = (props: JustPageProps) => { return ( - + Create a secret diff --git a/assets/js/pages/SplashPage.tsx b/assets/js/pages/SplashPage.tsx index 6f0696a..aa2b69d 100644 --- a/assets/js/pages/SplashPage.tsx +++ b/assets/js/pages/SplashPage.tsx @@ -28,13 +28,26 @@ const SplashPage = (props: SplashPageProps) => { return ( - + - - Securely Share Your Secrets + + + Securely Share Your Secrets + - With Intended Link you can easily share messages and files securely - and secretly. + + With Intended Link you can easily share messages and files + securely and secretly. +