implement step 2 stuff

This commit is contained in:
Silas 2021-12-04 16:57:47 -05:00
parent d32dc8c2cb
commit 5de53e23ea
Signed by: silentsilas
GPG Key ID: 4199EFB7DAA34349
14 changed files with 121 additions and 20 deletions

3
assets/js/definitions/index.d.ts vendored Normal file
View File

@ -0,0 +1,3 @@
interface Link {
id: string
}

View File

@ -0,0 +1,16 @@
// 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']
// );

View File

@ -2,6 +2,7 @@ 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";
const ForPage = () => { const ForPage = () => {
const [recipientInput, setRecipientInput] = useState(""); const [recipientInput, setRecipientInput] = useState("");
const [serviceSelect, setServiceSelect] = useState(""); const [serviceSelect, setServiceSelect] = useState("");
@ -16,6 +17,35 @@ const ForPage = () => {
setServiceSelect(e.target.value); setServiceSelect(e.target.value);
}; };
const postContacts = async () => {
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 == "") {
alert("No created link found in storage");
return;
}
const formData = new FormData();
formData.append('recipient', recipientInput);
formData.append('service', serviceSelect);
formData.append("link_id", linkId);
try {
await fetch(`${window.location.origin}/just/for`, {
body: formData,
method: "POST"
});
window.location.href = `${window.location.origin}/just/for/you`;
} catch (err: any) {
alert(err.message);
}
};
return ( return (
<React.StrictMode> <React.StrictMode>
<GlobalStyle /> <GlobalStyle />
@ -50,7 +80,7 @@ const ForPage = () => {
<Button variant="secondary" onClick={() => window.location.href = "/just"}> <Button variant="secondary" onClick={() => window.location.href = "/just"}>
<IconArrow arrowDirection="left" /> <IconArrow arrowDirection="left" />
</Button> </Button>
<Button onClick={() => window.location.href = "/just/for/you"}>Generate Secret Code</Button> <Button onClick={postContacts}>Generate Secret Code</Button>
</SpaceBetweenContainer> </SpaceBetweenContainer>
</CenteredContainer> </CenteredContainer>
</CenteredContainer> </CenteredContainer>

View File

@ -3,7 +3,7 @@ import React, { useState } from "react";
import { ProgressIndicator, Header2, Button, IconArrow, Label, FileInput, TextArea, CenteredContainer, Spacer, TextAlignWrapper, GlobalStyle } from '@intended/intended-ui'; import { ProgressIndicator, Header2, Button, IconArrow, Label, FileInput, TextArea, CenteredContainer, Spacer, TextAlignWrapper, GlobalStyle } from '@intended/intended-ui';
import HexMix from "../utils/hexmix"; import HexMix from "../utils/hexmix";
const JustPage = () => { const JustPage = (props) => {
const [secretInput, setSecretInput] = useState(""); const [secretInput, setSecretInput] = useState("");
const [fileInput, setFileInput] = useState<File | null>(null); const [fileInput, setFileInput] = useState<File | null>(null);
const [fileName, setFileName] = useState(""); const [fileName, setFileName] = useState("");
@ -55,12 +55,17 @@ const JustPage = () => {
formData.append('filename', 'secret.txt'); formData.append('filename', 'secret.txt');
try { try {
await fetch(`${window.location.origin}/just`, { const link: unknown = await fetch(`${window.location.origin}/just`, {
headers: {
"X-CSRF-Token": props.csrf
},
body: formData, body: formData,
method: "POST" method: "POST"
}); });
const url = `${window.location.origin}/just/for#${keyHex}.${ivHex}`; sessionStorage.setItem("link_id", (link as Link).id);
window.location.href = url sessionStorage.setItem("key_hex", keyHex);
sessionStorage.setItem("iv_hex", ivHex);
window.location.href = `${window.location.origin}/just/for`;
} catch (err: any) { } catch (err: any) {
alert(err.message); alert(err.message);
} }

View File

@ -1,8 +1,27 @@
import React from "react"; import React, { useState } from "react";
import { ProgressIndicator, Header2, Button, IconArrow, InputButtonWithIcon, Label, Input, CenteredContainer, SpaceBetweenContainer, Spacer, TextAlignWrapper, GlobalStyle } from "@intended/intended-ui"; import { ProgressIndicator, Header2, Button, IconArrow, InputButtonWithIcon, Label, Input, CenteredContainer, SpaceBetweenContainer, Spacer, TextAlignWrapper, GlobalStyle } from "@intended/intended-ui";
const YouPage = () => { const YouPage = () => {
const calculateUrl = () => {
const linkId = sessionStorage.getItem("link_id");
const keyHex = sessionStorage.getItem("key_hex");
const ivHex = sessionStorage.getItem("iv_hex");
`${window.location.origin}/just/for/you/${linkId}#${keyHex}.${ivHex}`
return "";
};
const [url, setUrl] = useState(calculateUrl());
const copyUrl = async () => {
try {
navigator.clipboard.writeText(url);
} catch (err: any) {
alert("Could not copy url to clipboard.");
}
}
return ( return (
<React.StrictMode> <React.StrictMode>
<GlobalStyle /> <GlobalStyle />
@ -18,8 +37,8 @@ const YouPage = () => {
</SpaceBetweenContainer> </SpaceBetweenContainer>
<InputButtonWithIcon <InputButtonWithIcon
id="shareLink" id="shareLink"
onClick={() => {}} onClick={copyUrl}
value="https://intended.link/for/you/MWUzZjg4YmEtZmNmNy00M..." value={url}
variant="copy" variant="copy"
/> />
<Spacer space="2rem" /> <Spacer space="2rem" />
@ -39,7 +58,10 @@ const YouPage = () => {
<Button variant="secondary" onClick={() => window.location.href = "/just/for"}> <Button variant="secondary" onClick={() => window.location.href = "/just/for"}>
<IconArrow arrowDirection="left" /> <IconArrow arrowDirection="left" />
</Button> </Button>
<Button onClick={() => {}}>Generate Secret Code</Button> <Button onClick={() => {
sessionStorage.clear();
window.location.href = "/just";
}}>Create Another Secret</Button>
</SpaceBetweenContainer> </SpaceBetweenContainer>
</CenteredContainer> </CenteredContainer>
</CenteredContainer> </CenteredContainer>

View File

@ -11,7 +11,8 @@
"forceConsistentCasingInFileNames": true, "forceConsistentCasingInFileNames": true,
"noUnusedLocals": true, "noUnusedLocals": true,
"noUnusedParameters": true, "noUnusedParameters": true,
"lib": ["es2015", "dom"] "lib": ["es2015", "dom"],
"typeRoots": ["./js/definitions"]
}, },
"exclude": [ "exclude": [
"/node_modules/**/*", "/node_modules/**/*",

View File

@ -36,6 +36,7 @@ defmodule Entendu.Links do
""" """
def get_link!(id), do: Repo.get!(Link, id) def get_link!(id), do: Repo.get!(Link, id)
def get_link(id), do: Repo.get(Link, id)
@doc """ @doc """
Creates a link. Creates a link.

View File

@ -11,6 +11,8 @@ defmodule Entendu.Links.Link do
field :filetype, :string field :filetype, :string
field :text_content, :string field :text_content, :string
field :file_content, :string field :file_content, :string
field :recipient, :string
field :service, :string
timestamps() timestamps()
end end
@ -24,7 +26,9 @@ defmodule Entendu.Links.Link do
:filename, :filename,
:filetype, :filetype,
:text_content, :text_content,
:file_content :file_content,
:recipient,
:service
]) ])
end end
end end

View File

@ -7,7 +7,6 @@ defmodule EntenduWeb.AuthController do
plug Ueberauth plug Ueberauth
alias Ueberauth.Strategy.Helpers
alias Entendu.UserFromAuth alias Entendu.UserFromAuth
def delete(conn, _params) do def delete(conn, _params) do

View File

@ -33,8 +33,6 @@ defmodule EntenduWeb.LinkController do
link_params <- Params.to_map(changeset), link_params <- Params.to_map(changeset),
{:ok, %Link{} = link} <- Links.create_link(link_params) do {:ok, %Link{} = link} <- Links.create_link(link_params) do
conn conn
|> put_status(:created)
|> assign(:link, link)
|> render("show_authorized.json", %{link: link}) |> render("show_authorized.json", %{link: link})
end end
end end
@ -43,8 +41,21 @@ defmodule EntenduWeb.LinkController do
render(conn, "for.html") render(conn, "for.html")
end end
def for(_conn, %{username: _username, service: _service}) do defparams(
{:error, "not implemented"} second_step(%{
service: :string,
recipient: :string
})
)
def for(conn, %{link_id: link_id} = params) do
with %Changeset{valid?: true} = changeset <- first_step(params),
link_params <- Params.to_map(changeset),
%Link{} = link <- Links.get_link(link_id),
Links.update_link(link, link_params) do
conn
|> render("show_authorized.json", %{link: link})
end
end end
def you_page(conn, _params) do def you_page(conn, _params) do

View File

@ -15,9 +15,9 @@ defmodule EntenduWeb.LiveHelpers do
link: @link, link: @link,
return_to: Routes.link_index_path(@socket, :index) %> return_to: Routes.link_index_path(@socket, :index) %>
""" """
def live_modal(socket, component, opts) do def live_modal(_socket, component, opts) do
path = Keyword.fetch!(opts, :return_to) path = Keyword.fetch!(opts, :return_to)
modal_opts = [id: :modal, return_to: path, component: component, opts: opts] modal_opts = [id: :modal, return_to: path, component: component, opts: opts]
live_component(socket, EntenduWeb.ModalComponent, modal_opts) live_component(EntenduWeb.ModalComponent, modal_opts)
end end
end end

View File

@ -1 +1 @@
<%= react_component("Components.JustPage") %> <%= react_component("Components.JustPage", %{ csrf: Plug.CSRFProtection.get_csrf_token() }) %>

View File

@ -1,6 +1,5 @@
defmodule EntenduWeb.LinkView do defmodule EntenduWeb.LinkView do
use EntenduWeb, :view use EntenduWeb, :view
alias EntenduWeb.LinkView
def render("show_authorized.json", %{link: link}) do def render("show_authorized.json", %{link: link}) do
%{ %{

View File

@ -0,0 +1,10 @@
defmodule Entendu.Repo.Migrations.AddServiceAndRecipientToLinks do
use Ecto.Migration
def change do
alter table(:links) do
add :recipient, :string
add :service, :string
end
end
end