add waffle library, handle file upload, authenticate user with oauth and see if they have the link's email associated to their account

This commit is contained in:
2022-02-13 00:20:21 -05:00
parent 5de53e23ea
commit cac3757723
20 changed files with 305 additions and 94 deletions

View File

@@ -14,15 +14,17 @@ import "../css/app.css"
// import {Socket} from "phoenix"
// import socket from "./socket"
//
import "phoenix_html"
import {Socket} from "phoenix"
import topbar from "topbar"
import {LiveSocket} from "phoenix_live_view"
import "phoenix_html";
import {Socket} from "phoenix";
import topbar from "topbar";
import {LiveSocket} from "phoenix_live_view";
import SplashPage from './pages/SplashPage';
import JustPage from './pages/JustPage'
import ForPage from './pages/ForPage'
import YouPage from './pages/YouPage'
import JustPage from './pages/JustPage';
import ForPage from './pages/ForPage';
import YouPage from './pages/YouPage';
import AuthPage from './pages/AuthPage';
import RevealPage from './pages/RevealPage';
let csrfToken = document.querySelector("meta[name='csrf-token']").getAttribute("content")
let liveSocket = new LiveSocket("/live", Socket, {params: {_csrf_token: csrfToken}})
@@ -42,5 +44,5 @@ liveSocket.connect()
window.liveSocket = liveSocket
window.Components = {
SplashPage, JustPage, ForPage, YouPage
SplashPage, JustPage, ForPage, YouPage, AuthPage, RevealPage
}

View File

@@ -1,16 +1,54 @@
// import HexMix from "../utils/hexmix";
// const fragmentData = window.location.hash.split('.');
// if (fragmentData.length <= 0) {
// alert("No key found in fragment URI");
// return;
// }
// const key = HexMix.hexToUint8(fragmentData[0]);
// const iv = HexMix.hexToUint8(fragmentData[1]);
import { Button, CenteredContainer, GlobalStyle, Header2, Header3, Input, Label, Spacer, TextAlignWrapper } from "@intended/intended-ui";
import React, { useEffect } from "react";
// const importedKey = await window.crypto.subtle.importKey(
// 'raw',
// key,
// 'AES-GCM',
// true,
// ['encrypt', 'decrypt']
// );
type AuthPageProps = {
csrf: string,
service: string,
recipient: string
}
const AuthPage = (props: AuthPageProps) => {
const { service, recipient } = props;
// const [recipientInput, setRecipientInput] = useState("");
// const [serviceSelect, setServiceSelect] = useState("github");
// useEffect(() => {
// }, [])
return (
<React.StrictMode>
<GlobalStyle />
<CenteredContainer fullscreen>
<CenteredContainer>
<Header2 style={{ margin: ".4rem" }}>Someone sent you a secret</Header2>
<Header3 small>
Please verify your identity to reveal this message.
</Header3>
<Spacer space="3rem" />
<TextAlignWrapper align="left">
<Label htmlFor="usernameEmail">Username / Email</Label>
</TextAlignWrapper>
<Input
variant="disabled-medium"
id="usernameEmail"
value={recipient}
/>
<Spacer space="3rem" />
<TextAlignWrapper align="left">
<Label htmlFor="service">Service</Label>
</TextAlignWrapper>
<Input variant="disabled-medium" id="service" value={service} />
<Spacer space="3rem" />
<a href={`https://intended.link/auth/${service}`}>
<Button variant="primary" wide onClick={() => {}}>
Verify
</Button>
</a>
</CenteredContainer>
</CenteredContainer>
</React.StrictMode>
);
}
export default AuthPage;

View File

@@ -3,9 +3,13 @@ import React, { useState } from "react";
import { ProgressIndicator, Header2, Button, IconArrow, Label, Input, Select, CenteredContainer, SpaceBetweenContainer, Spacer, TextAlignWrapper, GlobalStyle } from "@intended/intended-ui";
const ForPage = () => {
type ForPageProps = {
csrf: string
}
const ForPage = (props: ForPageProps) => {
const [recipientInput, setRecipientInput] = useState("");
const [serviceSelect, setServiceSelect] = useState("");
const [serviceSelect, setServiceSelect] = useState("github");
const handleRecipientInputChange = (
e: React.ChangeEvent<HTMLInputElement>
@@ -18,14 +22,14 @@ const ForPage = () => {
};
const postContacts = async () => {
const fragmentData = window.location.hash.split('.');
if (fragmentData.length <= 0) {
alert("No key found in fragment URI");
return;
}
// const fragmentData = window.location.hash.split('.');
// if (fragmentData.length <= 0) {
// alert("No key found in fragment URI");
// return;
// }
const linkId = sessionStorage.getItem("link_id");
if (linkId == null || linkId == "") {
if (!linkId) {
alert("No created link found in storage");
return;
}
@@ -36,10 +40,18 @@ const ForPage = () => {
formData.append("link_id", linkId);
try {
await fetch(`${window.location.origin}/just/for`, {
const results = await fetch(`${window.location.origin}/just/for`, {
headers: {
"X-CSRF-Token": props.csrf
},
body: formData,
method: "POST"
});
if (!results.ok) {
throw new Error('Network response was not OK');
}
await results.json();
window.location.href = `${window.location.origin}/just/for/you`;
} catch (err: any) {
alert(err.message);
@@ -74,7 +86,9 @@ const ForPage = () => {
id="serviceSelector"
onChange={handleServiceChange}
value={serviceSelect}
/>
>
<option value='github'>Github</option>
</Select>
<Spacer space="3rem" />
<SpaceBetweenContainer>
<Button variant="secondary" onClick={() => window.location.href = "/just"}>

View File

@@ -1,13 +1,21 @@
import React, { useState } from "react";
import React, { useEffect, useState } from "react";
import { ProgressIndicator, Header2, Button, IconArrow, Label, FileInput, TextArea, CenteredContainer, Spacer, TextAlignWrapper, GlobalStyle } from '@intended/intended-ui';
import HexMix from "../utils/hexmix";
const JustPage = (props) => {
type JustPageProps = {
csrf: string
}
const JustPage = (props: JustPageProps) => {
const [secretInput, setSecretInput] = useState("");
const [fileInput, setFileInput] = useState<File | null>(null);
const [fileName, setFileName] = useState("");
useEffect(() => {
sessionStorage.clear();
}, [])
const handleChange = (e: React.ChangeEvent<HTMLTextAreaElement>) => {
setSecretInput(e.target.value);
};
@@ -51,18 +59,20 @@ const JustPage = (props) => {
const blobData = new Blob([encrypted]);
formData.append('text_content', blobData);
formData.append('filetype', 'text/plain');
formData.append('filename', 'secret.txt');
// formData.append('filetype', 'text/plain');
// formData.append('filename', 'secret.txt');
try {
const link: unknown = await fetch(`${window.location.origin}/just`, {
const link: Response = await fetch(`${window.location.origin}/just`, {
headers: {
"X-CSRF-Token": props.csrf
},
body: formData,
method: "POST"
});
sessionStorage.setItem("link_id", (link as Link).id);
const { id: link_id } = await link.json()
sessionStorage.setItem("link_id", link_id);
sessionStorage.setItem("key_hex", keyHex);
sessionStorage.setItem("iv_hex", ivHex);
window.location.href = `${window.location.origin}/just/for`;

View File

@@ -0,0 +1,61 @@
import { Button, CenteredContainer, GlobalStyle, Header2, Header3, InputButtonWithIcon, Label, SpaceBetweenContainer, Spacer, TextAlignWrapper, TextAreaParagraph } from "@intended/intended-ui";
import React, { useEffect, useState } from "react";
// import HexMix from "../utils/hexmix";
// const fragmentData = window.location.hash.split('.');
// if (fragmentData.length <= 0) {
// alert("No key found in fragment URI");
// return;
// }
// const key = HexMix.hexToUint8(fragmentData[0]);
// const iv = HexMix.hexToUint8(fragmentData[1]);
// const importedKey = await window.crypto.subtle.importKey(
// 'raw',
// key,
// 'AES-GCM',
// true,
// ['encrypt', 'decrypt']
// );
const RevealPage = () => {
return (
<React.StrictMode>
<GlobalStyle />
<CenteredContainer fullscreen>
<CenteredContainer>
<Header2 style={{ margin: ".4rem" }}>Someone sent you a secret</Header2>
<Header3 small>
Please verify your identity to reveal this message.
</Header3>
<Spacer space="3rem" />
<SpaceBetweenContainer>
<Label htmlFor="secretMessage">Secret message</Label>
<Label htmlFor="secretMessage">Sent 8/24/21 @ 1:27pm</Label>
</SpaceBetweenContainer>
<TextAreaParagraph id="secretMessage">
"Sup. What are you doing for lunch?"
</TextAreaParagraph>
<Spacer space="3rem" />
<TextAlignWrapper align="left">
<Label htmlFor="service">Secret File</Label>
</TextAlignWrapper>
<InputButtonWithIcon
variant="download"
id="downloadfile"
value="1780983.jpg"
onClick={() => {}}
/>
<Spacer space="3rem" />
<Button variant="secondary" wide onClick={() => {}}>
Send a secret
</Button>
</CenteredContainer>
</CenteredContainer>
</React.StrictMode>
);
}
export default RevealPage;

View File

@@ -8,11 +8,10 @@ const YouPage = () => {
const keyHex = sessionStorage.getItem("key_hex");
const ivHex = sessionStorage.getItem("iv_hex");
`${window.location.origin}/just/for/you/${linkId}#${keyHex}.${ivHex}`
return "";
return `${window.location.origin}/just/for/you/${linkId}#${keyHex}.${ivHex}`;
};
const [url, setUrl] = useState(calculateUrl());
const [url, _setUrl] = useState(calculateUrl());
const copyUrl = async () => {
try {
@@ -51,7 +50,7 @@ const YouPage = () => {
<Input
variant="disabled-light"
id="encodedSecret"
value="\4š€Š”Çm’ÄyÆFՑ¬Ð$CÑӀÃyۄ"
value={url}
/>
<Spacer space="3rem" />
<SpaceBetweenContainer>