enforce limits

This commit is contained in:
cupcakearmy 2022-03-01 16:16:02 +01:00
parent d112eba8fe
commit 36fa451249
No known key found for this signature in database
GPG Key ID: 3235314B4D31232F
12 changed files with 57 additions and 26 deletions

View File

@ -4,15 +4,15 @@ lazy_static! {
pub static ref VERSION: String = option_env!("CARGO_PKG_VERSION") pub static ref VERSION: String = option_env!("CARGO_PKG_VERSION")
.unwrap_or("Unknown") .unwrap_or("Unknown")
.to_string(); .to_string();
pub static ref LIMIT: usize = pub static ref LIMIT: u32 =
Byte::from_str(std::env::var("SIZE_LIMIT").unwrap_or("1 KiB".to_string())) Byte::from_str(std::env::var("SIZE_LIMIT").unwrap_or("1 KiB".to_string()))
.unwrap() .unwrap()
.get_bytes() as usize; .get_bytes() as u32;
pub static ref MAX_VIEWS: usize = std::env::var("MAX_VIEWS") pub static ref MAX_VIEWS: u32 = std::env::var("MAX_VIEWS")
.unwrap_or("100".to_string()) .unwrap_or("100".to_string())
.parse() .parse()
.unwrap(); .unwrap();
pub static ref MAX_EXPIRATION: usize = std::env::var("MAX_EXPIRATION") pub static ref MAX_EXPIRATION: u32 = std::env::var("MAX_EXPIRATION")
.unwrap_or("360".to_string()) // 6 hours in minutes .unwrap_or("360".to_string()) // 6 hours in minutes
.parse() .parse()
.unwrap(); .unwrap();

View File

@ -6,7 +6,7 @@ use serde::{Deserialize, Serialize};
pub struct Note { pub struct Note {
pub meta: String, pub meta: String,
pub contents: String, pub contents: String,
pub views: Option<u8>, pub views: Option<u32>,
pub expiration: Option<u32>, pub expiration: Option<u32>,
} }

View File

@ -2,6 +2,7 @@ use actix_web::{delete, get, post, web, HttpResponse, Responder, Scope};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::time::SystemTime; use std::time::SystemTime;
use crate::config;
use crate::note::{generate_id, Note, NoteInfo, NotePublic}; use crate::note::{generate_id, Note, NoteInfo, NotePublic};
use crate::store; use crate::store;
@ -40,17 +41,22 @@ async fn create(note: web::Json<Note>) -> impl Responder {
if n.views == None && n.expiration == None { if n.views == None && n.expiration == None {
return bad_req; return bad_req;
} }
if !*config::ALLOW_ADVANCED {
n.views = Some(1);
n.expiration = None;
}
match n.views { match n.views {
Some(v) => { Some(v) => {
if v > 100 { if v > *config::MAX_VIEWS {
return bad_req; return bad_req;
} }
n.expiration = None; // views overrides expiration
} }
_ => {} _ => {}
} }
match n.expiration { match n.expiration {
Some(e) => { Some(e) => {
if e > 360 { if e > *config::MAX_EXPIRATION {
return bad_req; return bad_req;
} }
let expiration = now() + (e * 60); let expiration = now() + (e * 60);

View File

@ -3,8 +3,8 @@ use serde::{Deserialize, Serialize};
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize)]
pub struct Status { pub struct Status {
pub version: String, pub version: String,
pub max_size: usize, pub max_size: u32,
pub max_views: usize, pub max_views: u32,
pub max_expiration: usize, pub max_expiration: u32,
pub allow_advanced: bool, pub allow_advanced: bool,
} }

View File

@ -19,7 +19,8 @@
"new_note_notice": "<b>Verfügbarkeit:</b><br />es ist nicht garantiert, dass die Notiz gespeichert wird, da alles im Speicher gehalten wird. Wenn dieser voll ist, werden die ältesten Notizen entfernt.<br />(Sie werden wahrscheinlich keine Probleme haben, seien Sie nur gewarnt).", "new_note_notice": "<b>Verfügbarkeit:</b><br />es ist nicht garantiert, dass die Notiz gespeichert wird, da alles im Speicher gehalten wird. Wenn dieser voll ist, werden die ältesten Notizen entfernt.<br />(Sie werden wahrscheinlich keine Probleme haben, seien Sie nur gewarnt).",
"errors": { "errors": {
"note_to_big": "Notiz konnte nicht erstellt werden. Notiz ist zu groß", "note_to_big": "Notiz konnte nicht erstellt werden. Notiz ist zu groß",
"note_error": "konnte keine Notiz erstellen. Bitte versuchen Sie es erneut." "note_error": "konnte keine Notiz erstellen. Bitte versuchen Sie es erneut.",
"max": "max: {n}"
}, },
"copied_to_clipboard": "in die Zwischenablage kopiert 🔗" "copied_to_clipboard": "in die Zwischenablage kopiert 🔗"
}, },

View File

@ -19,7 +19,8 @@
"new_note_notice": "<b>availability:</b><br />the note is not guaranteed to be stored as everything is kept in ram, if it fills up the oldest notes will be removed.<br />(you probably will be fine, just be warned.)", "new_note_notice": "<b>availability:</b><br />the note is not guaranteed to be stored as everything is kept in ram, if it fills up the oldest notes will be removed.<br />(you probably will be fine, just be warned.)",
"errors": { "errors": {
"note_to_big": "could not create note. note is to big", "note_to_big": "could not create note. note is to big",
"note_error": "could not create note. please try again." "note_error": "could not create note. please try again.",
"max": "max: {n}"
}, },
"copied_to_clipboard": "copied to clipboard 🔗" "copied_to_clipboard": "copied to clipboard 🔗"
}, },

View File

@ -19,7 +19,8 @@
"new_note_notice": "<b>disponibilidad:</b><br />no se garantiza que la nota se almacene, ya que todo se guarda en la memoria RAM, si se llena se eliminarán las notas más antiguas.<br />(probablemente estará bien, sólo está advertido.)", "new_note_notice": "<b>disponibilidad:</b><br />no se garantiza que la nota se almacene, ya que todo se guarda en la memoria RAM, si se llena se eliminarán las notas más antiguas.<br />(probablemente estará bien, sólo está advertido.)",
"errors": { "errors": {
"note_to_big": "no se pudo crear la nota. la nota es demasiado grande", "note_to_big": "no se pudo crear la nota. la nota es demasiado grande",
"note_error": "No se ha podido crear la nota. Por favor, inténtelo de nuevo." "note_error": "No se ha podido crear la nota. Por favor, inténtelo de nuevo.",
"max": "max: {n}"
}, },
"copied_to_clipboard": "copiado al portapapeles 🔗" "copied_to_clipboard": "copiado al portapapeles 🔗"
}, },

View File

@ -19,7 +19,8 @@
"new_note_notice": "<b>disponibilité :</b><br />la note n'est pas garantie d'être stockée car tout est conservé dans la mémoire vive, si elle se remplit les notes les plus anciennes seront supprimées.<br />(vous serez probablement bien, soyez juste averti.)", "new_note_notice": "<b>disponibilité :</b><br />la note n'est pas garantie d'être stockée car tout est conservé dans la mémoire vive, si elle se remplit les notes les plus anciennes seront supprimées.<br />(vous serez probablement bien, soyez juste averti.)",
"errors": { "errors": {
"note_to_big": "Impossible de créer une note. La note est trop grande", "note_to_big": "Impossible de créer une note. La note est trop grande",
"note_error": "n'a pas pu créer de note. Veuillez réessayer." "note_error": "n'a pas pu créer de note. Veuillez réessayer.",
"max": "max: {n}"
}, },
"copied_to_clipboard": "copié dans le presse-papiers 🔗" "copied_to_clipboard": "copié dans le presse-papiers 🔗"
}, },

View File

@ -19,7 +19,8 @@
"new_note_notice": "<b>disponibilità:</b><br />la nota non è garantita per essere memorizzata come tutto è tenuto in ram, se si riempie le note più vecchie saranno rimosse.<br />(probabilmente andrà bene, basta essere avvertiti).", "new_note_notice": "<b>disponibilità:</b><br />la nota non è garantita per essere memorizzata come tutto è tenuto in ram, se si riempie le note più vecchie saranno rimosse.<br />(probabilmente andrà bene, basta essere avvertiti).",
"errors": { "errors": {
"note_to_big": "impossibile creare una nota. la nota è troppo grande", "note_to_big": "impossibile creare una nota. la nota è troppo grande",
"note_error": "Impossibile creare la nota. Riprova." "note_error": "Impossibile creare la nota. Riprova.",
"max": "max: {n}"
}, },
"copied_to_clipboard": "copiato negli appunti 🔗" "copied_to_clipboard": "copiato negli appunti 🔗"
}, },

View File

@ -49,7 +49,7 @@
height: 2rem; height: 2rem;
width: 1.25rem; width: 1.25rem;
left: 0.125rem; left: 0.125rem;
bottom: 0.1rem; bottom: 0.125rem;
background-color: var(--ui-bg-1); background-color: var(--ui-bg-1);
-webkit-transition: 0.4s; -webkit-transition: 0.4s;
transition: var(--ui-anim); transition: var(--ui-anim);

View File

@ -1,15 +1,13 @@
<script lang="ts"> <script lang="ts">
import { getRandomBytes, Hex } from '$lib/crypto' import { getRandomBytes, Hex } from '$lib/crypto'
import { fade } from 'svelte/transition'
import { t } from 'svelte-intl-precompile'
import copyToClipboard from 'copy-to-clipboard' import copyToClipboard from 'copy-to-clipboard'
import { t } from 'svelte-intl-precompile'
import { fade } from 'svelte/transition'
import Icon from './Icon.svelte' import Icon from './Icon.svelte'
export let label: string = '' export let label: string = ''
export let value: any export let value: any
export let validate: (value: any) => boolean | string = () => true
export let copy: boolean = false export let copy: boolean = false
export let random: boolean = false export let random: boolean = false
@ -19,6 +17,8 @@
let notification: string | null = null let notification: string | null = null
let notificationTimeout: NodeJS.Timeout | null = null let notificationTimeout: NodeJS.Timeout | null = null
$: valid = validate(value)
$: if (isPassword) { $: if (isPassword) {
value value
$$restProps.type = hidden ? initialType : 'text' $$restProps.type = hidden ? initialType : 'text'
@ -49,8 +49,11 @@
<label> <label>
<small disabled={$$restProps.disabled}> <small disabled={$$restProps.disabled}>
{label} {label}
{#if valid !== true}
<span class="error-text">{valid}</span>
{/if}
</small> </small>
<input bind:value {...$$restProps} /> <input bind:value {...$$restProps} class:valid={valid === true} />
<div class="icons"> <div class="icons">
{#if isPassword} {#if isPassword}
<Icon class="icon" icon={hidden ? 'eye' : 'eye-off'} on:click={toggle} /> <Icon class="icon" icon={hidden ? 'eye' : 'eye-off'} on:click={toggle} />
@ -73,6 +76,10 @@
display: block; display: block;
} }
label > small {
display: block;
}
input { input {
width: 100%; width: 100%;
margin: 0; margin: 0;
@ -86,6 +93,10 @@
border-color: var(--ui-clr-primary); border-color: var(--ui-clr-primary);
} }
input:not(.valid) {
border-color: var(--ui-clr-error);
}
.icons { .icons {
border: 1px red; border: 1px red;
position: absolute; position: absolute;

View File

@ -1,14 +1,15 @@
<script lang="ts"> <script lang="ts">
import { create, Note, PayloadToLargeError } from '$lib/api' import { create, Note, PayloadToLargeError } from '$lib/api'
import { encrypt, getKeyFromString, getRandomBytes, Hex } from '$lib/crypto' import { encrypt, getKeyFromString, getRandomBytes, Hex } from '$lib/crypto'
import { status } from '$lib/stores/status'
import Button from '$lib/ui/Button.svelte' import Button from '$lib/ui/Button.svelte'
import FileUpload from '$lib/ui/FileUpload.svelte' import FileUpload from '$lib/ui/FileUpload.svelte'
import MaxSize from '$lib/ui/MaxSize.svelte' import MaxSize from '$lib/ui/MaxSize.svelte'
import Switch from '$lib/ui/Switch.svelte' import Switch from '$lib/ui/Switch.svelte'
import TextArea from '$lib/ui/TextArea.svelte' import TextArea from '$lib/ui/TextArea.svelte'
import TextInput from '$lib/ui/TextInput.svelte' import TextInput from '$lib/ui/TextInput.svelte'
import { blur } from 'svelte/transition'
import { t } from 'svelte-intl-precompile' import { t } from 'svelte-intl-precompile'
import { blur } from 'svelte/transition'
let note: Note = { let note: Note = {
contents: '', contents: '',
@ -107,7 +108,9 @@
<div class="bottom"> <div class="bottom">
<Switch class="file" label={$t('common.file')} bind:value={file} /> <Switch class="file" label={$t('common.file')} bind:value={file} />
<Switch label={$t('common.advanced')} bind:value={advanced} /> {#if $status?.allow_advanced}
<Switch label={$t('common.advanced')} bind:value={advanced} />
{/if}
<div class="grow" /> <div class="grow" />
<div class="tr"> <div class="tr">
<small>{$t('common.max')}: <MaxSize /> </small> <small>{$t('common.max')}: <MaxSize /> </small>
@ -138,7 +141,10 @@
label={$t('common.views', { values: { n: 0 } })} label={$t('common.views', { values: { n: 0 } })}
bind:value={note.views} bind:value={note.views}
disabled={timeExpiration} disabled={timeExpiration}
max={100} max={$status?.max_views}
validate={(v) =>
($status && v < $status?.max_views) ||
$t('home.errors.max', { values: { n: $status?.max_views ?? 0 } })}
/> />
<div class="middle-switch"> <div class="middle-switch">
<Switch label={$t('common.mode')} bind:value={timeExpiration} color={false} /> <Switch label={$t('common.mode')} bind:value={timeExpiration} color={false} />
@ -148,7 +154,10 @@
label={$t('common.minutes', { values: { n: 0 } })} label={$t('common.minutes', { values: { n: 0 } })}
bind:value={note.expiration} bind:value={note.expiration}
disabled={!timeExpiration} disabled={!timeExpiration}
max={360} max={$status?.max_expiration}
validate={(v) =>
($status && v < $status?.max_expiration) ||
$t('home.errors.max', { values: { n: $status?.max_expiration ?? 0 } })}
/> />
</div> </div>
</div> </div>