always encrypt content

This commit is contained in:
cupcakearmy 2021-05-03 12:21:51 +02:00
parent dc212d7441
commit 7a3397f978
No known key found for this signature in database
GPG Key ID: D28129AE5654D9D9
6 changed files with 26 additions and 55 deletions

View File

@ -5,11 +5,10 @@ const base = axios.create({ baseURL: dev ? 'http://localhost:5000' : undefined }
export type Note = { export type Note = {
contents: string contents: string
password: boolean
views?: number views?: number
expiration?: number expiration?: number
} }
export type NoteInfo = Pick<Note, 'password'> export type NoteInfo = {}
export type NotePublic = Pick<Note, 'contents'> export type NotePublic = Pick<Note, 'contents'>
export async function create(note: Note) { export async function create(note: Note) {

View File

@ -1,7 +1,7 @@
<script lang="ts"> <script lang="ts">
import type { Note } from '$lib/api' import type { Note } from '$lib/api'
import { create } from '$lib/api' import { create } from '$lib/api'
import { getKeyFromString, encrypt } from '$lib/crypto' import { getKeyFromString, encrypt, Hex, getRandomBytes } from '$lib/crypto'
import Button from '$lib/ui/Button.svelte' import Button from '$lib/ui/Button.svelte'
import Switch from '$lib/ui/Switch.svelte' import Switch from '$lib/ui/Switch.svelte'
@ -10,11 +10,9 @@
let note: Note = { let note: Note = {
contents: '', contents: '',
password: false,
views: 1, views: 1,
expiration: 60, expiration: 60,
} }
let password: string = ''
let result: { password: string; id: string } | null = null let result: { password: string; id: string } | null = null
let advanced = false let advanced = false
let type = false let type = false
@ -37,18 +35,15 @@
try { try {
error = null error = null
loading = true loading = true
const password = Hex.encode(getRandomBytes(32))
const key = await getKeyFromString(password)
const data: Note = { const data: Note = {
contents: note.contents, contents: await encrypt(note.contents, key),
password: !!password,
} }
// @ts-ignore // @ts-ignore
if (type) data.expiration = parseInt(note.expiration) if (type) data.expiration = parseInt(note.expiration)
// @ts-ignore // @ts-ignore
else data.views = parseInt(note.views) else data.views = parseInt(note.views)
if (data.password) {
const key = await getKeyFromString(password)
data.contents = await encrypt(data.contents, key)
}
const response = await create(data) const response = await create(data)
result = { result = {
@ -68,11 +63,12 @@
</script> </script>
{#if result} {#if result}
{#if result.password} <TextInput
<TextInput type="password" readonly value={result.password} copy /> type="text"
<br /> readonly
{/if} value="{window.location.origin}/note/{result.id}/{result.password}"
<TextInput type="text" readonly value="{window.location.origin}/note/{result.id}" copy /> copy
/>
<br /> <br />
<Button on:click={reset}>new</Button> <Button on:click={reset}>new</Button>
{:else} {:else}
@ -112,15 +108,6 @@
max={360} max={360}
/> />
</div> </div>
<br />
<TextInput
type="password"
label="password"
placeholder="optional"
bind:value={password}
copy
random
/>
</div> </div>
<style> <style>

View File

@ -26,9 +26,9 @@
<b>▶ Features</b> <b>▶ Features</b>
<ul> <ul>
<li>server cannot decrypt contents due to client side encryption</li>
<li>view and time constrains</li> <li>view and time constrains</li>
<li>in memory, no persistence</li> <li>in memory, no persistence</li>
<li>in browser encryption → server cannot decrypt contents</li>
</ul> </ul>
<p> <p>

View File

@ -17,8 +17,8 @@
import { onMount } from 'svelte' import { onMount } from 'svelte'
export let id: string export let id: string
let needPassword = false export let password: string
let password: string = ''
let note: NotePublic | null = null let note: NotePublic | null = null
let exists = false let exists = false
@ -29,8 +29,7 @@
try { try {
loading = true loading = true
error = null error = null
const data = await info(id) await info(id)
needPassword = data.password
exists = true exists = true
} catch { } catch {
exists = false exists = false
@ -40,18 +39,16 @@
}) })
async function show() { async function show() {
const data = note || (await get(id)) // Don't get the content twice on wrong password.
if (needPassword) {
try { try {
error = false
const data = note || (await get(id)) // Don't get the content twice on wrong password.
const key = await getKeyFromString(password) const key = await getKeyFromString(password)
data.contents = await decrypt(data.contents, key) data.contents = await decrypt(data.contents, key)
error = false note = data
} catch { } catch {
error = true error = true
} }
} }
note = data
}
</script> </script>
{#if !loading} {#if !loading}
@ -67,17 +64,12 @@
{:else} {:else}
<form on:submit|preventDefault={show}> <form on:submit|preventDefault={show}>
<p>click below to show and delete the note if the counter has reached it's limit</p> <p>click below to show and delete the note if the counter has reached it's limit</p>
{#if needPassword}
<TextInput type="password" label="password" bind:value={password} />
<br />
{/if}
<Button type="submit">show note</Button> <Button type="submit">show note</Button>
{#if error} {#if error}
<br /> <br />
<p class="error-text"> <p class="error-text">
wrong password. could not decipher. wrong password. could not decipher. probably a broken link. note was destroyed.
<br /> <br />
note already destroyed. try again without reloading the page.
</p> </p>
{/if} {/if}
</form> </form>

View File

@ -5,15 +5,12 @@ use serde::{Deserialize, Serialize};
#[derive(Serialize, Deserialize, Clone)] #[derive(Serialize, Deserialize, Clone)]
pub struct Note { pub struct Note {
pub contents: String, pub contents: String,
pub password: bool,
pub views: Option<u8>, pub views: Option<u8>,
pub expiration: Option<u64>, pub expiration: Option<u64>,
} }
#[derive(Serialize, Deserialize, Clone)] #[derive(Serialize, Deserialize, Clone)]
pub struct NoteInfo { pub struct NoteInfo {}
pub password: bool,
}
#[derive(Serialize, Deserialize, Clone)] #[derive(Serialize, Deserialize, Clone)]
pub struct NotePublic { pub struct NotePublic {

View File

@ -23,11 +23,7 @@ async fn one(path: web::Path<NotePath>) -> impl Responder {
let note = store::get(&p.id); let note = store::get(&p.id);
match note { match note {
None => return HttpResponse::NotFound().finish(), None => return HttpResponse::NotFound().finish(),
Some(note) => { Some(_) => return HttpResponse::Ok().json(NoteInfo {}),
return HttpResponse::Ok().json(NoteInfo {
password: note.password,
})
}
} }
} }