add password to frontend

This commit is contained in:
2023-05-23 09:39:19 +02:00
parent 6da28a701e
commit fdc2722fb9
8 changed files with 124 additions and 70 deletions

View File

@@ -8,48 +8,69 @@
export let note: Note
export let timeExpiration = false
let customPassword = false
$: if (!customPassword) note.password = undefined
</script>
<div class="fields">
<TextInput
data-testid="field-views"
type="number"
label={$t('common.views', { values: { n: 0 } })}
bind:value={note.views}
disabled={timeExpiration}
max={$status?.max_views}
min={1}
validate={(v) =>
($status && v <= $status?.max_views && v > 0) ||
$t('home.errors.max', { values: { n: $status?.max_views ?? 0 } })}
/>
<div class="middle-switch">
<div class="flex col">
<div class="flex">
<TextInput
data-testid="field-views"
type="number"
label={$t('common.views', { values: { n: 0 } })}
bind:value={note.views}
disabled={timeExpiration}
max={$status?.max_views}
min={1}
validate={(v) =>
($status && v <= $status?.max_views && v > 0) ||
$t('home.errors.max', { values: { n: $status?.max_views ?? 0 } })}
/>
<Switch
data-testid="switch-advanced-toggle"
label={$t('common.mode')}
bind:value={timeExpiration}
color={false}
/>
<TextInput
data-testid="field-expiration"
type="number"
label={$t('common.minutes', { values: { n: 0 } })}
bind:value={note.expiration}
disabled={!timeExpiration}
max={$status?.max_expiration}
validate={(v) =>
($status && v < $status?.max_expiration) ||
$t('home.errors.max', { values: { n: $status?.max_expiration ?? 0 } })}
/>
</div>
<div class="flex">
<Switch bind:value={customPassword} label={$t('home.advanced.custom_password')} />
<TextInput
type="password"
bind:value={note.password}
label={$t('common.password')}
disabled={!customPassword}
random
/>
</div>
<div>
{$t('home.advanced.explanation')}
</div>
<TextInput
data-testid="field-expiration"
type="number"
label={$t('common.minutes', { values: { n: 0 } })}
bind:value={note.expiration}
disabled={!timeExpiration}
max={$status?.max_expiration}
validate={(v) =>
($status && v < $status?.max_expiration) ||
$t('home.errors.max', { values: { n: $status?.max_expiration ?? 0 } })}
/>
</div>
<style>
.middle-switch {
margin: 0 1rem;
.flex {
display: flex;
align-items: flex-end;
gap: 1rem;
width: 100%;
}
.fields {
display: flex;
.col {
gap: 1.5rem;
flex-direction: column;
}
</style>

View File

@@ -1,7 +1,7 @@
<script lang="ts" context="module">
export type NoteResult = {
password: string
id: string
password?: string
}
</script>
@@ -14,7 +14,8 @@
export let result: NoteResult
$: url = `${window.location.origin}/note/${result.id}#${result.password}`
let url = `${window.location.origin}/note/${result.id}`
if (result.password) url += `#${result.password}`
function reset() {
window.location.reload()

View File

@@ -4,43 +4,35 @@
export let color = true
</script>
<div {...$$restProps}>
<label class="switch">
<small>{label}</small>
<input type="checkbox" bind:checked={value} />
<span class:color class="slider" />
</label>
</div>
<label {...$$restProps}>
<small>{label}</small>
<input type="checkbox" bind:checked={value} />
<span class:color class="slider" />
</label>
<style>
div {
height: 3.75rem;
}
.switch {
label {
position: relative;
display: inline-block;
width: 4rem;
height: 2.5rem;
}
.switch input {
opacity: 0;
width: 0;
height: 0;
label input {
display: none;
}
small {
display: block;
width: max-content;
}
.slider {
position: absolute;
display: block;
width: 4rem;
height: 2.5rem;
position: relative;
cursor: pointer;
top: 0;
left: 0;
right: 0;
bottom: 0;
border: 2px solid var(--ui-bg-1);
background-color: var(--ui-bg-0);
transition: var(--ui-anim);
transform: translateY(1.2rem);
}
.slider:before {

View File

@@ -30,7 +30,7 @@
</script>
<label>
<small disabled={$$restProps.disabled}>
<small class:disabled={$$restProps.disabled}>
{label}
{#if valid !== true}
<span class="error-text">{valid}</span>
@@ -54,6 +54,7 @@
label {
position: relative;
display: block;
width: 100%;
}
label > small {

View File

@@ -1,5 +1,5 @@
<script lang="ts">
import { AES, Hex } from 'occulto'
import { AES, Hex, Bytes } from 'occulto'
import { t } from 'svelte-intl-precompile'
import { blur } from 'svelte/transition'
@@ -57,13 +57,14 @@
try {
loading = $t('common.encrypting')
const key = await AES.generateKey()
const password = Hex.encode(key)
const derived = note.password && (await AES.derive(note.password))
const key = derived ? derived[0] : await AES.generateKey()
const data: Note = {
contents: '',
meta: note.meta,
}
if (derived) data.meta.derivation = derived[1]
if (isFile) {
if (files.length === 0) throw new EmptyContentError()
data.contents = await Adapters.Files.encrypt(files, key)
@@ -77,8 +78,8 @@
loading = $t('common.uploading')
const response = await create(data)
result = {
password: password,
id: response.id,
password: note.password ? undefined : Hex.encode(key),
}
notify.success($t('home.messages.note_created'))
} catch (e) {
@@ -148,7 +149,7 @@
{#if advanced}
<div transition:blur={{ duration: 250 }}>
<br />
<hr />
<AdvancedParameters bind:note bind:timeExpiration />
</div>
{/if}

View File

@@ -23,6 +23,7 @@
right: 0;
width: 100%;
background-color: var(--ui-bg-0-85);
backdrop-filter: blur(2px);
}
a {