Compare commits

...

72 Commits

Author SHA1 Message Date
bab65bcdad bug due to dep update 2022-01-03 18:16:54 +01:00
a0732a4593 move folder 2022-01-02 23:46:08 +01:00
835f7df0f6 update dep 2022-01-02 18:43:31 +01:00
2def365cae quality of life improvemnts 2021-12-30 22:36:28 +01:00
c8b2539414 add version in about page 2021-12-22 15:20:30 +01:00
c8a25eb9bf release date 2021-12-22 14:57:58 +01:00
15bceb1715 add env 2021-12-22 14:56:33 +01:00
8acc4108ae Update README.md 2021-12-22 14:54:02 +01:00
0f708f53c0 changelog 2021-12-22 14:48:48 +01:00
8d03ad8e15 changelog 2021-12-22 14:47:43 +01:00
33829768eb time based fix 2021-12-22 14:46:06 +01:00
8cee6579e2 file upload 2021-12-22 13:10:08 +01:00
8eeb2a8de7 forgot missing packages 2021-12-21 10:35:02 +01:00
e4ce767444 add support for files 2021-12-21 00:15:04 +01:00
00fd514da5 feedback on to big error 2021-12-20 18:22:10 +01:00
ba38d2b819 proxy for cors 2021-12-20 18:14:59 +01:00
d0f83e6148 changelog 2021-12-20 17:54:17 +01:00
a040ad469e remove println 2021-12-20 17:54:09 +01:00
0c01866344 Merge pull request #15 from cupcakearmy/size-limit
Size limit
2021-12-20 17:45:05 +01:00
048c5198a2 Merge remote-tracking branch 'origin/main' into size-limit 2021-12-20 17:44:53 +01:00
f606916d97 Merge pull request #14 from cupcakearmy/pnpm
Pnpm
2021-12-20 17:43:11 +01:00
aea85c3b73 env docs 2021-12-20 17:42:35 +01:00
5f904b3971 cargo file 2021-12-20 17:42:30 +01:00
ac5d52a010 middleware to handle json payloads 2021-12-20 17:42:16 +01:00
8644a937d0 remove hardcoded limit 2021-12-20 17:42:08 +01:00
a0ebb97bc5 pnpm 2021-12-20 17:41:03 +01:00
19cd9b8507 examples on deployment 2021-12-16 13:54:15 +01:00
fe653e91c8 pnpm 2021-12-16 13:40:50 +01:00
a78ec72687 readme 2021-11-23 15:43:57 +01:00
a462bed948 1.2.0 2021-11-11 13:37:21 +01:00
325518ba15 Update README.md 2021-09-01 11:10:02 +02:00
4b80912727 Merge pull request #11 from stiivo/patch-1
Update README.md
2021-09-01 10:58:13 +02:00
Steven Günther
c78ad636c3 Update README.md
typo
2021-09-01 10:19:15 +02:00
4fe7833977 Update README.md 2021-06-01 12:23:08 +02:00
24f9aeb229 arm images 2021-05-19 11:29:33 +02:00
976413e11b limit min height 2021-05-17 09:45:01 +02:00
2480d875b4 about page 2021-05-16 12:47:52 +02:00
5dff12ea70 use hash instead of path for key 2021-05-16 11:16:25 +02:00
e332dc63e8 on push 2021-05-14 15:09:55 +02:00
a18e9bcc88 Merge pull request #7 from cupcakearmy/testing
use docker-compose
2021-05-14 14:48:56 +02:00
4b43edf54a use docker-compose 2021-05-14 14:48:34 +02:00
e3aa2dd5ff Update test.yml 2021-05-10 10:13:05 +02:00
98a03c25e6 Merge pull request #6 from cupcakearmy/testing
Testing
2021-05-10 10:11:59 +02:00
7f618e7e45 ci 2021-05-10 10:11:31 +02:00
84a7be4549 config 2021-05-10 10:04:19 +02:00
b2bad5f64c cypress runner 2021-05-10 09:58:21 +02:00
41f55c0920 test ids 2021-05-10 09:58:13 +02:00
edbf8a8ecf changelog 2021-05-08 21:47:13 +02:00
4852804581 time bug 2021-05-08 21:47:08 +02:00
22b1c35b3e loading state 2021-05-08 21:46:52 +02:00
d1e9ffd89b up the iterations 2021-05-08 21:46:43 +02:00
9c675ba48c notes about availability 2021-05-08 21:46:33 +02:00
ef3d3d5bde changelog 2021-05-08 10:34:18 +02:00
7e835af3f2 changelog 2021-05-08 10:17:20 +02:00
f153102978 bug 2021-05-08 10:16:05 +02:00
5944c784ba changelog 2021-05-07 14:12:23 +02:00
2aa186450a one less dependency 2021-05-07 14:09:26 +02:00
70b53106ea use svg as text 2021-05-07 12:14:07 +02:00
b958189b0c update dependencies 2021-05-07 11:57:28 +02:00
acd488aab0 typos 2021-05-05 10:52:10 +02:00
5378b7a820 changelog 2021-05-05 10:44:38 +02:00
1bb5d3ecb0 ios appearance and theme override 2021-05-05 10:42:37 +02:00
0d79e9c85e remove arm builds for now 2021-05-05 09:57:30 +02:00
70382a63ed slash at the end 2021-05-04 19:45:19 +02:00
b3886cc6fc add depends on 2021-05-04 19:30:25 +02:00
cfe525f274 arm images 2021-05-03 18:53:45 +02:00
96e8ec4b67 Update README.md 2021-05-03 12:38:51 +02:00
7a3397f978 always encrypt content 2021-05-03 12:21:51 +02:00
dc212d7441 docs 2021-05-03 12:21:44 +02:00
6e04594b4d changelog 2021-05-03 11:26:04 +02:00
b6834aa829 logos 2021-05-03 11:10:53 +02:00
093a6c5c2b comments 2021-05-02 19:03:16 +02:00
82 changed files with 2908 additions and 3324 deletions

View File

@@ -1 +1,2 @@
target
/**/target
/**/node_modules

View File

@@ -14,6 +14,8 @@ jobs:
uses: docker/setup-qemu-action@v1
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v1
with:
install: true
- name: Docker Labels
id: meta
uses: crazy-max/ghaction-docker-meta@v2
@@ -32,6 +34,7 @@ jobs:
id: docker_build
uses: docker/build-push-action@v2
with:
platforms: linux/amd64,linux/arm64
push: true
tags: ${{ steps.meta.outputs.tags }}
- name: Image digest

3
.gitignore vendored
View File

@@ -1,6 +1,6 @@
# Backend
/target
target
# Client
.DS_Store
@@ -8,3 +8,4 @@ node_modules
/.svelte
/build
/functions
.env

View File

@@ -5,35 +5,150 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [1.3.3] - 2022-01-03
### Fixed
- Bug fix due to dependency update.
## [1.3.2] - 2022-01-02
### Changed
- Dependencies updates.
- Folder structure.
## [1.3.1] - 2021-12-30
### Added
- Short explanation in the home page.
### Changed
- Explanation in about & readme.
- Shorten server ids from 512 to 256bit.
## [1.3.0] - 2021-12-22
### Added
- Option to set a custom size limit.
- Options to share files.
### Changed
- Don't delete note if time is not expired yet
- Use pnpm instead of npm.
## [1.2.0] - 2021-11-11
### Changed
- Switch to pnpm.
### Security
- Dependencies updated.
## [1.1.1] - 2021-05-17
### Fixed
- Height on big displays.
- About page.
## [1.1.0] - 2021-05-16
### Security
- Using hash `#` instead of path.
## [1.0.11] - 2021-05-08
### Added
- loading text.
- description for created notes about availability.
### Changed
- iterations from 100 to 100k.
### Fixed
- time based view bug.
## [1.0.10] - 2021-05-08
### Fixed
- API endpoint was not reachable.
## [1.0.9] - 2021-05-07
## Changed
- Removed a dependency.
## [1.0.8] - 2021-05-05
### Added
- Manual theme override option.
### Fixed
- Removed Arm builds for now.
- iOS style bugs.
## [1.0.7] - 2021-05-04
### Added
- Arm images.
## [1.0.6] - 2021-05-04
### Added
- Always use encryption with random passwords included links.
## [1.0.5] - 2021-05-03
### Fixed
- Typos.
## [1.0.4] - 2021-05-02
### Added
- From scratch docker image
- From scratch docker image.
## [1.0.3] - 2021-05-02
### Fixed
- Higher default text area
- Mobile touchups
- Higher default text area.
- Mobile touchups.
## [1.0.2] - 2021-05-02
### Fixed
- SVG Icons
- SVG Icons.
## [1.0.1] - 2021-05-02
### Added
- Dark mode support
- Dark mode support.
### Fixed
- Don't reload data on wrong password
- Don't reload data on wrong password.
## [1.0.0] - 2021-05-02
Initial release
Initial release.

View File

@@ -1,26 +1,31 @@
# Client
FROM node:16-alpine as CLIENT
WORKDIR /tmp
COPY ./client .
COPY ./frontend ./
RUN npm ci
RUN npm run build
RUN npm install -g pnpm
RUN pnpm install
RUN pnpm run build
FROM rust:1.51-alpine as RUST
# Rust
FROM rust:1.56-alpine as RUST
WORKDIR /tmp
RUN apk add libc-dev openssl-dev alpine-sdk
COPY ./Cargo* .
COPY ./src ./src
COPY ./backend ./
RUN cargo build --release
FROM scratch
# Server
FROM alpine
WORKDIR /app
COPY --from=RUST /tmp/target/release/cryptgeon .
COPY --from=CLIENT /tmp/build ./client/build
COPY --from=CLIENT /tmp/build ./frontend/build
ENV MEMCACHE=memcached:11211
ENTRYPOINT [ "/app/cryptgeon" ]
EXPOSE 5000
ENTRYPOINT [ "/app/cryptgeon" ]

View File

@@ -1,14 +1,21 @@
<p align="center">
<img src="./design/Github.png">
<img src="./design/Github.png" alt="logo">
</p>
![Docker pulls badge](https://img.shields.io/docker/pulls/cupcakearmy/cryptgeon)
![Docker image size badge](https://img.shields.io/docker/image-size/cupcakearmy/cryptgeon)
![Latest version](https://img.shields.io/github/v/release/cupcakearmy/cryptgeon)
<a href="https://discord.gg/nuby6RnxZt">
<img alt="discord" src="https://img.shields.io/discord/252403122348097536?style=for-the-badge" />
<img alt="docker pulls" src="https://img.shields.io/docker/pulls/cupcakearmy/cryptgeon?style=for-the-badge" />
<img alt="Docker image size badge" src="https://img.shields.io/docker/image-size/cupcakearmy/cryptgeon?style=for-the-badge" />
<img alt="Latest version" src="https://img.shields.io/github/v/release/cupcakearmy/cryptgeon?style=for-the-badge" />
</a>
<br/>
<a href="https://www.producthunt.com/posts/cryptgeon?utm_source=badge-featured&utm_medium=badge&utm_souce=badge-cryptgeon" target="_blank"><img src="https://api.producthunt.com/widgets/embed-image/v1/featured.svg?post_id=295189&theme=light" alt="Cryptgeon - Securely share self-destructing notes | Product Hunt" style="width: 250px; height: 54px;" width="250" height="54" /></a>
<br/>
## About?
_cryptgeon_ is an secure, open source sharing note service inspired by [_PrivNote_](https://privnote.com)
_cryptgeon_ is a secure, open source sharing note or file service inspired by [_PrivNote_](https://privnote.com)
## Demo
@@ -16,21 +23,37 @@ Check out the demo and see for yourself https://cryptgeon.nicco.io.
## Features
- view and time constrains
- server cannot decrypt contents due to client side encryption
- view or time constraints
- in memory, no persistence
- in browser encryption → server cannot decrypt contents
- obligatory dark mode support
## How does it work?
each note has a 512bit generated <i>id</i> that is used to retrieve the note. data is stored in memory and never persisted to disk.
each note has a generated <code>id (256bit)</code> and <code>key 256(bit)</code>. The
<code>id</code>
is used to save & retrieve the note. the note is then encrypted with aes in gcm mode on the
client side with the <code>key</code> and then sent to the server. data is stored in memory and
never persisted to disk. the server never sees the encryption key and cannot decrypt the contents
of the notes even if it tried to.
## Screenshot
![screenshot](./design/Screens.png)
## Environment Variables
| Variable | Default | Description |
| ------------ | ----------------- | --------------------------------------------------------------------------------------- |
| `MEMCACHE` | `memcached:11211` | Memcached URL to connect to. |
| `SIZE_LIMIT` | `1 KiB` | Max size for body. Accepted values according to [byte-unit](https://docs.rs/byte-unit/) |
## Deployment
`https` is required otherwise browsers will not support the cryptographic functions.
### Docker
Docker is the easiest way. There is the [official image here](https://hub.docker.com/r/cupcakearmy/cryptgeon).
```yaml
@@ -41,19 +64,64 @@ version: '3.7'
services:
memcached:
image: memcached:1-alpine
entrypoint: memcached -m 128 # Limit to 128 MB Ram, customize at free will.
entrypoint: memcached -m 128M -I 4M # Limit to 128 MB Ram, 4M per entry, customize at free will.
app:
image: cupcakearmy/cryptgeon:latest
depends_on:
- memcached
environment:
SIZE_LIMIT: 4M
ports:
- 80:5000
```
### NGINX Proxy
See the [examples/nginx](https://github.com/cupcakearmy/cryptgeon/tree/main/examples/nginx) folder. There an example with a simple proxy, and one with https. You need to specify the server names and certificates.
### Traefik 2
Assumptions:
- External proxy docker network `proxy`
- A certificate resolver `le`
- A https entrypoint `secure`
- Domain name `example.org`
```yaml
version: '3.8'
networks:
proxy:
external: true
services:
memcached:
image: memcached:1-alpine
restart: unless-stopped
entrypoint: memcached -m 128M -I 4M # Limit to 128 MB Ram, 4M per entry, customize at free will.
app:
image: cupcakearmy/cryptgeon:latest
restart: unless-stopped
depends_on:
- memcached
networks:
- default
- proxy
labels:
- traefik.enable=true
- traefik.http.routers.cryptgeon.rule=Host(`example.org`)
- traefik.http.routers.cryptgeon.entrypoints=secure
- traefik.http.routers.cryptgeon.tls.certresolver=le
```
## Development
1. Clone
2. run `npm i` in the root and and client `client/` folders.
3. Run `npm run dev` to start development.
2. run `pnpm i` in the root and and client `client/` folders.
3. Run `pnpm run dev` to start development.
Running `npm run dev` in the root folder will start the following things
@@ -61,7 +129,7 @@ Running `npm run dev` in the root folder will start the following things
- rust backend with hot reload
- client with hot reload
You can see the app under [localhost:3000](http://localhost:3000).
You can see the app under [localhost:1234](http://localhost:1234).
###### Attributions

File diff suppressed because it is too large Load Diff

View File

@@ -1,8 +1,8 @@
[package]
name = "cryptgeon"
version = "1.0.0"
version = "1.3.3"
authors = ["cupcakearmy <hi@nicco.io>"]
edition = "2018"
edition = "2021"
[[bin]]
name = "cryptgeon"
@@ -18,4 +18,7 @@ serde_json = "1"
lazy_static = "1"
ring = "0.16"
bs62 = "0.1"
memcache = "0.15"
memcache = "0.16"
byte-unit = "4"
dotenv = "0.15"
mime = "0.3"

View File

@@ -2,9 +2,9 @@ use actix_files::{Files, NamedFile};
use actix_web::{web, Responder};
pub fn init(cfg: &mut web::ServiceConfig) {
cfg.service(Files::new("/", "./client/build").index_file("index.html"));
cfg.service(Files::new("/", "./frontend/build").index_file("index.html"));
}
pub async fn fallback_fn() -> impl Responder {
NamedFile::open("./client/build/index.html")
NamedFile::open("./frontend/build/index.html")
}

View File

@@ -1,23 +1,27 @@
use actix_web::{middleware, web, App, HttpServer};
use dotenv::dotenv;
#[macro_use]
extern crate lazy_static;
mod client;
mod note;
mod size;
mod store;
#[actix_web::main]
async fn main() -> std::io::Result<()> {
HttpServer::new(|| {
dotenv().ok();
return HttpServer::new(|| {
App::new()
.wrap(middleware::Compress::default())
.wrap(middleware::DefaultHeaders::default())
.configure(size::init)
.configure(note::init)
.configure(client::init)
.default_service(web::resource("").route(web::get().to(client::fallback_fn)))
})
.bind("0.0.0.0:5000")?
.run()
.await
.await;
}

View File

@@ -4,24 +4,23 @@ use serde::{Deserialize, Serialize};
#[derive(Serialize, Deserialize, Clone)]
pub struct Note {
pub meta: String,
pub contents: String,
pub password: bool,
pub views: Option<u8>,
pub expiration: Option<u64>,
pub expiration: Option<u32>,
}
#[derive(Serialize, Deserialize, Clone)]
pub struct NoteInfo {
pub password: bool,
}
pub struct NoteInfo {}
#[derive(Serialize, Deserialize, Clone)]
pub struct NotePublic {
pub meta: String,
pub contents: String,
}
pub fn generate_id() -> String {
let mut id: [u8; 64] = [0; 64];
let mut id: [u8; 32] = [0; 32];
let sr = ring::rand::SystemRandom::new();
let _ = sr.fill(&mut id);
return bs62::encode_data(&id);

View File

@@ -3,13 +3,14 @@ use serde::{Deserialize, Serialize};
use std::time::SystemTime;
use crate::note::{generate_id, Note, NoteInfo, NotePublic};
use crate::size::LIMIT;
use crate::store;
fn now() -> u64 {
pub fn now() -> u32 {
SystemTime::now()
.duration_since(SystemTime::UNIX_EPOCH)
.unwrap()
.as_secs()
.as_secs() as u32
}
#[derive(Serialize, Deserialize)]
@@ -17,17 +18,13 @@ struct NotePath {
id: String,
}
#[get("/notes/{id}")]
#[get("/{id}")]
async fn one(path: web::Path<NotePath>) -> impl Responder {
let p = path.into_inner();
let note = store::get(&p.id);
match note {
None => return HttpResponse::NotFound().finish(),
Some(note) => {
return HttpResponse::Ok().json(NoteInfo {
password: note.password,
})
}
Some(_) => return HttpResponse::Ok().json(NoteInfo {}),
}
}
@@ -36,14 +33,11 @@ struct CreateResponse {
id: String,
}
#[post("/notes")]
#[post("/")]
async fn create(note: web::Json<Note>) -> impl Responder {
let mut n = note.into_inner();
let id = generate_id();
let bad_req = HttpResponse::BadRequest().finish();
if n.contents.chars().count() > 8192 {
return bad_req;
}
if n.views == None && n.expiration == None {
return bad_req;
}
@@ -60,7 +54,8 @@ async fn create(note: web::Json<Note>) -> impl Responder {
if e > 360 {
return bad_req;
}
n.expiration = Some(now() + (e * 60))
let expiration = now() + (e * 60);
n.expiration = Some(expiration);
}
_ => {}
}
@@ -68,7 +63,7 @@ async fn create(note: web::Json<Note>) -> impl Responder {
return HttpResponse::Ok().json(CreateResponse { id: id });
}
#[delete("/notes/{id}")]
#[delete("/{id}")]
async fn delete(path: web::Path<NotePath>) -> impl Responder {
let p = path.into_inner();
let note = store::get(&p.id);
@@ -91,9 +86,11 @@ async fn delete(path: web::Path<NotePath>) -> impl Responder {
}
_ => {}
}
let n = now();
match changed.expiration {
Some(e) => {
if e > now() {
if e < n {
store::del(&p.id.clone());
return HttpResponse::BadRequest().finish();
}
@@ -102,19 +99,39 @@ async fn delete(path: web::Path<NotePath>) -> impl Responder {
}
return HttpResponse::Ok().json(NotePublic {
contents: changed.contents,
meta: changed.meta,
});
}
}
}
#[derive(Serialize, Deserialize)]
struct Status {
version: String,
max_size: usize,
}
#[get("/status")]
async fn status() -> impl Responder {
println!("Limit: {}", *LIMIT);
return HttpResponse::Ok().json(Status {
version: option_env!("CARGO_PKG_VERSION")
.unwrap_or("Unknown")
.to_string(),
max_size: *LIMIT,
});
}
pub fn init(cfg: &mut web::ServiceConfig) {
cfg.service(
web::scope("/api")
.service(create)
.service(delete)
.service(one),
.service(
web::scope("/notes")
.service(one)
.service(create)
.service(delete)
.service(status),
)
.service(status),
);
// cfg.service(create);
// cfg.service(delete);
// cfg.service(one);
}

20
backend/src/size.rs Normal file
View File

@@ -0,0 +1,20 @@
use actix_web::web;
use byte_unit::Byte;
use mime;
lazy_static! {
pub static ref LIMIT: usize =
Byte::from_str(std::env::var("SIZE_LIMIT").unwrap_or("1 KiB".to_string()))
.unwrap()
.get_bytes() as usize;
}
pub fn init(cfg: &mut web::ServiceConfig) {
println!("Limit: {}", *LIMIT);
let json = web::JsonConfig::default().limit(*LIMIT);
let plain = web::PayloadConfig::default()
.limit(*LIMIT)
.mimetype(mime::STAR_STAR);
cfg.data(json);
cfg.data(plain);
}

View File

@@ -1,5 +1,6 @@
use memcache;
use crate::note::now;
use crate::note::Note;
lazy_static! {
@@ -12,7 +13,11 @@ lazy_static! {
pub fn set(id: &String, note: &Note) {
let serialized = serde_json::to_string(&note.clone()).unwrap();
CLIENT.set(id, serialized, 0).unwrap();
let expiration: u32 = match note.expiration {
Some(e) => e - now(),
None => 0,
};
CLIENT.set(id, serialized, expiration).unwrap();
}
pub fn get(id: &String) -> Option<Note> {

1000
client/package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,24 +0,0 @@
{
"private": true,
"scripts": {
"dev": "svelte-kit dev",
"build": "svelte-kit build",
"preview": "svelte-kit preview",
"licenses": "npx license-checker --summary > licenses.csv"
},
"devDependencies": {
"@sveltejs/adapter-static": "next",
"@sveltejs/kit": "next",
"svelte": "^3.34.0",
"svelte-preprocess": "^4.0.0",
"tslib": "^2.0.0",
"typescript": "^4.0.0",
"vite": "^2.1.0"
},
"type": "module",
"dependencies": {
"@fontsource/fira-mono": "^4.2.2",
"axios": "^0.21.1",
"copy-to-clipboard": "^3.3.1"
}
}

View File

@@ -1,80 +0,0 @@
@import '@fontsource/fira-mono';
* {
box-sizing: border-box;
}
:root {
font-family: 'Fira Mono', monospace;
--ui-bg-0: #fefefe;
--ui-bg-0-85: #fefefed9;
--ui-bg-1: #eee;
--ui-bg-2: #e2e2e2;
--ui-text-0: #111;
--ui-text-1: #222;
--ui-clr-primary: hsl(186, 65%, 55%);
--ui-clr-error: hsl(357, 77%, 51%);
--ui-anim: all 150ms ease;
}
@media (prefers-color-scheme: dark) {
:root {
--ui-bg-0: #111;
--ui-bg-0-85: #111111d9;
--ui-bg-1: #222;
--ui-bg-2: #282828;
--ui-text-0: #fefefe;
--ui-text-1: #eee;
}
}
.error-text {
color: var(--ui-clr-error);
}
body {
min-height: 100vh;
margin: 0;
background-color: var(--ui-bg-0);
color: var(--ui-text-0);
}
a {
color: inherit;
text-decoration: inherit;
box-sizing: content-box;
border-bottom: 2px solid var(--ui-bg-2);
cursor: pointer;
}
a:active {
border-color: var(--ui-clr-primary);
}
a:hover {
border-color: var(--ui-text-0);
}
input,
textarea,
button {
appearance: none;
transition: var(--ui-anim);
font-family: inherit;
font-size: inherit;
background: inherit;
color: inherit;
}
*:disabled,
*[disabled='true'] {
opacity: 0.5;
}
fieldset {
margin: 0;
padding: 0;
border: none;
}

View File

@@ -1,38 +0,0 @@
import axios from 'axios'
import { dev } from '$app/env'
const base = axios.create({ baseURL: dev ? 'http://localhost:5000' : undefined })
export type Note = {
contents: string
password: boolean
views?: number
expiration?: number
}
export type NoteInfo = Pick<Note, 'password'>
export type NotePublic = Pick<Note, 'contents'>
export async function create(note: Note) {
const { data } = await base({
url: '/api/notes',
method: 'post',
data: note,
})
return data as { id: string }
}
export async function get(id: string) {
const { data } = await base({
url: `/api/notes/${id}`,
method: 'delete',
})
return data as NotePublic
}
export async function info(id: string) {
const { data } = await base({
url: `/api/notes/${id}`,
method: 'get',
})
return data as NoteInfo
}

View File

@@ -1,34 +0,0 @@
<script lang="ts">
export let label: string = ''
export let value: string
</script>
<label>
<small>
{label}
</small>
<textarea {...$$restProps} bind:value />
</label>
<style>
textarea {
width: 100%;
min-height: calc(100vh - 30rem);
margin: 0;
border: 2px solid var(--ui-bg-1);
resize: vertical;
outline: none;
padding: 0.5rem;
}
@media screen and (max-width: 30rem) {
textarea {
min-height: calc(100vh - 25rem);
}
}
textarea:hover,
textarea:focus {
border-color: var(--ui-clr-primary);
}
</style>

View File

@@ -1,159 +0,0 @@
<script lang="ts">
import type { Note } from '$lib/api'
import { create } from '$lib/api'
import { getKeyFromString, encrypt } from '$lib/crypto'
import Button from '$lib/ui/Button.svelte'
import Switch from '$lib/ui/Switch.svelte'
import TextArea from '$lib/ui/TextArea.svelte'
import TextInput from '$lib/ui/TextInput.svelte'
let note: Note = {
contents: '',
password: false,
views: 1,
expiration: 60,
}
let password: string = ''
let result: { password: string; id: string } | null = null
let advanced = false
let type = false
let message = ''
let loading = false
let error: string | null = null
$: if (!advanced) {
note.views = 1
type = false
}
$: {
let fraction: string
fraction = type ? `${note.expiration} minutes` : `${note.views} views`
message = 'the note will expire and be destroyed after ' + fraction
}
async function submit() {
try {
error = null
loading = true
const data: Note = {
contents: note.contents,
password: !!password,
}
// @ts-ignore
if (type) data.expiration = parseInt(note.expiration)
// @ts-ignore
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)
result = {
password: password,
id: response.id,
}
} catch {
error = 'could not create note.'
} finally {
loading = false
}
}
function reset() {
window.location.reload()
}
</script>
{#if result}
{#if result.password}
<TextInput type="password" readonly value={result.password} copy />
<br />
{/if}
<TextInput type="text" readonly value="{window.location.origin}/note/{result.id}" copy />
<br />
<Button on:click={reset}>new</Button>
{:else}
<form on:submit|preventDefault={submit}>
<fieldset disabled={loading}>
<TextArea label="note" bind:value={note.contents} placeholder="..." />
<div class="bottom">
<Switch label="advanced" bind:value={advanced} />
<Button type="submit">create</Button>
</div>
{#if error}
<div class="error-text">{error}</div>
{/if}
<p><br />{message}</p>
<div class="advanced" class:hidden={!advanced}>
<br />
<div class="fields">
<TextInput
type="number"
label="views"
bind:value={note.views}
disabled={type}
max={100}
/>
<div class="middle-switch">
<Switch label="mode" bind:value={type} color={false} />
</div>
<TextInput
type="number"
label="minutes"
bind:value={note.expiration}
disabled={!type}
max={360}
/>
</div>
<br />
<TextInput
type="password"
label="password"
placeholder="optional"
bind:value={password}
copy
random
/>
</div>
<style>
.fields {
display: flex;
}
.spacer {
width: 3rem;
}
</style>
</fieldset>
</form>
{/if}
<style>
.bottom {
display: flex;
justify-content: space-between;
align-items: flex-end;
margin-top: 0.5rem;
}
.middle-switch {
margin: 0 1rem;
}
.advanced {
max-height: 14em;
overflow: hidden;
transition: var(--ui-anim);
}
.advanced.hidden {
max-height: 0;
}
</style>

View File

@@ -1 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg width="100%" height="100%" viewBox="0 0 475 200" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;"><g id="Logo"><clipPath id="_clip1"><rect x="4.516" y="3.225" width="193.55" height="193.55"/></clipPath><g clip-path="url(#_clip1)"><g><g><path d="M171.604,43.296c-2.087,-0 -3.78,1.693 -3.78,3.78c-0,2.087 1.693,3.78 3.78,3.78c2.087,0 3.78,-1.693 3.78,-3.78c0,-2.087 -1.693,-3.78 -3.78,-3.78Z" style="fill-rule:nonzero;"/></g></g><g><g><path d="M101.291,134.023c-2.087,-0 -3.78,1.693 -3.78,3.78c-0,2.087 1.693,3.78 3.78,3.78c2.087,0 3.78,-1.693 3.78,-3.78c0,-2.087 -1.693,-3.78 -3.78,-3.78Z" style="fill-rule:nonzero;"/></g></g><g><g><path d="M154.215,96.22c-2.088,-0 -3.78,1.692 -3.78,3.78c-0,18.76 -15.263,34.023 -34.023,34.023c-2.088,-0 -3.78,1.692 -3.78,3.78c-0,2.088 1.692,3.78 3.78,3.78c22.929,0 41.583,-18.654 41.583,-41.583c0,-2.088 -1.692,-3.78 -3.78,-3.78Z" style="fill-rule:nonzero;"/></g></g><g><g><path d="M197.667,60.507l-9.515,-19.026c-4.101,-8.207 -12.349,-13.306 -21.526,-13.306c-7.48,-0 -14.627,3.547 -19.155,9.498l-10.678,12.016c-2.847,-4.047 -7.021,-7.049 -11.831,-8.421l-19.102,-5.459c-14.623,-4.178 -28.92,-15.441 -39.227,-30.901c-0.924,-1.386 -2.646,-2.003 -4.24,-1.521c-1.595,0.483 -2.685,1.953 -2.685,3.618l-0,20.372c-0,9.468 1.418,18.804 4.219,27.813c-2.936,0.73 -5.896,1.34 -8.842,1.816c-5.773,0.936 -11.654,1.411 -17.48,1.411l-29.309,-0c-1.374,-0 -2.64,0.746 -3.306,1.948c-0.666,1.202 -0.628,2.671 0.101,3.836l22.636,36.219c9.672,15.473 26.33,25.183 44.578,25.983l-36.36,41.158c-5.602,5.728 -3.654,15.315 3.746,18.396l20.018,9.887c0.088,0.044 0.179,0.084 0.271,0.121c5.789,2.313 12.389,-0.496 14.725,-6.279l13.969,-32.982l27.738,0c31.966,0 58.972,-25.967 58.972,-56.704l0,-22.682c0,-6.253 5.088,-11.341 11.341,-11.341l7.561,0c1.31,0 2.527,-0.678 3.216,-1.793c0.688,-1.114 0.751,-2.506 0.165,-3.677Zm-130.399,-42.236c10.418,12.203 23.307,21.034 36.515,24.808l19.104,5.459c3.725,1.063 6.865,3.624 8.666,7.048l-10.049,11.307l-17.652,-10.591c-7.646,-4.588 -16.746,-6.412 -25.776,-4.951c-2.837,0.46 -4.648,1.038 -6.877,1.759c-2.609,-8.332 -3.931,-16.971 -3.931,-25.733l0,-9.106Zm119.457,40.146c-10.422,-0 -18.901,8.479 -18.901,18.901l-0,22.682c-0,26.639 -23.544,49.144 -51.412,49.144l-30.242,-0c-10.771,-0 -20.452,5.983 -25.265,15.615l-0.798,1.596c-0.934,1.867 -0.177,4.137 1.691,5.071c1.867,0.934 4.138,0.176 5.072,-1.691c0.44,-0.586 3.306,-9.102 13.21,-12.125l-12.349,29.159c-0.01,0.024 -0.02,0.047 -0.03,0.071c-0.75,1.877 -2.864,2.851 -4.8,2.148c-21.279,-10.506 -19.997,-9.888 -20.252,-9.99c-2.526,-1.01 -3.191,-4.259 -1.267,-6.182c0.131,-0.131 8.026,-9.078 41.009,-46.411c13.867,-0.617 26.842,-6.319 36.694,-16.172c1.477,-1.476 1.477,-3.87 0,-5.346c-1.476,-1.477 -3.869,-1.476 -5.346,-0c-16.827,16.828 -36.803,13.634 -39.027,14.014c-16.604,0 -31.772,-8.407 -40.574,-22.488l-2.417,-3.868l2.729,1.065c17.308,6.753 38.919,4.347 53.817,-5.586c1.737,-1.158 2.206,-3.505 1.048,-5.242c-1.158,-1.737 -3.505,-2.207 -5.243,-1.048c-13.085,8.724 -31.922,10.666 -46.874,4.832l-12.185,-4.753l-9.896,-15.836l22.488,0c6.23,0 12.518,-0.507 18.688,-1.507c12.711,-2.055 18.051,-4.855 22.993,-5.655c7.181,-1.163 14.516,0.274 20.677,3.97l29.625,17.775c1.79,1.074 4.112,0.494 5.187,-1.296c1.074,-1.79 0.494,-4.113 -1.296,-5.187l-5.377,-3.226c26.559,-29.893 25.139,-28.272 25.319,-28.511c3.102,-4.136 8.038,-6.605 13.205,-6.605c6.293,0 11.95,3.497 14.764,9.127l6.779,13.555l-1.444,-0Z" style="fill-rule:nonzero;"/></g></g></g><text x="195.418px" y="127.131px" style="font-family:'Sofia-Regular', 'Sofia';font-size:60.681px;">cryptogeon</text></g></svg>

Before

Width:  |  Height:  |  Size: 3.8 KiB

View File

@@ -1,85 +0,0 @@
<script lang="ts">
</script>
<header>
<a href="/">
<svg
width="100%"
height="100%"
viewBox="0 0 475 200"
version="1.1"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
xml:space="preserve"
style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;"
fill="currentColor"
><g id="Logo"
><clipPath id="_clip1"><rect x="4.516" y="3.225" width="193.55" height="193.55" /></clipPath
><g clip-path="url(#_clip1)"
><g
><g
><path
d="M171.604,43.296c-2.087,-0 -3.78,1.693 -3.78,3.78c-0,2.087 1.693,3.78 3.78,3.78c2.087,0 3.78,-1.693 3.78,-3.78c0,-2.087 -1.693,-3.78 -3.78,-3.78Z"
style="fill-rule:nonzero;"
/></g
></g
><g
><g
><path
d="M101.291,134.023c-2.087,-0 -3.78,1.693 -3.78,3.78c-0,2.087 1.693,3.78 3.78,3.78c2.087,0 3.78,-1.693 3.78,-3.78c0,-2.087 -1.693,-3.78 -3.78,-3.78Z"
style="fill-rule:nonzero;"
/></g
></g
><g
><g
><path
d="M154.215,96.22c-2.088,-0 -3.78,1.692 -3.78,3.78c-0,18.76 -15.263,34.023 -34.023,34.023c-2.088,-0 -3.78,1.692 -3.78,3.78c-0,2.088 1.692,3.78 3.78,3.78c22.929,0 41.583,-18.654 41.583,-41.583c0,-2.088 -1.692,-3.78 -3.78,-3.78Z"
style="fill-rule:nonzero;"
/></g
></g
><g
><g
><path
d="M197.667,60.507l-9.515,-19.026c-4.101,-8.207 -12.349,-13.306 -21.526,-13.306c-7.48,-0 -14.627,3.547 -19.155,9.498l-10.678,12.016c-2.847,-4.047 -7.021,-7.049 -11.831,-8.421l-19.102,-5.459c-14.623,-4.178 -28.92,-15.441 -39.227,-30.901c-0.924,-1.386 -2.646,-2.003 -4.24,-1.521c-1.595,0.483 -2.685,1.953 -2.685,3.618l-0,20.372c-0,9.468 1.418,18.804 4.219,27.813c-2.936,0.73 -5.896,1.34 -8.842,1.816c-5.773,0.936 -11.654,1.411 -17.48,1.411l-29.309,-0c-1.374,-0 -2.64,0.746 -3.306,1.948c-0.666,1.202 -0.628,2.671 0.101,3.836l22.636,36.219c9.672,15.473 26.33,25.183 44.578,25.983l-36.36,41.158c-5.602,5.728 -3.654,15.315 3.746,18.396l20.018,9.887c0.088,0.044 0.179,0.084 0.271,0.121c5.789,2.313 12.389,-0.496 14.725,-6.279l13.969,-32.982l27.738,0c31.966,0 58.972,-25.967 58.972,-56.704l0,-22.682c0,-6.253 5.088,-11.341 11.341,-11.341l7.561,0c1.31,0 2.527,-0.678 3.216,-1.793c0.688,-1.114 0.751,-2.506 0.165,-3.677Zm-130.399,-42.236c10.418,12.203 23.307,21.034 36.515,24.808l19.104,5.459c3.725,1.063 6.865,3.624 8.666,7.048l-10.049,11.307l-17.652,-10.591c-7.646,-4.588 -16.746,-6.412 -25.776,-4.951c-2.837,0.46 -4.648,1.038 -6.877,1.759c-2.609,-8.332 -3.931,-16.971 -3.931,-25.733l0,-9.106Zm119.457,40.146c-10.422,-0 -18.901,8.479 -18.901,18.901l-0,22.682c-0,26.639 -23.544,49.144 -51.412,49.144l-30.242,-0c-10.771,-0 -20.452,5.983 -25.265,15.615l-0.798,1.596c-0.934,1.867 -0.177,4.137 1.691,5.071c1.867,0.934 4.138,0.176 5.072,-1.691c0.44,-0.586 3.306,-9.102 13.21,-12.125l-12.349,29.159c-0.01,0.024 -0.02,0.047 -0.03,0.071c-0.75,1.877 -2.864,2.851 -4.8,2.148c-21.279,-10.506 -19.997,-9.888 -20.252,-9.99c-2.526,-1.01 -3.191,-4.259 -1.267,-6.182c0.131,-0.131 8.026,-9.078 41.009,-46.411c13.867,-0.617 26.842,-6.319 36.694,-16.172c1.477,-1.476 1.477,-3.87 0,-5.346c-1.476,-1.477 -3.869,-1.476 -5.346,-0c-16.827,16.828 -36.803,13.634 -39.027,14.014c-16.604,0 -31.772,-8.407 -40.574,-22.488l-2.417,-3.868l2.729,1.065c17.308,6.753 38.919,4.347 53.817,-5.586c1.737,-1.158 2.206,-3.505 1.048,-5.242c-1.158,-1.737 -3.505,-2.207 -5.243,-1.048c-13.085,8.724 -31.922,10.666 -46.874,4.832l-12.185,-4.753l-9.896,-15.836l22.488,0c6.23,0 12.518,-0.507 18.688,-1.507c12.711,-2.055 18.051,-4.855 22.993,-5.655c7.181,-1.163 14.516,0.274 20.677,3.97l29.625,17.775c1.79,1.074 4.112,0.494 5.187,-1.296c1.074,-1.79 0.494,-4.113 -1.296,-5.187l-5.377,-3.226c26.559,-29.893 25.139,-28.272 25.319,-28.511c3.102,-4.136 8.038,-6.605 13.205,-6.605c6.293,0 11.95,3.497 14.764,9.127l6.779,13.555l-1.444,-0Z"
style="fill-rule:nonzero;"
/></g
></g
></g
><text
x="195.418px"
y="127.131px"
style="font-family:'Sofia-Regular', 'Sofia';font-size:60.681px;">cryptogeon</text
></g
></svg
>
</a>
</header>
<style>
a {
border: none;
}
header {
text-align: center;
margin-top: 4rem;
margin-bottom: 2rem;
}
@media screen and (max-width: 30rem) {
header {
margin-top: 1rem;
margin-bottom: 1rem;
}
header svg {
max-height: 4rem;
}
}
header svg {
width: 100%;
max-width: 16rem;
transform: translateX(-1rem);
}
</style>

View File

@@ -1,45 +0,0 @@
<script lang="ts">
import '../app.css'
import Header from '$lib/views/Header/index.svelte'
</script>
<svelte:head>
<title>cryptgeon</title>
</svelte:head>
<main>
<Header />
<slot />
</main>
<footer>
<a href="/">/home</a>
<a href="/about">/about</a>
<a href="https://github.com/cupcakearmy/cryptgeon" target="_blank" rel="noopener">/code</a>
</footer>
<style>
a {
margin: 0 0.5rem;
}
main {
padding: 1rem;
padding-bottom: 4rem;
width: 100%;
max-width: 35rem;
margin: 0 auto;
}
footer {
display: flex;
flex-direction: row;
justify-content: flex-end;
align-items: center;
padding: 1rem;
position: fixed;
bottom: 0;
right: 0;
width: 100%;
background-color: var(--ui-bg-0-85);
}
</style>

View File

@@ -1,66 +0,0 @@
<script context="module">
import { browser, dev } from '$app/env'
export const hydrate = dev
export const router = browser
export const prerender = true
</script>
<svelte:head>
<title>About</title>
</svelte:head>
<section class="content">
<h1>About</h1>
<p>
<i>cryptgeon</i> is an secure, open source sharing note service inspired by
<a href="https://privnote.com"><i>PrivNote</i></a>.
</p>
<p>
<b>▶ how does it work?</b>
<br />
each note has a 512bit generated <i>id</i> that is used to retrieve the note. data is stored in memory
and never persisted to disk.
</p>
<b>▶ Features</b>
<ul>
<li>view and time constrains</li>
<li>in memory, no persistence</li>
<li>in browser encryption → server cannot decrypt contents</li>
</ul>
<p>
<b>▶ tech stack</b>
<br />
the backend is written in rust and the frontend is svelte and typescript.
<br />
you are welcomed to check & audit the
<a href="https://github.com/cupcakearmy/cryptgeon" target="_blank" rel="noopener">source code</a
>.
</p>
<p>
<br />
<b>▶ attributions</b>
<br />
<small>
icons made by <a href="https://www.freepik.com" title="Freepik">freepik</a> from
<a href="https://www.flaticon.com/" title="Flaticon">www.flaticon.com</a>
</small>
</p>
</section>
<style>
section {
width: 100%;
}
ul {
margin: 0;
padding: 0;
padding-left: 1rem;
list-style: square;
}
</style>

View File

@@ -1,98 +0,0 @@
<script context="module" lang="ts">
export async function load({ page }) {
return {
props: page.params,
}
}
</script>
<script lang="ts">
import type { NotePublic } from '$lib/api'
import { info, get } from '$lib/api'
import { decrypt, getKeyFromString } from '$lib/crypto'
import Button from '$lib/ui/Button.svelte'
import TextInput from '$lib/ui/TextInput.svelte'
import copy from 'copy-to-clipboard'
import { onMount } from 'svelte'
export let id: string
let needPassword = false
let password: string = ''
let note: NotePublic | null = null
let exists = false
let loading = true
let error = false
onMount(async () => {
try {
loading = true
error = null
const data = await info(id)
needPassword = data.password
exists = true
} catch {
exists = false
} finally {
loading = false
}
})
async function show() {
const data = note || (await get(id)) // Don't get the content twice on wrong password.
if (needPassword) {
try {
const key = await getKeyFromString(password)
data.contents = await decrypt(data.contents, key)
error = false
} catch {
error = true
}
}
note = data
}
</script>
{#if !loading}
{#if !exists}
<p class="error-text">note was not found or was already deleted.</p>
{:else if note && !error}
<p class="error-text">you will not get the chance to see the note again.</p>
<div class="note">
{note.contents}
</div>
<br />
<Button on:click={() => copy(note.contents)}>copy to clipboard</Button>
{:else}
<form on:submit|preventDefault={show}>
<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>
{#if error}
<br />
<p class="error-text">
wrong password. could not decipher.
<br />
note already destroyed. try again without reloading the page.
</p>
{/if}
</form>
{/if}
{/if}
<style>
.note {
width: 100%;
margin: 0;
padding: 0;
border: 2px solid var(--ui-bg-1);
outline: none;
padding: 0.5rem;
white-space: pre;
overflow: auto;
}
</style>

View File

@@ -1,17 +0,0 @@
const preprocess = require('svelte-preprocess')
const adapter = require('@sveltejs/adapter-static')
/** @type {import('@sveltejs/kit').Config} */
module.exports = {
// Consult https://github.com/sveltejs/svelte-preprocess
// for more information about preprocessors
preprocess: preprocess(),
kit: {
adapter: adapter({
fallback: 'index.html',
}),
// hydrate the <div id="svelte"> element in src/app.html
target: '#svelte',
},
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 70 KiB

After

Width:  |  Height:  |  Size: 76 KiB

BIN
design/Logo.afdesign (Stored with Git LFS)

Binary file not shown.

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 3.8 KiB

After

Width:  |  Height:  |  Size: 12 KiB

View File

@@ -1 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg width="100%" height="100%" viewBox="0 0 475 200" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;"><path d="M475,20.713c0,-11.432 -9.281,-20.713 -20.713,-20.713l-433.574,0c-11.432,0 -20.713,9.281 -20.713,20.713l0,158.574c0,11.432 9.281,20.713 20.713,20.713l433.574,0c11.432,0 20.713,-9.281 20.713,-20.713l0,-158.574Z" style="fill:#fff;"/><g id="Logo"><clipPath id="_clip1"><rect x="29.237" y="13.493" width="173.013" height="173.013"/></clipPath><g clip-path="url(#_clip1)"><g><g><path d="M178.596,49.313c-1.865,-0 -3.379,1.513 -3.379,3.379c0,1.865 1.514,3.379 3.379,3.379c1.865,-0 3.379,-1.514 3.379,-3.379c0,-1.866 -1.514,-3.379 -3.379,-3.379Z" style="fill-rule:nonzero;"/></g></g><g><g><path d="M115.744,130.412c-1.866,0 -3.379,1.514 -3.379,3.38c-0,1.865 1.513,3.379 3.379,3.379c1.865,-0 3.379,-1.514 3.379,-3.379c-0,-1.866 -1.514,-3.38 -3.379,-3.38Z" style="fill-rule:nonzero;"/></g></g><g><g><path d="M163.052,96.621c-1.866,-0 -3.379,1.513 -3.379,3.379c-0,16.769 -13.643,30.412 -30.413,30.412c-1.866,0 -3.379,1.513 -3.379,3.38c0,1.866 1.513,3.379 3.379,3.379c20.496,-0 37.171,-16.675 37.171,-37.171c0,-1.866 -1.513,-3.379 -3.379,-3.379Z" style="fill-rule:nonzero;"/></g></g><g><g><path d="M201.894,64.697l-8.506,-17.006c-3.666,-7.337 -11.039,-11.895 -19.242,-11.895c-6.686,-0 -13.075,3.171 -17.122,8.49l-9.545,10.741c-2.545,-3.617 -6.277,-6.301 -10.576,-7.527l-17.075,-4.88c-13.071,-3.735 -25.851,-13.803 -35.064,-27.622c-0.826,-1.239 -2.366,-1.791 -3.791,-1.36c-1.425,0.432 -2.4,1.746 -2.4,3.235l-0,18.21c-0,8.463 1.268,16.809 3.771,24.862c-2.624,0.652 -5.27,1.198 -7.904,1.623c-5.16,0.837 -10.417,1.261 -15.625,1.261l-26.199,0c-1.228,0 -2.36,0.667 -2.955,1.741c-0.595,1.075 -0.561,2.388 0.09,3.429l20.235,32.376c8.646,13.832 23.535,22.511 39.847,23.226l-32.501,36.791c-5.008,5.121 -3.267,13.69 3.348,16.444l17.894,8.838c0.079,0.039 0.16,0.075 0.242,0.108c5.175,2.068 11.074,-0.443 13.163,-5.612l12.487,-29.483l24.794,0c28.575,0 52.715,-23.211 52.715,-50.687l0,-20.275c0,-5.59 4.548,-10.137 10.138,-10.137l6.758,-0c1.171,-0 2.259,-0.607 2.875,-1.603c0.616,-0.996 0.671,-2.241 0.148,-3.288Zm-116.563,-37.754c9.313,10.908 20.834,18.802 32.64,22.176l17.077,4.879c3.33,0.951 6.137,3.24 7.747,6.301l-8.983,10.107l-15.779,-9.467c-6.835,-4.101 -14.969,-5.732 -23.041,-4.426c-2.536,0.411 -4.155,0.927 -6.147,1.573c-2.332,-7.449 -3.514,-15.171 -3.514,-23.003l0,-8.14Zm106.782,35.886c-9.316,0 -16.896,7.58 -16.896,16.896l0,20.275c0,23.812 -21.045,43.929 -45.957,43.929l-27.033,0c-9.627,0 -18.281,5.349 -22.584,13.959l-0.713,1.426c-0.835,1.669 -0.158,3.699 1.511,4.533c1.67,0.835 3.699,0.158 4.534,-1.511c0.393,-0.524 2.955,-8.137 11.808,-10.839l-11.038,26.065c-0.01,0.021 -0.018,0.042 -0.027,0.064c-0.67,1.678 -2.56,2.548 -4.29,1.919c-19.022,-9.39 -17.875,-8.838 -18.104,-8.929c-2.258,-0.903 -2.852,-3.807 -1.132,-5.527c0.116,-0.116 7.174,-8.114 36.658,-41.486c12.395,-0.551 23.993,-5.648 32.8,-14.456c1.32,-1.319 1.32,-3.459 0,-4.779c-1.319,-1.32 -3.459,-1.319 -4.779,0c-15.042,15.043 -32.897,12.188 -34.886,12.528c-14.842,-0 -28.4,-7.515 -36.269,-20.103l-2.16,-3.457l2.439,0.952c15.471,6.036 34.79,3.886 48.107,-4.993c1.552,-1.035 1.972,-3.133 0.937,-4.686c-1.036,-1.553 -3.134,-1.972 -4.687,-0.937c-11.696,7.799 -28.535,9.535 -41.901,4.32l-10.892,-4.249l-8.846,-14.155l20.102,-0c5.57,-0 11.19,-0.454 16.706,-1.348c11.362,-1.837 16.135,-4.34 20.552,-5.055c6.42,-1.039 12.976,0.245 18.484,3.549l26.481,15.888c1.6,0.961 3.676,0.442 4.637,-1.158c0.96,-1.6 0.441,-3.676 -1.159,-4.636l-4.806,-2.884c23.741,-26.721 22.472,-25.272 22.633,-25.486c2.772,-3.697 7.185,-5.904 11.803,-5.904c5.626,0 10.683,3.126 13.198,8.159l6.059,12.116l-1.29,0Z" style="fill-rule:nonzero;"/></g></g></g><text x="199.883px" y="124.252px" style="font-family:'Sofia-Regular', 'Sofia';font-size:54.242px;">cryptogeon</text></g></svg>

Before

Width:  |  Height:  |  Size: 4.0 KiB

View File

@@ -6,11 +6,16 @@ version: '3.7'
services:
memcached:
image: memcached:1-alpine
entrypoint: memcached -m 128
restart: unless-stopped
entrypoint: memcached -m 128M -I 4M
ports:
- 11211:11211
app:
build: .
depends_on:
- memcached
environment:
SIZE_LIMIT: 4M
ports:
- 80:5000

View File

@@ -0,0 +1,22 @@
version: '3.8'
services:
memcached:
image: memcached:1-alpine
entrypoint: memcached -m 128 # Limit to 128 MB Ram, customize at free will.
app:
image: cupcakearmy/cryptgeon:latest
depends_on:
- memcached
proxy:
image: nginx:alpine
depends_on:
- app
volumes:
- ./nginx-plain.conf:/etc/nginx/conf.d/default.conf
# Or with tls
# - ./nginx-tls.conf:/etc/nginx/conf.d/default.conf
ports:
- 80:80

View File

@@ -0,0 +1,13 @@
server {
listen 80;
listen [::]:80;
server_name _;
location / {
proxy_pass http://app:5000/;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}

View File

@@ -0,0 +1,29 @@
# You should change the server_name to something sensible.
# Also you need to specify the path to the ssl certificates.
server {
listen 80;
listen [::]:80;
server_name _;
# Enforce HTTPS
return 301 https://$server_name$request_uri;
}
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name _;
ssl_certificate /path/to/fullchain.pem;
ssl_certificate_key /path/to/privkey.pem;
ssl_trusted_certificate /path/to/fullchain.pem;
location / {
proxy_pass http://app:5000/;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}

View File

@@ -1,5 +1,6 @@
.DS_Store
node_modules
/.svelte
/.svelte-kit
/build
/functions

View File

@@ -1,4 +1,4 @@
├─ MIT: 43
├─ MIT: 46
├─ MIT*: 2
├─ BSD-3-Clause: 2
├─ ISC: 1
1 ├─ MIT: 43 ├─ MIT: 46
2 ├─ MIT*: 2 ├─ MIT*: 2
3 ├─ BSD-3-Clause: 2 ├─ BSD-3-Clause: 2
4 ├─ ISC: 1 ├─ ISC: 1

25
frontend/package.json Normal file
View File

@@ -0,0 +1,25 @@
{
"private": true,
"scripts": {
"dev": "svelte-kit dev",
"build": "svelte-kit build",
"preview": "svelte-kit preview",
"licenses": "license-checker --summary > licenses.csv"
},
"type": "module",
"devDependencies": {
"@sveltejs/adapter-static": "^1.0.0-next.24",
"@sveltejs/kit": "^1.0.0-next.212",
"svelte": "^3.44.3",
"svelte-preprocess": "^4.10.1",
"tslib": "^2.3.1",
"typescript": "^4.5.4",
"vite": "^2.7.10"
},
"dependencies": {
"@fontsource/fira-mono": "^4.5.0",
"copy-to-clipboard": "^3.3.1",
"file-saver": "^2.0.5",
"pretty-bytes": "^5.6.0"
}
}

649
frontend/pnpm-lock.yaml generated Normal file
View File

@@ -0,0 +1,649 @@
lockfileVersion: 5.3
specifiers:
'@fontsource/fira-mono': ^4.5.0
'@sveltejs/adapter-static': ^1.0.0-next.24
'@sveltejs/kit': ^1.0.0-next.212
copy-to-clipboard: ^3.3.1
file-saver: ^2.0.5
pretty-bytes: ^5.6.0
svelte: ^3.44.3
svelte-preprocess: ^4.10.1
tslib: ^2.3.1
typescript: ^4.5.4
vite: ^2.7.10
dependencies:
'@fontsource/fira-mono': 4.5.0
copy-to-clipboard: 3.3.1
file-saver: 2.0.5
pretty-bytes: 5.6.0
devDependencies:
'@sveltejs/adapter-static': 1.0.0-next.24
'@sveltejs/kit': 1.0.0-next.212_svelte@3.44.3
svelte: 3.44.3
svelte-preprocess: 4.10.1_svelte@3.44.3+typescript@4.5.4
tslib: 2.3.1
typescript: 4.5.4
vite: 2.7.10
packages:
/@fontsource/fira-mono/4.5.0:
resolution: {integrity: sha512-KE+d3wmgq/YKM0BqgUF7p2yeBNi805Nfof1lC1wJ7E9i2EWoC363sGdKG+MQBVm+ei3GYZu+Bo8Xha1w1pkB7g==}
dev: false
/@rollup/pluginutils/4.1.2:
resolution: {integrity: sha512-ROn4qvkxP9SyPeHaf7uQC/GPFY6L/OWy9+bd9AwcjOAWQwxRscoEyAUD8qCY5o5iL4jqQwoLk2kaTKJPb/HwzQ==}
engines: {node: '>= 8.0.0'}
dependencies:
estree-walker: 2.0.2
picomatch: 2.3.1
dev: true
/@sveltejs/adapter-static/1.0.0-next.24:
resolution: {integrity: sha512-lMiwZrZumWRrTQxaj9pFs5oW0h/97spyDl1QjmnkNaA006WeqornoETt31WpU0Lz2/2uYNXvUBBcL1LGc9Vylg==}
dependencies:
tiny-glob: 0.2.9
dev: true
/@sveltejs/kit/1.0.0-next.212_svelte@3.44.3:
resolution: {integrity: sha512-hjpk/Rqrl6hhNf1Qsx6EDvL3Cm9JvmvW/Z1FRYVhGg1xin/JQkPgFzTU27NBSYhtK1t4buLmlO1tqdMvurs9Fg==}
engines: {node: '>=14.13'}
hasBin: true
peerDependencies:
svelte: ^3.44.0
dependencies:
'@sveltejs/vite-plugin-svelte': 1.0.0-next.33_svelte@3.44.3+vite@2.7.10
sade: 1.8.0
svelte: 3.44.3
vite: 2.7.10
transitivePeerDependencies:
- diff-match-patch
- less
- sass
- stylus
- supports-color
dev: true
/@sveltejs/vite-plugin-svelte/1.0.0-next.33_svelte@3.44.3+vite@2.7.10:
resolution: {integrity: sha512-aj0h2+ZixgT+yoJFIs8dRRw/Cj9tgNu3+hY4CJikpa04mfhR61wXqJFfi2ZEFMUvFda5nCxKYIChFkc6wq5fJA==}
engines: {node: ^14.13.1 || >= 16}
peerDependencies:
diff-match-patch: ^1.0.5
svelte: ^3.44.0
vite: ^2.7.0
peerDependenciesMeta:
diff-match-patch:
optional: true
dependencies:
'@rollup/pluginutils': 4.1.2
debug: 4.3.3
kleur: 4.1.4
magic-string: 0.25.7
require-relative: 0.8.7
svelte: 3.44.3
svelte-hmr: 0.14.9_svelte@3.44.3
vite: 2.7.10
transitivePeerDependencies:
- supports-color
dev: true
/@types/node/17.0.6:
resolution: {integrity: sha512-+XBAjfZmmivILUzO0HwBJoYkAyyySSLg5KCGBDFLomJo0sV6szvVLAf4ANZZ0pfWzgEds5KmGLG9D5hfEqOhaA==}
dev: true
/@types/pug/2.0.6:
resolution: {integrity: sha512-SnHmG9wN1UVmagJOnyo/qkk0Z7gejYxOYYmaAwr5u2yFYfsupN3sg10kyzN8Hep/2zbHxCnsumxOoRIRMBwKCg==}
dev: true
/@types/sass/1.43.1:
resolution: {integrity: sha512-BPdoIt1lfJ6B7rw35ncdwBZrAssjcwzI5LByIrYs+tpXlj/CAkuVdRsgZDdP4lq5EjyWzwxZCqAoFyHKFwp32g==}
dependencies:
'@types/node': 17.0.6
dev: true
/balanced-match/1.0.2:
resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==}
dev: true
/brace-expansion/1.1.11:
resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==}
dependencies:
balanced-match: 1.0.2
concat-map: 0.0.1
dev: true
/buffer-crc32/0.2.13:
resolution: {integrity: sha1-DTM+PwDqxQqhRUq9MO+MKl2ackI=}
dev: true
/concat-map/0.0.1:
resolution: {integrity: sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=}
dev: true
/copy-to-clipboard/3.3.1:
resolution: {integrity: sha512-i13qo6kIHTTpCm8/Wup+0b1mVWETvu2kIMzKoK8FpkLkFxlt0znUAHcMzox+T8sPlqtZXq3CulEjQHsYiGFJUw==}
dependencies:
toggle-selection: 1.0.6
dev: false
/debug/4.3.3:
resolution: {integrity: sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==}
engines: {node: '>=6.0'}
peerDependencies:
supports-color: '*'
peerDependenciesMeta:
supports-color:
optional: true
dependencies:
ms: 2.1.2
dev: true
/detect-indent/6.1.0:
resolution: {integrity: sha512-reYkTUJAZb9gUuZ2RvVCNhVHdg62RHnJ7WJl8ftMi4diZ6NWlciOzQN88pUhSELEwflJht4oQDv0F0BMlwaYtA==}
engines: {node: '>=8'}
dev: true
/es6-promise/3.3.1:
resolution: {integrity: sha1-oIzd6EzNvzTQJ6FFG8kdS80ophM=}
dev: true
/esbuild-android-arm64/0.13.15:
resolution: {integrity: sha512-m602nft/XXeO8YQPUDVoHfjyRVPdPgjyyXOxZ44MK/agewFFkPa8tUo6lAzSWh5Ui5PB4KR9UIFTSBKh/RrCmg==}
cpu: [arm64]
os: [android]
requiresBuild: true
dev: true
optional: true
/esbuild-darwin-64/0.13.15:
resolution: {integrity: sha512-ihOQRGs2yyp7t5bArCwnvn2Atr6X4axqPpEdCFPVp7iUj4cVSdisgvEKdNR7yH3JDjW6aQDw40iQFoTqejqxvQ==}
cpu: [x64]
os: [darwin]
requiresBuild: true
dev: true
optional: true
/esbuild-darwin-arm64/0.13.15:
resolution: {integrity: sha512-i1FZssTVxUqNlJ6cBTj5YQj4imWy3m49RZRnHhLpefFIh0To05ow9DTrXROTE1urGTQCloFUXTX8QfGJy1P8dQ==}
cpu: [arm64]
os: [darwin]
requiresBuild: true
dev: true
optional: true
/esbuild-freebsd-64/0.13.15:
resolution: {integrity: sha512-G3dLBXUI6lC6Z09/x+WtXBXbOYQZ0E8TDBqvn7aMaOCzryJs8LyVXKY4CPnHFXZAbSwkCbqiPuSQ1+HhrNk7EA==}
cpu: [x64]
os: [freebsd]
requiresBuild: true
dev: true
optional: true
/esbuild-freebsd-arm64/0.13.15:
resolution: {integrity: sha512-KJx0fzEDf1uhNOZQStV4ujg30WlnwqUASaGSFPhznLM/bbheu9HhqZ6mJJZM32lkyfGJikw0jg7v3S0oAvtvQQ==}
cpu: [arm64]
os: [freebsd]
requiresBuild: true
dev: true
optional: true
/esbuild-linux-32/0.13.15:
resolution: {integrity: sha512-ZvTBPk0YWCLMCXiFmD5EUtB30zIPvC5Itxz0mdTu/xZBbbHJftQgLWY49wEPSn2T/TxahYCRDWun5smRa0Tu+g==}
cpu: [ia32]
os: [linux]
requiresBuild: true
dev: true
optional: true
/esbuild-linux-64/0.13.15:
resolution: {integrity: sha512-eCKzkNSLywNeQTRBxJRQ0jxRCl2YWdMB3+PkWFo2BBQYC5mISLIVIjThNtn6HUNqua1pnvgP5xX0nHbZbPj5oA==}
cpu: [x64]
os: [linux]
requiresBuild: true
dev: true
optional: true
/esbuild-linux-arm/0.13.15:
resolution: {integrity: sha512-wUHttDi/ol0tD8ZgUMDH8Ef7IbDX+/UsWJOXaAyTdkT7Yy9ZBqPg8bgB/Dn3CZ9SBpNieozrPRHm0BGww7W/jA==}
cpu: [arm]
os: [linux]
requiresBuild: true
dev: true
optional: true
/esbuild-linux-arm64/0.13.15:
resolution: {integrity: sha512-bYpuUlN6qYU9slzr/ltyLTR9YTBS7qUDymO8SV7kjeNext61OdmqFAzuVZom+OLW1HPHseBfJ/JfdSlx8oTUoA==}
cpu: [arm64]
os: [linux]
requiresBuild: true
dev: true
optional: true
/esbuild-linux-mips64le/0.13.15:
resolution: {integrity: sha512-KlVjIG828uFPyJkO/8gKwy9RbXhCEUeFsCGOJBepUlpa7G8/SeZgncUEz/tOOUJTcWMTmFMtdd3GElGyAtbSWg==}
cpu: [mips64el]
os: [linux]
requiresBuild: true
dev: true
optional: true
/esbuild-linux-ppc64le/0.13.15:
resolution: {integrity: sha512-h6gYF+OsaqEuBjeesTBtUPw0bmiDu7eAeuc2OEH9S6mV9/jPhPdhOWzdeshb0BskRZxPhxPOjqZ+/OqLcxQwEQ==}
cpu: [ppc64]
os: [linux]
requiresBuild: true
dev: true
optional: true
/esbuild-netbsd-64/0.13.15:
resolution: {integrity: sha512-3+yE9emwoevLMyvu+iR3rsa+Xwhie7ZEHMGDQ6dkqP/ndFzRHkobHUKTe+NCApSqG5ce2z4rFu+NX/UHnxlh3w==}
cpu: [x64]
os: [netbsd]
requiresBuild: true
dev: true
optional: true
/esbuild-openbsd-64/0.13.15:
resolution: {integrity: sha512-wTfvtwYJYAFL1fSs8yHIdf5GEE4NkbtbXtjLWjM3Cw8mmQKqsg8kTiqJ9NJQe5NX/5Qlo7Xd9r1yKMMkHllp5g==}
cpu: [x64]
os: [openbsd]
requiresBuild: true
dev: true
optional: true
/esbuild-sunos-64/0.13.15:
resolution: {integrity: sha512-lbivT9Bx3t1iWWrSnGyBP9ODriEvWDRiweAs69vI+miJoeKwHWOComSRukttbuzjZ8r1q0mQJ8Z7yUsDJ3hKdw==}
cpu: [x64]
os: [sunos]
requiresBuild: true
dev: true
optional: true
/esbuild-windows-32/0.13.15:
resolution: {integrity: sha512-fDMEf2g3SsJ599MBr50cY5ve5lP1wyVwTe6aLJsM01KtxyKkB4UT+fc5MXQFn3RLrAIAZOG+tHC+yXObpSn7Nw==}
cpu: [ia32]
os: [win32]
requiresBuild: true
dev: true
optional: true
/esbuild-windows-64/0.13.15:
resolution: {integrity: sha512-9aMsPRGDWCd3bGjUIKG/ZOJPKsiztlxl/Q3C1XDswO6eNX/Jtwu4M+jb6YDH9hRSUflQWX0XKAfWzgy5Wk54JQ==}
cpu: [x64]
os: [win32]
requiresBuild: true
dev: true
optional: true
/esbuild-windows-arm64/0.13.15:
resolution: {integrity: sha512-zzvyCVVpbwQQATaf3IG8mu1IwGEiDxKkYUdA4FpoCHi1KtPa13jeScYDjlW0Qh+ebWzpKfR2ZwvqAQkSWNcKjA==}
cpu: [arm64]
os: [win32]
requiresBuild: true
dev: true
optional: true
/esbuild/0.13.15:
resolution: {integrity: sha512-raCxt02HBKv8RJxE8vkTSCXGIyKHdEdGfUmiYb8wnabnaEmHzyW7DCHb5tEN0xU8ryqg5xw54mcwnYkC4x3AIw==}
hasBin: true
requiresBuild: true
optionalDependencies:
esbuild-android-arm64: 0.13.15
esbuild-darwin-64: 0.13.15
esbuild-darwin-arm64: 0.13.15
esbuild-freebsd-64: 0.13.15
esbuild-freebsd-arm64: 0.13.15
esbuild-linux-32: 0.13.15
esbuild-linux-64: 0.13.15
esbuild-linux-arm: 0.13.15
esbuild-linux-arm64: 0.13.15
esbuild-linux-mips64le: 0.13.15
esbuild-linux-ppc64le: 0.13.15
esbuild-netbsd-64: 0.13.15
esbuild-openbsd-64: 0.13.15
esbuild-sunos-64: 0.13.15
esbuild-windows-32: 0.13.15
esbuild-windows-64: 0.13.15
esbuild-windows-arm64: 0.13.15
dev: true
/estree-walker/2.0.2:
resolution: {integrity: sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==}
dev: true
/file-saver/2.0.5:
resolution: {integrity: sha512-P9bmyZ3h/PRG+Nzga+rbdI4OEpNDzAVyy74uVO9ATgzLK6VtAsYybF/+TOCvrc0MO793d6+42lLyZTw7/ArVzA==}
dev: false
/fs.realpath/1.0.0:
resolution: {integrity: sha1-FQStJSMVjKpA20onh8sBQRmU6k8=}
dev: true
/fsevents/2.3.2:
resolution: {integrity: sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==}
engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0}
os: [darwin]
requiresBuild: true
dev: true
optional: true
/function-bind/1.1.1:
resolution: {integrity: sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==}
dev: true
/glob/7.2.0:
resolution: {integrity: sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==}
dependencies:
fs.realpath: 1.0.0
inflight: 1.0.6
inherits: 2.0.4
minimatch: 3.0.4
once: 1.4.0
path-is-absolute: 1.0.1
dev: true
/globalyzer/0.1.0:
resolution: {integrity: sha512-40oNTM9UfG6aBmuKxk/giHn5nQ8RVz/SS4Ir6zgzOv9/qC3kKZ9v4etGTcJbEl/NyVQH7FGU7d+X1egr57Md2Q==}
dev: true
/globrex/0.1.2:
resolution: {integrity: sha512-uHJgbwAMwNFf5mLst7IWLNg14x1CkeqglJb/K3doi4dw6q2IvAAmM/Y81kevy83wP+Sst+nutFTYOGg3d1lsxg==}
dev: true
/graceful-fs/4.2.8:
resolution: {integrity: sha512-qkIilPUYcNhJpd33n0GBXTB1MMPp14TxEsEs0pTrsSVucApsYzW5V+Q8Qxhik6KU3evy+qkAAowTByymK0avdg==}
dev: true
/has/1.0.3:
resolution: {integrity: sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==}
engines: {node: '>= 0.4.0'}
dependencies:
function-bind: 1.1.1
dev: true
/inflight/1.0.6:
resolution: {integrity: sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=}
dependencies:
once: 1.4.0
wrappy: 1.0.2
dev: true
/inherits/2.0.4:
resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==}
dev: true
/is-core-module/2.8.0:
resolution: {integrity: sha512-vd15qHsaqrRL7dtH6QNuy0ndJmRDrS9HAM1CAiSifNUFv4x1a0CCVsj18hJ1mShxIG6T2i1sO78MkP56r0nYRw==}
dependencies:
has: 1.0.3
dev: true
/kleur/4.1.4:
resolution: {integrity: sha512-8QADVssbrFjivHWQU7KkMgptGTl6WAcSdlbBPY4uNF+mWr6DGcKrvY2w4FQJoXch7+fKMjj0dRrL75vk3k23OA==}
engines: {node: '>=6'}
dev: true
/magic-string/0.25.7:
resolution: {integrity: sha512-4CrMT5DOHTDk4HYDlzmwu4FVCcIYI8gauveasrdCu2IKIFOJ3f0v/8MDGJCDL9oD2ppz/Av1b0Nj345H9M+XIA==}
dependencies:
sourcemap-codec: 1.4.8
dev: true
/min-indent/1.0.1:
resolution: {integrity: sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==}
engines: {node: '>=4'}
dev: true
/minimatch/3.0.4:
resolution: {integrity: sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==}
dependencies:
brace-expansion: 1.1.11
dev: true
/minimist/1.2.5:
resolution: {integrity: sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==}
dev: true
/mkdirp/0.5.5:
resolution: {integrity: sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==}
hasBin: true
dependencies:
minimist: 1.2.5
dev: true
/mri/1.2.0:
resolution: {integrity: sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==}
engines: {node: '>=4'}
dev: true
/ms/2.1.2:
resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==}
dev: true
/nanoid/3.1.30:
resolution: {integrity: sha512-zJpuPDwOv8D2zq2WRoMe1HsfZthVewpel9CAvTfc/2mBD1uUT/agc5f7GHGWXlYkFvi1mVxe4IjvP2HNrop7nQ==}
engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1}
hasBin: true
dev: true
/once/1.4.0:
resolution: {integrity: sha1-WDsap3WWHUsROsF9nFC6753Xa9E=}
dependencies:
wrappy: 1.0.2
dev: true
/path-is-absolute/1.0.1:
resolution: {integrity: sha1-F0uSaHNVNP+8es5r9TpanhtcX18=}
engines: {node: '>=0.10.0'}
dev: true
/path-parse/1.0.7:
resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==}
dev: true
/picocolors/1.0.0:
resolution: {integrity: sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==}
dev: true
/picomatch/2.3.1:
resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==}
engines: {node: '>=8.6'}
dev: true
/postcss/8.4.5:
resolution: {integrity: sha512-jBDboWM8qpaqwkMwItqTQTiFikhs/67OYVvblFFTM7MrZjt6yMKd6r2kgXizEbTTljacm4NldIlZnhbjr84QYg==}
engines: {node: ^10 || ^12 || >=14}
dependencies:
nanoid: 3.1.30
picocolors: 1.0.0
source-map-js: 1.0.1
dev: true
/pretty-bytes/5.6.0:
resolution: {integrity: sha512-FFw039TmrBqFK8ma/7OL3sDz/VytdtJr044/QUJtH0wK9lb9jLq9tJyIxUwtQJHwar2BqtiA4iCWSwo9JLkzFg==}
engines: {node: '>=6'}
dev: false
/require-relative/0.8.7:
resolution: {integrity: sha1-eZlTn8ngR6N5KPoZb44VY9q9Nt4=}
dev: true
/resolve/1.20.0:
resolution: {integrity: sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A==}
dependencies:
is-core-module: 2.8.0
path-parse: 1.0.7
dev: true
/rimraf/2.7.1:
resolution: {integrity: sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==}
hasBin: true
dependencies:
glob: 7.2.0
dev: true
/rollup/2.62.0:
resolution: {integrity: sha512-cJEQq2gwB0GWMD3rYImefQTSjrPYaC6s4J9pYqnstVLJ1CHa/aZNVkD4Epuvg4iLeMA4KRiq7UM7awKK6j7jcw==}
engines: {node: '>=10.0.0'}
hasBin: true
optionalDependencies:
fsevents: 2.3.2
dev: true
/sade/1.8.0:
resolution: {integrity: sha512-NRfCA8AVYuAA7Hu8bs18od6J4BdcXXwOv6OJuNgwbw8LcLK8JKwaM3WckLZ+MGyPJUS/ivVgK3twltrOIJJnug==}
engines: {node: '>=6'}
dependencies:
mri: 1.2.0
dev: true
/sander/0.5.1:
resolution: {integrity: sha1-dB4kXiMfB8r7b98PEzrfohalAq0=}
dependencies:
es6-promise: 3.3.1
graceful-fs: 4.2.8
mkdirp: 0.5.5
rimraf: 2.7.1
dev: true
/sorcery/0.10.0:
resolution: {integrity: sha1-iukK19fLBfxZ8asMY3hF1cFaUrc=}
hasBin: true
dependencies:
buffer-crc32: 0.2.13
minimist: 1.2.5
sander: 0.5.1
sourcemap-codec: 1.4.8
dev: true
/source-map-js/1.0.1:
resolution: {integrity: sha512-4+TN2b3tqOCd/kaGRJ/sTYA0tR0mdXx26ipdolxcwtJVqEnqNYvlCAt1q3ypy4QMlYus+Zh34RNtYLoq2oQ4IA==}
engines: {node: '>=0.10.0'}
dev: true
/sourcemap-codec/1.4.8:
resolution: {integrity: sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==}
dev: true
/strip-indent/3.0.0:
resolution: {integrity: sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==}
engines: {node: '>=8'}
dependencies:
min-indent: 1.0.1
dev: true
/svelte-hmr/0.14.9_svelte@3.44.3:
resolution: {integrity: sha512-bKE9+4qb4sAnA+TKHiYurUl970rjA0XmlP9TEP7K/ncyWz3m81kA4HOgmlZK/7irGK7gzZlaPDI3cmf8fp/+tg==}
peerDependencies:
svelte: '>=3.19.0'
dependencies:
svelte: 3.44.3
dev: true
/svelte-preprocess/4.10.1_svelte@3.44.3+typescript@4.5.4:
resolution: {integrity: sha512-NSNloaylf+o9UeyUR2KvpdxrAyMdHl3U7rMnoP06/sG0iwJvlUM4TpMno13RaNqovh4AAoGsx1jeYcIyuGUXMw==}
engines: {node: '>= 9.11.2'}
requiresBuild: true
peerDependencies:
'@babel/core': ^7.10.2
coffeescript: ^2.5.1
less: ^3.11.3
node-sass: '*'
postcss: ^7 || ^8
postcss-load-config: ^2.1.0 || ^3.0.0
pug: ^3.0.0
sass: ^1.26.8
stylus: ^0.54.7
sugarss: ^2.0.0
svelte: ^3.23.0
typescript: ^4.5.2
peerDependenciesMeta:
'@babel/core':
optional: true
coffeescript:
optional: true
less:
optional: true
node-sass:
optional: true
postcss:
optional: true
postcss-load-config:
optional: true
pug:
optional: true
sass:
optional: true
stylus:
optional: true
sugarss:
optional: true
typescript:
optional: true
dependencies:
'@types/pug': 2.0.6
'@types/sass': 1.43.1
detect-indent: 6.1.0
magic-string: 0.25.7
sorcery: 0.10.0
strip-indent: 3.0.0
svelte: 3.44.3
typescript: 4.5.4
dev: true
/svelte/3.44.3:
resolution: {integrity: sha512-aGgrNCip5PQFNfq9e9tmm7EYxWLVHoFsEsmKrtOeRD8dmoGDdyTQ+21xd7qgFd8MNdKGSYvg7F9dr+Tc0yDymg==}
engines: {node: '>= 8'}
dev: true
/tiny-glob/0.2.9:
resolution: {integrity: sha512-g/55ssRPUjShh+xkfx9UPDXqhckHEsHr4Vd9zX55oSdGZc/MD0m3sferOkwWtp98bv+kcVfEHtRJgBVJzelrzg==}
dependencies:
globalyzer: 0.1.0
globrex: 0.1.2
dev: true
/toggle-selection/1.0.6:
resolution: {integrity: sha1-bkWxJj8gF/oKzH2J14sVuL932jI=}
dev: false
/tslib/2.3.1:
resolution: {integrity: sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==}
dev: true
/typescript/4.5.4:
resolution: {integrity: sha512-VgYs2A2QIRuGphtzFV7aQJduJ2gyfTljngLzjpfW9FoYZF6xuw1W0vW9ghCKLfcWrCFxK81CSGRAvS1pn4fIUg==}
engines: {node: '>=4.2.0'}
hasBin: true
dev: true
/vite/2.7.10:
resolution: {integrity: sha512-KEY96ntXUid1/xJihJbgmLZx7QSC2D4Tui0FdS0Old5OokYzFclcofhtxtjDdGOk/fFpPbHv9yw88+rB93Tb8w==}
engines: {node: '>=12.2.0'}
hasBin: true
peerDependencies:
less: '*'
sass: '*'
stylus: '*'
peerDependenciesMeta:
less:
optional: true
sass:
optional: true
stylus:
optional: true
dependencies:
esbuild: 0.13.15
postcss: 8.4.5
resolve: 1.20.0
rollup: 2.62.0
optionalDependencies:
fsevents: 2.3.2
dev: true
/wrappy/1.0.2:
resolution: {integrity: sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=}
dev: true

124
frontend/src/app.css Normal file
View File

@@ -0,0 +1,124 @@
@import '@fontsource/fira-mono';
* {
box-sizing: border-box;
}
:root {
font-family: 'Fira Mono', monospace;
--ui-bg-0: #111;
--ui-bg-0-85: #111111d9;
--ui-bg-1: #333;
--ui-bg-2: #444;
--ui-text-0: #fefefe;
--ui-text-1: #eee;
--ui-clr-primary: hsl(186, 65%, 55%);
--ui-clr-error: hsl(357, 77%, 51%);
--ui-anim: all 150ms ease;
}
@media (prefers-color-scheme: light) {
:root {
--ui-bg-0: #fefefe;
--ui-bg-0-85: #fefefed9;
--ui-bg-1: #eee;
--ui-bg-2: #e2e2e2;
--ui-text-0: #111;
--ui-text-1: #333;
}
}
:root[theme='dark'] {
--ui-bg-0: #111 !important;
--ui-bg-0-85: #111111d9 !important;
--ui-bg-1: #333 !important;
--ui-bg-2: #444 !important;
--ui-text-0: #fefefe !important;
--ui-text-1: #eee !important;
}
:root[theme='light'] {
--ui-bg-0: #fefefe !important;
--ui-bg-0-85: #fefefed9 !important;
--ui-bg-1: #eee !important;
--ui-bg-2: #e2e2e2 !important;
--ui-text-0: #111 !important;
--ui-text-1: #333 !important;
}
.error-text {
color: var(--ui-clr-error);
}
body {
min-height: 100vh;
margin: 0;
background-color: var(--ui-bg-0);
color: var(--ui-text-0);
}
a {
color: inherit;
text-decoration: inherit;
box-sizing: content-box;
border-bottom: 2px solid var(--ui-bg-2);
cursor: pointer;
}
a:active {
border-color: var(--ui-clr-primary);
}
a:hover {
border-color: var(--ui-text-0);
}
input,
textarea,
button {
appearance: none;
-webkit-appearance: none;
border-radius: 0;
transition: var(--ui-anim);
font-family: inherit;
font-size: inherit;
background: inherit;
color: inherit;
}
*:disabled,
*[disabled='true'] {
opacity: 0.5;
}
fieldset {
margin: 0;
padding: 0;
border: none;
}
.box {
width: 100%;
min-height: min(calc(100vh - 30rem), 20rem);
margin: 0;
border: 2px solid var(--ui-bg-1);
resize: vertical;
outline: none;
padding: 0.5rem;
}
@media screen and (max-width: 30rem) {
.box {
min-height: calc(100vh - 25rem);
}
}
.box:hover,
.box:focus {
border-color: var(--ui-clr-primary);
}
.tr {
text-align: right;
}

74
frontend/src/lib/api.ts Normal file
View File

@@ -0,0 +1,74 @@
export type NoteMeta = { type: 'text' | 'file' }
export type Note = {
contents: string
meta: NoteMeta
views?: number
expiration?: number
}
export type NoteInfo = {}
export type NotePublic = Pick<Note, 'contents' | 'meta'>
export type NoteCreate = Omit<Note, 'meta'> & { meta: string }
export type FileDTO = Pick<File, 'name' | 'size' | 'type'> & {
contents: string
}
type CallOptions = {
url: string
method: string
body?: any
}
export class PayloadToLargeError extends Error {}
export async function call(options: CallOptions) {
const response = await fetch('/api/' + options.url, {
method: options.method,
body: options.body === undefined ? undefined : JSON.stringify(options.body),
mode: 'cors',
headers: {
'Content-Type': 'application/json',
},
})
if (!response.ok) {
if (response.status === 413) throw new PayloadToLargeError()
else throw new Error('API call failed')
}
return response.json()
}
export async function create(note: Note) {
const { meta, ...rest } = note
const body: NoteCreate = {
...rest,
meta: JSON.stringify(meta),
}
const data = await call({
url: 'notes/',
method: 'post',
body,
})
return data as { id: string }
}
export async function get(id: string): Promise<NotePublic> {
const data = await call({
url: `notes/${id}`,
method: 'delete',
})
const { contents, meta } = data
return {
contents,
meta: JSON.parse(meta) as NoteMeta,
}
}
export async function info(id: string): Promise<NoteInfo> {
const data = await call({
url: `notes/${id}`,
method: 'get',
})
return data
}

View File

@@ -36,7 +36,7 @@ export function getKeyFromString(password: string) {
}
export async function getDerivedForKey(key: CryptoKey, salt: ArrayBuffer) {
const iterations = 1_000
const iterations = 100_000
return window.crypto.subtle.deriveKey(
{
name: 'PBKDF2',

13
frontend/src/lib/files.ts Normal file
View File

@@ -0,0 +1,13 @@
export class Files {
static toString(f: File | Blob): Promise<string> {
const reader = new window.FileReader()
reader.readAsDataURL(f)
return new Promise((resolve) => {
reader.onloadend = () => resolve(reader.result as string)
})
}
static fromString(s: string): Promise<Blob> {
return fetch(s).then((r) => r.blob())
}
}

View File

@@ -0,0 +1,17 @@
import { call } from '$lib/api'
import { writable } from 'svelte/store'
export type Status = {
version: string
max_size: number
}
export const status = writable<null | Status>(null)
export async function init() {
const data = await call({
url: 'status',
method: 'get',
})
status.set(data)
}

View File

@@ -0,0 +1,19 @@
<script lang="ts">
export let title: string
</script>
<p>
<b>{title}</b>
<slot />
</p>
<style>
b {
display: block;
margin-bottom: 0.25rem;
}
p > :global(span) {
padding-left: 1.25em;
}
</style>

View File

@@ -0,0 +1,72 @@
<script lang="ts">
import type { FileDTO } from '$lib/api'
import { Files } from '$lib/files'
import { createEventDispatcher } from 'svelte'
import MaxSize from './MaxSize.svelte'
export let label: string = ''
let files: File[] = []
const dispatch = createEventDispatcher<{ file: string }>()
async function onInput(e: Event) {
const input = e.target as HTMLInputElement
if (input.files.length) {
files = Array.from(input.files)
const data: FileDTO[] = await Promise.all(
files.map(async (file) => ({
name: file.name,
type: file.type,
size: file.size,
contents: await Files.toString(file),
}))
)
console.debug(
'files',
data.map((d) => d.contents.length)
)
dispatch('file', JSON.stringify(data))
} else {
dispatch('file', '')
}
}
</script>
<label>
<small>
{label}
</small>
<input type="file" on:change={onInput} multiple />
<div class="box">
{#if files.length}
<div>
<b>Selected Files</b>
{#each files as file}
<div class="file">
{file.name}
</div>
{/each}
</div>
{:else}
<div>
<b>No Files Selected</b>
<br />
<small>max: <MaxSize /></small>
</div>
{/if}
</div>
</label>
<style>
input {
display: none;
}
.box {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
cursor: pointer;
}
</style>

View File

@@ -1,8 +1,9 @@
<script lang="ts">
import { onMount } from 'svelte'
export let icon: string
export let icon: string = ''
export let href: string = ''
$: src = `/icons/${icon}.svg`
$: src = href || `/icons/${icon}.svg`
let html = null

View File

@@ -0,0 +1,12 @@
<script lang="ts">
import { status } from '$lib/stores/status'
import prettyBytes from 'pretty-bytes'
</script>
<span>
{#if $status !== null}
{prettyBytes($status.max_size, { binary: true })}
{:else}
loading...
{/if}
</span>

View File

@@ -0,0 +1,69 @@
<script lang="ts">
import type { FileDTO, NotePublic } from '$lib/api'
import { Files } from '$lib/files'
import copy from 'copy-to-clipboard'
import { saveAs } from 'file-saver'
import prettyBytes from 'pretty-bytes'
import Button from './Button.svelte'
export let note: NotePublic
let files: FileDTO[] = []
$: if (note.meta.type === 'file') {
files = JSON.parse(note.contents) as FileDTO[]
}
$: download = () => {
for (const file of files) {
downloadFile(file)
}
}
async function downloadFile(file: FileDTO) {
const f = new File([await Files.fromString(file.contents)], file.name, {
type: file.type,
})
saveAs(f)
}
</script>
<p class="error-text">you will <b>not</b> get the chance to see the note again.</p>
{#if note.meta.type === 'text'}
<div class="note" data-testid="note-result">
{note.contents}
</div>
<Button on:click={() => copy(note.contents)}>copy to clipboard</Button>
{:else}
{#each files as file}
<div class="note file" data-testid="note-result">
<b on:click={() => downloadFile(file)}> {file.name}</b>
<small> {file.type} {prettyBytes(file.size)}</small>
</div>
{/each}
<Button on:click={download}>download all</Button>
{/if}
<style>
.note {
width: 100%;
margin: 0;
padding: 0;
border: 2px solid var(--ui-bg-1);
outline: none;
padding: 0.5rem;
white-space: pre;
overflow: auto;
margin-bottom: 0.5rem;
}
.note b {
cursor: pointer;
}
.note.file {
display: flex;
justify-content: space-between;
align-items: center;
}
</style>

View File

@@ -4,7 +4,7 @@
export let color = true
</script>
<div>
<div {...$$restProps}>
<label class="switch">
<small>{label}</small>
<input type="checkbox" bind:checked={value} />

View File

@@ -0,0 +1,11 @@
<script lang="ts">
export let label: string = ''
export let value: string
</script>
<label>
<small>
{label}
</small>
<textarea class="box" {...$$restProps} bind:value />
</label>

View File

@@ -0,0 +1,62 @@
<script lang="ts" context="module">
import { writable } from 'svelte/store'
enum Theme {
Dark = 'dark',
Light = 'light',
Auto = 'auto',
}
const NextTheme = {
[Theme.Auto]: Theme.Light,
[Theme.Light]: Theme.Dark,
[Theme.Dark]: Theme.Auto,
}
function init(): Theme {
if (typeof window !== 'undefined') {
const saved = window.localStorage.getItem('theme') as Theme
if (Object.values(Theme).includes(saved)) return saved
}
return Theme.Auto
}
export const theme = writable<Theme>(init())
theme.subscribe((theme) => {
if (typeof window !== 'undefined') {
window.localStorage.setItem('theme', theme)
const html = window.document.getElementsByTagName('html')[0]
html.setAttribute('theme', theme)
}
})
</script>
<script lang="ts">
import Icon from '$lib/ui/Icon.svelte'
function change() {
theme.update((current) => NextTheme[current])
}
</script>
<div on:click={change}>
<Icon class="icon" icon="contrast-sharp" />
{$theme}
</div>
<style>
div :global(.icon) {
height: 1rem;
width: 1rem;
margin-right: 0.5rem;
}
div {
display: flex;
flex-direction: row;
justify-content: flex-end;
align-items: center;
cursor: pointer;
}
</style>

View File

@@ -0,0 +1,195 @@
<script lang="ts">
import { create, Note, PayloadToLargeError } from '$lib/api'
import { encrypt, getKeyFromString, getRandomBytes, Hex } from '$lib/crypto'
import Button from '$lib/ui/Button.svelte'
import FileUpload from '$lib/ui/FileUpload.svelte'
import MaxSize from '$lib/ui/MaxSize.svelte'
import Switch from '$lib/ui/Switch.svelte'
import TextArea from '$lib/ui/TextArea.svelte'
import TextInput from '$lib/ui/TextInput.svelte'
import { blur } from 'svelte/transition'
let note: Note = {
contents: '',
meta: { type: 'text' },
views: 1,
expiration: 60,
}
let result: { password: string; id: string } | null = null
let advanced = false
let file = false
let type = false
let message = ''
let loading = false
let error: string | null = null
$: if (!advanced) {
note.views = 1
type = false
}
$: {
let fraction: string
fraction = type ? `${note.expiration} minutes` : `${note.views} views`
message = 'the note will expire and be destroyed after ' + fraction
}
$: note.meta.type = file ? 'file' : 'text'
$: if (!file) {
note.contents = ''
}
async function submit() {
try {
error = null
loading = true
const password = Hex.encode(getRandomBytes(32))
const key = await getKeyFromString(password)
const data: Note = {
contents: await encrypt(note.contents, key),
meta: note.meta,
}
// @ts-ignore
if (type) data.expiration = parseInt(note.expiration)
// @ts-ignore
else data.views = parseInt(note.views)
const response = await create(data)
result = {
password: password,
id: response.id,
}
} catch (e) {
if (e instanceof PayloadToLargeError) {
error = 'could not create not. note is to big'
} else {
error = 'could not create note. please try again.'
}
} finally {
loading = false
}
}
function reset() {
window.location.reload()
}
</script>
{#if result}
<TextInput
type="text"
readonly
label="share link"
value="{window.location.origin}/note/{result.id}#{result.password}"
copy
data-testid="note-share-link"
/>
<br />
<p>
<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.)
</p>
<br />
<Button on:click={reset}>new note</Button>
{:else}
<p>
Easily send <i>fully encrypted</i>, secure notes or files with one click. Just create a note and
share the link.
</p>
<form on:submit|preventDefault={submit}>
<fieldset disabled={loading}>
{#if file}
<FileUpload label="file" on:file={(f) => (note.contents = f.detail)} />
{:else}
<TextArea
label="note"
bind:value={note.contents}
placeholder="..."
data-testid="input-note"
/>
{/if}
<div class="bottom">
<Switch class="file" label="file" bind:value={file} />
<Switch label="advanced" bind:value={advanced} />
<div class="grow" />
<div class="tr">
<small>max: <MaxSize /> </small>
<br />
<Button type="submit" data-testid="button-create">create</Button>
</div>
</div>
{#if error}
<div class="error-text">{error}</div>
{/if}
<p>
<br />
{#if loading}
loading...
{:else}
{message}
{/if}
</p>
{#if advanced}
<div transition:blur={{ duration: 250 }}>
<br />
<div class="fields">
<TextInput
type="number"
label="views"
bind:value={note.views}
disabled={type}
max={100}
/>
<div class="middle-switch">
<Switch label="mode" bind:value={type} color={false} />
</div>
<TextInput
type="number"
label="minutes"
bind:value={note.expiration}
disabled={!type}
max={360}
/>
</div>
</div>
{/if}
</fieldset>
</form>
{/if}
<style>
.bottom {
display: flex;
align-items: flex-end;
margin-top: 0.5rem;
}
.bottom :global(.file) {
margin-right: 0.5rem;
}
.grow {
flex: 1;
}
.middle-switch {
margin: 0 1rem;
}
.error-text {
margin-top: 0.5rem;
}
.fields {
display: flex;
}
</style>

View File

@@ -0,0 +1,37 @@
<script lang="ts">
import Icon from '$lib/ui/Icon.svelte'
import ThemeToggle from '$lib/ui/ThemeToggle.svelte'
</script>
<footer>
<ThemeToggle />
<nav>
<a href="/">/home</a>
<a href="/about">/about</a>
<a href="https://github.com/cupcakearmy/cryptgeon" target="_blank" rel="noopener">/code</a>
</nav>
</footer>
<style>
footer {
display: flex;
justify-content: space-between;
padding: 1rem;
position: fixed;
bottom: 0;
right: 0;
width: 100%;
background-color: var(--ui-bg-0-85);
}
a {
margin: 0 0.5rem;
}
nav {
display: flex;
flex-direction: row;
justify-content: flex-end;
align-items: center;
}
</style>

View File

@@ -0,0 +1,107 @@
<header>
<a href="/">
<svg
width="100%"
height="100%"
viewBox="0 0 450 200"
version="1.1"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
xml:space="preserve"
style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;"
><g id="Logo"
><clipPath id="_clip1"><rect x="6.336" y="3.225" width="193.55" height="193.55" /></clipPath
><g clip-path="url(#_clip1)"
><g
><g
><path
d="M173.425,43.296c-2.087,-0 -3.78,1.693 -3.78,3.78c-0,2.087 1.693,3.78 3.78,3.78c2.087,0 3.78,-1.693 3.78,-3.78c0,-2.087 -1.693,-3.78 -3.78,-3.78Z"
style="fill-rule:nonzero;"
/></g
></g
><g
><g
><path
d="M103.112,134.023c-2.087,-0 -3.781,1.693 -3.781,3.78c0,2.087 1.694,3.78 3.781,3.78c2.086,0 3.78,-1.693 3.78,-3.78c-0,-2.087 -1.694,-3.78 -3.78,-3.78Z"
style="fill-rule:nonzero;"
/></g
></g
><g
><g
><path
d="M156.036,96.22c-2.088,-0 -3.781,1.692 -3.781,3.78c0,18.76 -15.262,34.023 -34.022,34.023c-2.088,-0 -3.781,1.692 -3.781,3.78c0,2.088 1.693,3.78 3.781,3.78c22.929,0 41.583,-18.654 41.583,-41.583c-0,-2.088 -1.693,-3.78 -3.78,-3.78Z"
style="fill-rule:nonzero;"
/></g
></g
><g
><g
><path
d="M199.488,60.507l-9.515,-19.026c-4.102,-8.207 -12.35,-13.306 -21.527,-13.306c-7.479,-0 -14.626,3.547 -19.154,9.498l-10.679,12.016c-2.846,-4.047 -7.021,-7.049 -11.83,-8.421l-19.102,-5.459c-14.623,-4.178 -28.92,-15.441 -39.227,-30.901c-0.924,-1.386 -2.646,-2.003 -4.241,-1.521c-1.594,0.483 -2.684,1.953 -2.684,3.618l-0,20.372c-0,9.468 1.417,18.804 4.219,27.813c-2.936,0.73 -5.896,1.34 -8.843,1.816c-5.772,0.936 -11.653,1.411 -17.48,1.411l-29.308,-0c-1.374,-0 -2.64,0.746 -3.307,1.948c-0.666,1.202 -0.627,2.671 0.101,3.836l22.637,36.219c9.672,15.473 26.329,25.183 44.578,25.983l-36.36,41.158c-5.602,5.728 -3.655,15.315 3.746,18.396l20.017,9.887c0.089,0.044 0.179,0.084 0.271,0.121c5.79,2.313 12.389,-0.496 14.726,-6.279l13.969,-32.982l27.738,0c31.966,0 58.972,-25.967 58.972,-56.704l0,-22.682c0,-6.253 5.088,-11.341 11.341,-11.341l7.56,0c1.311,0 2.528,-0.678 3.216,-1.793c0.689,-1.114 0.752,-2.506 0.166,-3.677Zm-130.399,-42.236c10.418,12.203 23.307,21.034 36.515,24.808l19.103,5.459c3.726,1.063 6.866,3.624 8.666,7.048l-10.048,11.307l-17.652,-10.591c-7.646,-4.588 -16.746,-6.412 -25.776,-4.951c-2.838,0.46 -4.649,1.038 -6.877,1.759c-2.609,-8.332 -3.931,-16.971 -3.931,-25.733l0,-9.106Zm119.457,40.146c-10.422,-0 -18.901,8.479 -18.901,18.901l-0,22.682c-0,26.639 -23.544,49.144 -51.412,49.144l-30.243,-0c-10.77,-0 -20.451,5.983 -25.265,15.615l-0.797,1.596c-0.934,1.867 -0.177,4.137 1.691,5.071c1.867,0.934 4.138,0.176 5.071,-1.691c0.44,-0.586 3.306,-9.102 13.21,-12.125l-12.349,29.159c-0.01,0.024 -0.02,0.047 -0.029,0.071c-0.75,1.877 -2.864,2.851 -4.8,2.148c-21.279,-10.506 -19.997,-9.888 -20.252,-9.99c-2.526,-1.01 -3.191,-4.259 -1.267,-6.182c0.13,-0.131 8.026,-9.078 41.009,-46.411c13.867,-0.617 26.841,-6.319 36.694,-16.172c1.476,-1.476 1.476,-3.87 0,-5.346c-1.476,-1.477 -3.87,-1.476 -5.346,-0c-16.827,16.828 -36.803,13.634 -39.028,14.014c-16.603,0 -31.771,-8.407 -40.573,-22.488l-2.417,-3.868l2.729,1.065c17.307,6.753 38.919,4.347 53.816,-5.586c1.737,-1.158 2.207,-3.505 1.049,-5.242c-1.159,-1.737 -3.505,-2.207 -5.243,-1.048c-13.085,8.724 -31.922,10.666 -46.875,4.832l-12.185,-4.753l-9.896,-15.836l22.488,0c6.231,0 12.519,-0.507 18.689,-1.507c12.711,-2.055 18.051,-4.855 22.992,-5.655c7.182,-1.163 14.516,0.274 20.678,3.97l29.625,17.775c1.789,1.074 4.112,0.494 5.186,-1.296c1.075,-1.79 0.495,-4.113 -1.295,-5.187l-5.378,-3.226c26.56,-29.893 25.14,-28.272 25.32,-28.511c3.101,-4.136 8.038,-6.605 13.204,-6.605c6.294,0 11.951,3.497 14.764,9.127l6.779,13.555l-1.443,-0Z"
style="fill-rule:nonzero;"
/></g
></g
></g
><g
><path
d="M222.664,114.692c0.85,-0 1.274,0.586 1.274,1.759c0,1.174 -0.242,2.347 -0.728,3.52c-0.485,1.173 -1.183,2.326 -2.093,3.459c-0.91,1.132 -2.185,2.063 -3.823,2.791c-1.639,0.728 -3.489,1.092 -5.552,1.092c-4.531,0 -8.081,-1.143 -10.65,-3.428c-2.569,-2.286 -3.853,-5.644 -3.853,-10.073c-0,-4.43 1.133,-7.889 3.398,-10.377c2.265,-2.488 5.158,-3.732 8.677,-3.732c2.549,0 4.41,0.678 5.583,2.033c1.173,1.355 1.76,2.964 1.76,4.824c-0,1.012 -0.304,1.821 -0.91,2.428c-0.607,0.606 -1.194,0.91 -1.76,0.91c-1.052,-0 -1.74,-0.243 -2.063,-0.728c0.242,-0.607 0.364,-1.477 0.364,-2.61c-0,-1.132 -0.385,-2.164 -1.153,-3.094c-0.769,-0.931 -1.699,-1.396 -2.792,-1.396c-1.901,0 -3.266,0.93 -4.095,2.791c-0.83,1.861 -1.244,4.784 -1.244,8.769c-0,3.984 0.778,6.867 2.336,8.647c1.557,1.78 3.732,2.67 6.523,2.67c2.791,-0 5.138,-0.86 7.039,-2.579c1.901,-1.72 2.852,-4.157 2.852,-7.312c0.04,-0.243 0.344,-0.364 0.91,-0.364Z"
style="fill-rule:nonzero;"
/><path
d="M227.337,116.815l-0,9.649c-0.405,0.566 -1.113,0.849 -2.124,0.849c-1.012,0 -1.821,-0.313 -2.428,-0.94c-0.606,-0.627 -0.91,-1.548 -0.91,-2.761l0,-23.059c0.405,-0.566 1.113,-0.85 2.124,-0.85c1.011,0 1.821,0.314 2.427,0.941c0.607,0.627 0.911,1.547 0.911,2.761l-0,4.612c2.022,-5.017 4.814,-7.525 8.373,-7.525c2.549,0 4.41,0.678 5.583,2.033c1.173,1.355 1.76,2.963 1.76,4.824c-0,1.012 -0.304,1.821 -0.91,2.427c-0.607,0.607 -1.194,0.911 -1.76,0.911c-1.052,-0 -1.74,-0.243 -2.063,-0.728c0.242,-0.607 0.364,-1.477 0.364,-2.61c-0,-1.132 -0.384,-2.164 -1.153,-3.094c-0.769,-0.931 -1.699,-1.396 -2.791,-1.396c-1.902,-0 -3.611,1.729 -5.128,5.188c-1.517,3.459 -2.275,6.382 -2.275,8.768Z"
style="fill-rule:nonzero;"
/><path
d="M245.419,103.405c0,-1.214 0.304,-2.134 0.911,-2.761c0.606,-0.627 1.375,-0.941 2.306,-0.941c0.93,0 1.678,0.284 2.245,0.85l-0,17.415c-0,4.814 1.213,7.221 3.641,7.221c2.184,0 3.974,-1.153 5.37,-3.458c1.395,-2.306 2.093,-6.19 2.093,-11.651l0,-6.675c0,-1.214 0.304,-2.134 0.91,-2.761c0.607,-0.627 1.376,-0.941 2.306,-0.941c0.931,0 1.679,0.284 2.246,0.85l-0,30.826c0.485,-0.041 1.254,-0.061 2.305,-0.061c1.052,0 1.578,0.445 1.578,1.335l-0.364,0.91c-1.537,0 -2.71,0.021 -3.519,0.061l-0,3.034c-0,4.167 -0.941,7.454 -2.822,9.861c-1.881,2.407 -4.399,3.61 -7.555,3.61c-1.861,0 -3.509,-0.556 -4.945,-1.669c-1.436,-1.112 -2.155,-2.862 -2.155,-5.248c0,-3.075 1.093,-5.522 3.277,-7.343c2.185,-1.82 5.097,-3.095 8.738,-3.823l0,-9.466c-1.699,3.156 -4.429,4.733 -8.192,4.733c-2.589,0 -4.632,-0.829 -6.128,-2.488c-1.497,-1.658 -2.246,-4.045 -2.246,-7.16l0,-14.26Zm7.646,39.989c0,1.416 0.385,2.498 1.153,3.246c0.769,0.748 1.699,1.123 2.791,1.123c1.093,-0 1.983,-0.324 2.67,-0.971c1.538,-1.376 2.306,-5.522 2.306,-12.44c-5.946,1.335 -8.92,4.349 -8.92,9.042Z"
style="fill-rule:nonzero;"
/><path
d="M298.576,104.861c1.335,2.306 2.002,5.411 2.002,9.315c0,3.904 -0.981,7.059 -2.943,9.466c-1.962,2.407 -4.52,3.611 -7.676,3.611c-1.861,-0 -3.509,-0.648 -4.945,-1.942c-1.436,-1.295 -2.155,-3.358 -2.155,-6.19c0,-6.634 3.297,-11.59 9.891,-14.866c-1.051,-1.457 -2.518,-2.185 -4.399,-2.185c-1.881,0 -3.671,0.93 -5.37,2.791c-1.699,1.861 -2.549,4.653 -2.549,8.374l0,36.105c-0.404,0.567 -1.112,0.85 -2.124,0.85c-1.011,-0 -1.82,-0.314 -2.427,-0.941c-0.607,-0.627 -0.91,-1.547 -0.91,-2.761l-0,-45.935c0.405,-0.566 1.112,-0.85 2.124,-0.85c1.011,0 1.82,0.314 2.427,0.941c0.607,0.627 0.91,1.547 0.91,2.761l0,1.335c2.104,-3.358 4.885,-5.037 8.344,-5.037c3.459,0 6.159,0.971 8.101,2.913c4.247,-1.375 9.001,-2.063 14.26,-2.063c1.092,-0 1.638,0.445 1.638,1.335l-0.364,0.91c-4.895,0 -9.507,0.688 -13.835,2.063Zm-8.738,20.025c3.317,-0 4.976,-3.297 4.976,-9.891c-0,-3.479 -0.284,-6.21 -0.85,-8.192c-5.34,2.913 -8.01,7.08 -8.01,12.5c0,1.78 0.385,3.156 1.153,4.127c0.769,0.971 1.679,1.456 2.731,1.456Z"
style="fill-rule:nonzero;"
/><path
d="M308.285,94.424c-0,-1.213 0.303,-2.134 0.91,-2.761c0.607,-0.627 1.375,-0.94 2.306,-0.94c0.93,-0 1.679,0.283 2.245,0.849l0,8.981l8.313,-0c0.85,-0 1.406,0.162 1.669,0.485c0.263,0.324 0.394,0.87 0.394,1.639l-10.376,-0l0,15.291c0,2.225 0.637,3.945 1.911,5.158c1.275,1.214 2.741,1.821 4.4,1.821c2.508,-0 4.349,-0.931 5.522,-2.792c1.173,-1.861 1.76,-4.874 1.76,-9.041c0.08,-0.243 0.384,-0.364 0.91,-0.364c0.728,-0 1.092,1.072 1.092,3.216c-0,3.277 -0.819,5.987 -2.458,8.131c-1.638,2.144 -4.156,3.216 -7.554,3.216c-3.398,0 -6.089,-0.89 -8.071,-2.67c-1.982,-1.78 -2.973,-4.429 -2.973,-7.949l-0,-22.27Z"
style="fill-rule:nonzero;"
/><path
d="M345.543,101.463c0.526,-1.173 1.365,-1.76 2.518,-1.76c1.153,0 2.013,0.284 2.579,0.85l-0,30.826c0.485,-0.041 1.254,-0.061 2.306,-0.061c1.052,0 1.578,0.445 1.578,1.335l-0.365,0.91c-1.537,0 -2.71,0.021 -3.519,0.061l-0,3.155c-0.041,4.167 -1.001,7.434 -2.882,9.8c-1.882,2.367 -4.38,3.55 -7.494,3.55c-1.861,0 -3.51,-0.556 -4.946,-1.669c-1.436,-1.112 -2.154,-2.862 -2.154,-5.248c-0,-3.075 1.092,-5.522 3.277,-7.343c2.184,-1.82 5.097,-3.095 8.738,-3.823l-0,-8.92c-1.699,2.792 -4.046,4.187 -7.039,4.187c-7.08,0 -10.619,-4.632 -10.619,-13.896c-0,-4.692 1.102,-8.151 3.307,-10.376c2.204,-2.225 5.127,-3.338 8.768,-3.338c2.791,0 4.774,0.587 5.947,1.76Zm-0.364,12.986l-0,-4.308c-0,-2.873 -0.486,-4.936 -1.457,-6.19c-0.971,-1.254 -2.093,-1.881 -3.367,-1.881c-1.275,0 -2.276,0.121 -3.004,0.364c-0.728,0.243 -1.436,0.748 -2.124,1.517c-1.295,1.456 -1.942,4.612 -1.942,9.466c0,3.196 0.283,5.684 0.85,7.464c0.566,1.78 1.213,2.903 1.942,3.368c0.728,0.465 1.749,0.698 3.064,0.698c1.315,-0 2.65,-0.84 4.005,-2.519c1.355,-1.678 2.033,-4.338 2.033,-7.979Zm-0,22.209l-0,-2.306c-5.947,1.335 -8.92,4.349 -8.92,9.042c-0,1.416 0.384,2.498 1.153,3.246c0.768,0.748 1.678,1.123 2.73,1.123c1.699,-0 2.963,-0.789 3.793,-2.367c0.829,-1.578 1.244,-4.49 1.244,-8.738Z"
style="fill-rule:nonzero;"
/><path
d="M381.891,113.478c0.849,-0 1.274,0.647 1.274,1.942c-0,2.993 -1.042,5.724 -3.125,8.192c-2.084,2.467 -5.249,3.701 -9.497,3.701c-4.247,0 -7.656,-1.143 -10.224,-3.428c-2.569,-2.286 -3.854,-5.644 -3.854,-10.073c0,-4.43 1.133,-7.889 3.398,-10.377c2.266,-2.488 5.158,-3.732 8.678,-3.732c2.548,0 4.409,0.678 5.582,2.033c1.174,1.355 1.76,2.964 1.76,4.824c0,3.034 -1.264,5.553 -3.792,7.555c-2.529,2.003 -5.755,3.004 -9.679,3.004c0.364,2.589 1.305,4.541 2.822,5.856c1.517,1.314 3.519,1.972 6.007,1.972c2.488,-0 4.733,-0.941 6.736,-2.822c2.002,-1.881 3.003,-4.642 3.003,-8.283c0.041,-0.243 0.344,-0.364 0.911,-0.364Zm-19.661,0.85l-0,0.546c2.508,-0.324 4.682,-1.113 6.523,-2.367c1.841,-1.254 2.761,-3.115 2.761,-5.583c0,-1.577 -0.344,-2.781 -1.031,-3.61c-0.688,-0.829 -1.659,-1.244 -2.913,-1.244c-1.901,0 -3.267,0.93 -4.096,2.791c-0.829,1.861 -1.244,5.017 -1.244,9.467Z"
style="fill-rule:nonzero;"
/><path
d="M393.359,99.703c3.601,0 6.534,1.194 8.799,3.581c2.265,2.386 3.398,5.633 3.398,9.739c0,4.106 -1.062,7.514 -3.186,10.225c-2.124,2.71 -4.965,4.065 -8.525,4.065c-3.56,0 -6.524,-1.224 -8.89,-3.671c-2.367,-2.447 -3.55,-5.846 -3.55,-10.194c0,-4.349 1.102,-7.727 3.307,-10.134c2.205,-2.407 5.087,-3.611 8.647,-3.611Zm0.061,2.367c-1.092,0 -2.033,0.273 -2.822,0.819c-0.789,0.546 -1.183,1.325 -1.183,2.336c-0,2.589 1.011,5.067 3.034,7.434c2.023,2.366 4.43,3.934 7.221,4.703c0.081,-1.538 0.121,-2.852 0.121,-3.945c0,-4.207 -0.445,-7.15 -1.335,-8.829c-0.89,-1.679 -2.568,-2.518 -5.036,-2.518Zm-6.25,11.347c-0,4.127 0.516,7.08 1.547,8.86c1.032,1.78 2.721,2.67 5.067,2.67c1.618,-0 2.862,-0.415 3.732,-1.244c0.87,-0.83 1.466,-2.175 1.79,-4.036c-2.63,-0.566 -5.047,-1.759 -7.251,-3.58c-2.205,-1.82 -3.813,-3.843 -4.825,-6.068c-0.04,0.688 -0.06,1.821 -0.06,3.398Z"
style="fill-rule:nonzero;"
/><path
d="M442.571,112.75c0.729,-0 1.093,1.072 1.093,3.216c-0,3.438 -0.739,6.189 -2.215,8.252c-1.477,2.064 -3.631,3.095 -6.463,3.095c-2.832,0 -5.006,-0.971 -6.523,-2.912c-1.517,-1.942 -2.275,-4.693 -2.275,-8.253l-0,-7.1c-0,-4.814 -1.214,-7.221 -3.641,-7.221c-2.144,0 -3.904,1.093 -5.28,3.277c-1.375,2.185 -2.063,5.846 -2.063,10.983l0,10.377c-0.404,0.566 -1.112,0.849 -2.124,0.849c-1.011,0 -1.82,-0.313 -2.427,-0.94c-0.607,-0.627 -0.91,-1.548 -0.91,-2.761l0,-23.059c0.405,-0.566 1.173,-0.85 2.306,-0.85c2.103,0 3.155,1.517 3.155,4.552c1.699,-3.035 4.39,-4.552 8.071,-4.552c2.629,0 4.723,0.83 6.28,2.488c1.558,1.659 2.337,4.046 2.337,7.161l-0,8.616c-0,2.306 0.364,4.046 1.092,5.219c0.728,1.173 1.81,1.76 3.246,1.76c1.436,-0 2.7,-0.9 3.793,-2.701c1.092,-1.8 1.638,-4.844 1.638,-9.132c0.041,-0.243 0.344,-0.364 0.91,-0.364Z"
style="fill-rule:nonzero;"
/></g
></g
></svg
>
</a>
</header>
<style>
a {
border: none;
}
header {
text-align: center;
margin-top: 4rem;
margin-bottom: 2rem;
}
@media screen and (max-width: 30rem) {
header {
margin-top: 1rem;
margin-bottom: 1rem;
}
header svg {
max-height: 4rem;
}
}
header svg {
width: 100%;
max-width: 16rem;
transform: translateX(-1rem);
fill: currentColor;
}
</style>

View File

@@ -0,0 +1,32 @@
<script lang="ts">
import { init } from '$lib/stores/status'
import Footer from '$lib/views/Footer.svelte'
import Header from '$lib/views/Header.svelte'
import { onMount } from 'svelte'
import '../app.css'
onMount(() => {
init()
})
</script>
<svelte:head>
<title>cryptgeon</title>
</svelte:head>
<main>
<Header />
<slot />
</main>
<Footer />
<style>
main {
padding: 1rem;
padding-bottom: 4rem;
width: 100%;
max-width: 35rem;
margin: 0 auto;
}
</style>

View File

@@ -0,0 +1,80 @@
<script context="module">
import { browser, dev } from '$app/env'
import { status } from '$lib/stores/status'
import AboutParagraph from '$lib/ui/AboutParagraph.svelte'
export const hydrate = dev
export const router = browser
export const prerender = true
</script>
<svelte:head>
<title>About</title>
</svelte:head>
<section class="content">
<h1>About</h1>
<p>
<i>cryptgeon</i> is a secure, open source sharing note / file service inspired by
<a href="https://privnote.com"><i>PrivNote</i></a>.
</p>
<AboutParagraph title="how does it work?">
<span>
each note has a generated <code>id (256bit)</code> and <code>key 256(bit)</code>. The
<code>id</code>
is used to save & retrieve the note. the note is then encrypted with aes in gcm mode on the client
side with the <code>key</code> and then sent to the server. data is stored in memory and never
persisted to disk. the server never sees the encryption key and cannot decrypt the contents of
the notes even if it tried to.
</span>
</AboutParagraph>
<AboutParagraph title="features">
<ul>
<li>server cannot decrypt contents due to client side encryption</li>
<li>view and time constraints</li>
<li>in memory, no persistence</li>
</ul>
</AboutParagraph>
<AboutParagraph title="tech stack">
<span>
the backend is written in rust and the frontend is svelte and typescript.
<br />
you are welcomed to check & audit the
<a href="https://github.com/cupcakearmy/cryptgeon" target="_blank" rel="noopener">
source code
</a>.
</span>
</AboutParagraph>
<AboutParagraph title="attribution">
<span>
icons made by <a href="https://www.freepik.com" title="Freepik">freepik</a> from
<a href="https://www.flaticon.com/" title="Flaticon">www.flaticon.com</a>
</span>
</AboutParagraph>
<AboutParagraph title="version">
<span>
{#if $status}
<code>v{$status.version}</code>
{/if}
</span>
</AboutParagraph>
</section>
<style>
section {
width: 100%;
}
ul {
margin: 0;
padding: 0;
padding-left: 1rem;
list-style: square;
}
</style>

View File

@@ -0,0 +1,81 @@
<script context="module" lang="ts">
export async function load({ params }) {
return {
props: params,
}
}
</script>
<script lang="ts">
import type { NotePublic } from '$lib/api'
import { get, info } from '$lib/api'
import { decrypt, getKeyFromString } from '$lib/crypto'
import Button from '$lib/ui/Button.svelte'
import ShowNote from '$lib/ui/ShowNote.svelte'
import { onMount } from 'svelte'
export let id: string
let password: string
let note: NotePublic | null = null
let exists = false
let loading = true
let error = false
onMount(async () => {
try {
loading = true
error = null
password = window.location.hash.slice(1)
await info(id)
exists = true
} catch {
exists = false
} finally {
loading = false
}
})
async function show() {
try {
error = false
loading = true
const data = note || (await get(id)) // Don't get the content twice on wrong password.
const key = await getKeyFromString(password)
data.contents = await decrypt(data.contents, key)
note = data
} catch {
error = true
} finally {
loading = false
}
}
</script>
{#if !loading}
{#if !exists}
<p class="error-text" data-testid="note-not-found">
note was not found or was already deleted.
</p>
{:else if note && !error}
<ShowNote {note} />
{:else}
<form on:submit|preventDefault={show}>
<fieldset>
<p>click below to show and delete the note if the counter has reached it's limit</p>
<Button type="submit" data-testid="button-show">show note</Button>
{#if error}
<br />
<p class="error-text">
wrong password. could not decipher. probably a broken link. note was destroyed.
<br />
</p>
{/if}
</fieldset>
</form>
{/if}
{/if}
{#if loading}
<p>loading...</p>
{/if}

View File

Before

Width:  |  Height:  |  Size: 6.1 KiB

After

Width:  |  Height:  |  Size: 6.1 KiB

View File

@@ -0,0 +1 @@
<svg xmlns='http://www.w3.org/2000/svg' class='ionicon' viewBox='0 0 512 512'><title>Contrast</title><path d='M256 32C132.29 32 32 132.29 32 256s100.29 224 224 224 224-100.29 224-224S379.71 32 256 32zM128.72 383.28A180 180 0 01256 76v360a178.82 178.82 0 01-127.28-52.72z'/></svg>

After

Width:  |  Height:  |  Size: 279 B

View File

Before

Width:  |  Height:  |  Size: 313 B

After

Width:  |  Height:  |  Size: 313 B

View File

Before

Width:  |  Height:  |  Size: 728 B

After

Width:  |  Height:  |  Size: 728 B

View File

Before

Width:  |  Height:  |  Size: 720 B

After

Width:  |  Height:  |  Size: 720 B

View File

Before

Width:  |  Height:  |  Size: 474 B

After

Width:  |  Height:  |  Size: 474 B

View File

Before

Width:  |  Height:  |  Size: 275 B

After

Width:  |  Height:  |  Size: 275 B

13
frontend/svelte.config.js Normal file
View File

@@ -0,0 +1,13 @@
import preprocess from 'svelte-preprocess'
import adapter from '@sveltejs/adapter-static'
export default {
preprocess: preprocess(),
kit: {
adapter: adapter({
fallback: 'index.html',
}),
target: '#svelte',
},
}

1375
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,11 +1,13 @@
{
"scripts": {
"dev:docker": "docker-compose up memcached",
"dev:backend": "cargo watch -x 'run --bin cryptgeon'",
"dev:front": "npm --prefix client run dev",
"dev:backend": "cd backend && cargo watch -x 'run --bin cryptgeon'",
"dev:front": "pnpm --prefix frontend run dev",
"dev:proxy": "node proxy.mjs",
"dev": "run-p dev:*"
},
"devDependencies": {
"http-proxy": "^1.18.1",
"npm-run-all": "^4.1.5"
}
}

489
pnpm-lock.yaml generated Normal file
View File

@@ -0,0 +1,489 @@
lockfileVersion: 5.3
specifiers:
http-proxy: ^1.18.1
npm-run-all: ^4.1.5
devDependencies:
http-proxy: 1.18.1
npm-run-all: 4.1.5
packages:
/ansi-styles/3.2.1:
resolution: {integrity: sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==}
engines: {node: '>=4'}
dependencies:
color-convert: 1.9.3
dev: true
/balanced-match/1.0.2:
resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==}
dev: true
/brace-expansion/1.1.11:
resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==}
dependencies:
balanced-match: 1.0.2
concat-map: 0.0.1
dev: true
/call-bind/1.0.2:
resolution: {integrity: sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==}
dependencies:
function-bind: 1.1.1
get-intrinsic: 1.1.1
dev: true
/chalk/2.4.2:
resolution: {integrity: sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==}
engines: {node: '>=4'}
dependencies:
ansi-styles: 3.2.1
escape-string-regexp: 1.0.5
supports-color: 5.5.0
dev: true
/color-convert/1.9.3:
resolution: {integrity: sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==}
dependencies:
color-name: 1.1.3
dev: true
/color-name/1.1.3:
resolution: {integrity: sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=}
dev: true
/concat-map/0.0.1:
resolution: {integrity: sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=}
dev: true
/cross-spawn/6.0.5:
resolution: {integrity: sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==}
engines: {node: '>=4.8'}
dependencies:
nice-try: 1.0.5
path-key: 2.0.1
semver: 5.7.1
shebang-command: 1.2.0
which: 1.3.1
dev: true
/define-properties/1.1.3:
resolution: {integrity: sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==}
engines: {node: '>= 0.4'}
dependencies:
object-keys: 1.1.1
dev: true
/error-ex/1.3.2:
resolution: {integrity: sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==}
dependencies:
is-arrayish: 0.2.1
dev: true
/es-abstract/1.18.0:
resolution: {integrity: sha512-LJzK7MrQa8TS0ja2w3YNLzUgJCGPdPOV1yVvezjNnS89D+VR08+Szt2mz3YB2Dck/+w5tfIq/RoUAFqJJGM2yw==}
engines: {node: '>= 0.4'}
dependencies:
call-bind: 1.0.2
es-to-primitive: 1.2.1
function-bind: 1.1.1
get-intrinsic: 1.1.1
has: 1.0.3
has-symbols: 1.0.2
is-callable: 1.2.3
is-negative-zero: 2.0.1
is-regex: 1.1.2
is-string: 1.0.5
object-inspect: 1.10.2
object-keys: 1.1.1
object.assign: 4.1.2
string.prototype.trimend: 1.0.4
string.prototype.trimstart: 1.0.4
unbox-primitive: 1.0.1
dev: true
/es-to-primitive/1.2.1:
resolution: {integrity: sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==}
engines: {node: '>= 0.4'}
dependencies:
is-callable: 1.2.3
is-date-object: 1.0.2
is-symbol: 1.0.3
dev: true
/escape-string-regexp/1.0.5:
resolution: {integrity: sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=}
engines: {node: '>=0.8.0'}
dev: true
/eventemitter3/4.0.7:
resolution: {integrity: sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==}
dev: true
/follow-redirects/1.14.6:
resolution: {integrity: sha512-fhUl5EwSJbbl8AR+uYL2KQDxLkdSjZGR36xy46AO7cOMTrCMON6Sa28FmAnC2tRTDbd/Uuzz3aJBv7EBN7JH8A==}
engines: {node: '>=4.0'}
peerDependencies:
debug: '*'
peerDependenciesMeta:
debug:
optional: true
dev: true
/function-bind/1.1.1:
resolution: {integrity: sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==}
dev: true
/get-intrinsic/1.1.1:
resolution: {integrity: sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q==}
dependencies:
function-bind: 1.1.1
has: 1.0.3
has-symbols: 1.0.2
dev: true
/graceful-fs/4.2.6:
resolution: {integrity: sha512-nTnJ528pbqxYanhpDYsi4Rd8MAeaBA67+RZ10CM1m3bTAVFEDcd5AuA4a6W5YkGZ1iNXHzZz8T6TBKLeBuNriQ==}
dev: true
/has-bigints/1.0.1:
resolution: {integrity: sha512-LSBS2LjbNBTf6287JEbEzvJgftkF5qFkmCo9hDRpAzKhUOlJ+hx8dd4USs00SgsUNwc4617J9ki5YtEClM2ffA==}
dev: true
/has-flag/3.0.0:
resolution: {integrity: sha1-tdRU3CGZriJWmfNGfloH87lVuv0=}
engines: {node: '>=4'}
dev: true
/has-symbols/1.0.2:
resolution: {integrity: sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw==}
engines: {node: '>= 0.4'}
dev: true
/has/1.0.3:
resolution: {integrity: sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==}
engines: {node: '>= 0.4.0'}
dependencies:
function-bind: 1.1.1
dev: true
/hosted-git-info/2.8.9:
resolution: {integrity: sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==}
dev: true
/http-proxy/1.18.1:
resolution: {integrity: sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==}
engines: {node: '>=8.0.0'}
dependencies:
eventemitter3: 4.0.7
follow-redirects: 1.14.6
requires-port: 1.0.0
transitivePeerDependencies:
- debug
dev: true
/is-arrayish/0.2.1:
resolution: {integrity: sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=}
dev: true
/is-bigint/1.0.1:
resolution: {integrity: sha512-J0ELF4yHFxHy0cmSxZuheDOz2luOdVvqjwmEcj8H/L1JHeuEDSDbeRP+Dk9kFVk5RTFzbucJ2Kb9F7ixY2QaCg==}
dev: true
/is-boolean-object/1.1.0:
resolution: {integrity: sha512-a7Uprx8UtD+HWdyYwnD1+ExtTgqQtD2k/1yJgtXP6wnMm8byhkoTZRl+95LLThpzNZJ5aEvi46cdH+ayMFRwmA==}
engines: {node: '>= 0.4'}
dependencies:
call-bind: 1.0.2
dev: true
/is-callable/1.2.3:
resolution: {integrity: sha512-J1DcMe8UYTBSrKezuIUTUwjXsho29693unXM2YhJUTR2txK/eG47bvNa/wipPFmZFgr/N6f1GA66dv0mEyTIyQ==}
engines: {node: '>= 0.4'}
dev: true
/is-core-module/2.3.0:
resolution: {integrity: sha512-xSphU2KG9867tsYdLD4RWQ1VqdFl4HTO9Thf3I/3dLEfr0dbPTWKsuCKrgqMljg4nPE+Gq0VCnzT3gr0CyBmsw==}
dependencies:
has: 1.0.3
dev: true
/is-date-object/1.0.2:
resolution: {integrity: sha512-USlDT524woQ08aoZFzh3/Z6ch9Y/EWXEHQ/AaRN0SkKq4t2Jw2R2339tSXmwuVoY7LLlBCbOIlx2myP/L5zk0g==}
engines: {node: '>= 0.4'}
dev: true
/is-negative-zero/2.0.1:
resolution: {integrity: sha512-2z6JzQvZRa9A2Y7xC6dQQm4FSTSTNWjKIYYTt4246eMTJmIo0Q+ZyOsU66X8lxK1AbB92dFeglPLrhwpeRKO6w==}
engines: {node: '>= 0.4'}
dev: true
/is-number-object/1.0.4:
resolution: {integrity: sha512-zohwelOAur+5uXtk8O3GPQ1eAcu4ZX3UwxQhUlfFFMNpUd83gXgjbhJh6HmB6LUNV/ieOLQuDwJO3dWJosUeMw==}
engines: {node: '>= 0.4'}
dev: true
/is-regex/1.1.2:
resolution: {integrity: sha512-axvdhb5pdhEVThqJzYXwMlVuZwC+FF2DpcOhTS+y/8jVq4trxyPgfcwIxIKiyeuLlSQYKkmUaPQJ8ZE4yNKXDg==}
engines: {node: '>= 0.4'}
dependencies:
call-bind: 1.0.2
has-symbols: 1.0.2
dev: true
/is-string/1.0.5:
resolution: {integrity: sha512-buY6VNRjhQMiF1qWDouloZlQbRhDPCebwxSjxMjxgemYT46YMd2NR0/H+fBhEfWX4A/w9TBJ+ol+okqJKFE6vQ==}
engines: {node: '>= 0.4'}
dev: true
/is-symbol/1.0.3:
resolution: {integrity: sha512-OwijhaRSgqvhm/0ZdAcXNZt9lYdKFpcRDT5ULUuYXPoT794UNOdU+gpT6Rzo7b4V2HUl/op6GqY894AZwv9faQ==}
engines: {node: '>= 0.4'}
dependencies:
has-symbols: 1.0.2
dev: true
/isexe/2.0.0:
resolution: {integrity: sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=}
dev: true
/json-parse-better-errors/1.0.2:
resolution: {integrity: sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==}
dev: true
/load-json-file/4.0.0:
resolution: {integrity: sha1-L19Fq5HjMhYjT9U62rZo607AmTs=}
engines: {node: '>=4'}
dependencies:
graceful-fs: 4.2.6
parse-json: 4.0.0
pify: 3.0.0
strip-bom: 3.0.0
dev: true
/memorystream/0.3.1:
resolution: {integrity: sha1-htcJCzDORV1j+64S3aUaR93K+bI=}
engines: {node: '>= 0.10.0'}
dev: true
/minimatch/3.0.4:
resolution: {integrity: sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==}
dependencies:
brace-expansion: 1.1.11
dev: true
/nice-try/1.0.5:
resolution: {integrity: sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==}
dev: true
/normalize-package-data/2.5.0:
resolution: {integrity: sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==}
dependencies:
hosted-git-info: 2.8.9
resolve: 1.20.0
semver: 5.7.1
validate-npm-package-license: 3.0.4
dev: true
/npm-run-all/4.1.5:
resolution: {integrity: sha512-Oo82gJDAVcaMdi3nuoKFavkIHBRVqQ1qvMb+9LHk/cF4P6B2m8aP04hGf7oL6wZ9BuGwX1onlLhpuoofSyoQDQ==}
engines: {node: '>= 4'}
hasBin: true
dependencies:
ansi-styles: 3.2.1
chalk: 2.4.2
cross-spawn: 6.0.5
memorystream: 0.3.1
minimatch: 3.0.4
pidtree: 0.3.1
read-pkg: 3.0.0
shell-quote: 1.7.2
string.prototype.padend: 3.1.2
dev: true
/object-inspect/1.10.2:
resolution: {integrity: sha512-gz58rdPpadwztRrPjZE9DZLOABUpTGdcANUgOwBFO1C+HZZhePoP83M65WGDmbpwFYJSWqavbl4SgDn4k8RYTA==}
dev: true
/object-keys/1.1.1:
resolution: {integrity: sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==}
engines: {node: '>= 0.4'}
dev: true
/object.assign/4.1.2:
resolution: {integrity: sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ==}
engines: {node: '>= 0.4'}
dependencies:
call-bind: 1.0.2
define-properties: 1.1.3
has-symbols: 1.0.2
object-keys: 1.1.1
dev: true
/parse-json/4.0.0:
resolution: {integrity: sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=}
engines: {node: '>=4'}
dependencies:
error-ex: 1.3.2
json-parse-better-errors: 1.0.2
dev: true
/path-key/2.0.1:
resolution: {integrity: sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=}
engines: {node: '>=4'}
dev: true
/path-parse/1.0.6:
resolution: {integrity: sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==}
dev: true
/path-type/3.0.0:
resolution: {integrity: sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==}
engines: {node: '>=4'}
dependencies:
pify: 3.0.0
dev: true
/pidtree/0.3.1:
resolution: {integrity: sha512-qQbW94hLHEqCg7nhby4yRC7G2+jYHY4Rguc2bjw7Uug4GIJuu1tvf2uHaZv5Q8zdt+WKJ6qK1FOI6amaWUo5FA==}
engines: {node: '>=0.10'}
hasBin: true
dev: true
/pify/3.0.0:
resolution: {integrity: sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=}
engines: {node: '>=4'}
dev: true
/read-pkg/3.0.0:
resolution: {integrity: sha1-nLxoaXj+5l0WwA4rGcI3/Pbjg4k=}
engines: {node: '>=4'}
dependencies:
load-json-file: 4.0.0
normalize-package-data: 2.5.0
path-type: 3.0.0
dev: true
/requires-port/1.0.0:
resolution: {integrity: sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=}
dev: true
/resolve/1.20.0:
resolution: {integrity: sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A==}
dependencies:
is-core-module: 2.3.0
path-parse: 1.0.6
dev: true
/semver/5.7.1:
resolution: {integrity: sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==}
hasBin: true
dev: true
/shebang-command/1.2.0:
resolution: {integrity: sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=}
engines: {node: '>=0.10.0'}
dependencies:
shebang-regex: 1.0.0
dev: true
/shebang-regex/1.0.0:
resolution: {integrity: sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=}
engines: {node: '>=0.10.0'}
dev: true
/shell-quote/1.7.2:
resolution: {integrity: sha512-mRz/m/JVscCrkMyPqHc/bczi3OQHkLTqXHEFu0zDhK/qfv3UcOA4SVmRCLmos4bhjr9ekVQubj/R7waKapmiQg==}
dev: true
/spdx-correct/3.1.1:
resolution: {integrity: sha512-cOYcUWwhCuHCXi49RhFRCyJEK3iPj1Ziz9DpViV3tbZOwXD49QzIN3MpOLJNxh2qwq2lJJZaKMVw9qNi4jTC0w==}
dependencies:
spdx-expression-parse: 3.0.1
spdx-license-ids: 3.0.7
dev: true
/spdx-exceptions/2.3.0:
resolution: {integrity: sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==}
dev: true
/spdx-expression-parse/3.0.1:
resolution: {integrity: sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==}
dependencies:
spdx-exceptions: 2.3.0
spdx-license-ids: 3.0.7
dev: true
/spdx-license-ids/3.0.7:
resolution: {integrity: sha512-U+MTEOO0AiDzxwFvoa4JVnMV6mZlJKk2sBLt90s7G0Gd0Mlknc7kxEn3nuDPNZRta7O2uy8oLcZLVT+4sqNZHQ==}
dev: true
/string.prototype.padend/3.1.2:
resolution: {integrity: sha512-/AQFLdYvePENU3W5rgurfWSMU6n+Ww8n/3cUt7E+vPBB/D7YDG8x+qjoFs4M/alR2bW7Qg6xMjVwWUOvuQ0XpQ==}
engines: {node: '>= 0.4'}
dependencies:
call-bind: 1.0.2
define-properties: 1.1.3
es-abstract: 1.18.0
dev: true
/string.prototype.trimend/1.0.4:
resolution: {integrity: sha512-y9xCjw1P23Awk8EvTpcyL2NIr1j7wJ39f+k6lvRnSMz+mz9CGz9NYPelDk42kOz6+ql8xjfK8oYzy3jAP5QU5A==}
dependencies:
call-bind: 1.0.2
define-properties: 1.1.3
dev: true
/string.prototype.trimstart/1.0.4:
resolution: {integrity: sha512-jh6e984OBfvxS50tdY2nRZnoC5/mLFKOREQfw8t5yytkoUsJRNxvI/E39qu1sD0OtWI3OC0XgKSmcWwziwYuZw==}
dependencies:
call-bind: 1.0.2
define-properties: 1.1.3
dev: true
/strip-bom/3.0.0:
resolution: {integrity: sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=}
engines: {node: '>=4'}
dev: true
/supports-color/5.5.0:
resolution: {integrity: sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==}
engines: {node: '>=4'}
dependencies:
has-flag: 3.0.0
dev: true
/unbox-primitive/1.0.1:
resolution: {integrity: sha512-tZU/3NqK3dA5gpE1KtyiJUrEB0lxnGkMFHptJ7q6ewdZ8s12QrODwNbhIJStmJkd1QDXa1NRA8aF2A1zk/Ypyw==}
dependencies:
function-bind: 1.1.1
has-bigints: 1.0.1
has-symbols: 1.0.2
which-boxed-primitive: 1.0.2
dev: true
/validate-npm-package-license/3.0.4:
resolution: {integrity: sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==}
dependencies:
spdx-correct: 3.1.1
spdx-expression-parse: 3.0.1
dev: true
/which-boxed-primitive/1.0.2:
resolution: {integrity: sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==}
dependencies:
is-bigint: 1.0.1
is-boolean-object: 1.1.0
is-number-object: 1.0.4
is-string: 1.0.5
is-symbol: 1.0.3
dev: true
/which/1.3.1:
resolution: {integrity: sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==}
hasBin: true
dependencies:
isexe: 2.0.0
dev: true

15
proxy.mjs Normal file
View File

@@ -0,0 +1,15 @@
import http from 'http'
import httpProxy from 'http-proxy'
const proxy = httpProxy.createProxyServer()
proxy.on('error', function (err, req, res) {
res.writeHead(500, { 'Content-Type': 'text/plain' })
res.end('500 Internal Server Error')
})
const server = http.createServer(function (req, res) {
const target = req.url.startsWith('/api/') ? 'http://localhost:5000' : 'http://localhost:3000'
proxy.web(req, res, { target })
})
server.listen(1234)
console.log('Proxy on http://localhost:1234')