mirror of
https://github.com/cupcakearmy/cryptgeon.git
synced 2025-09-04 08:30:39 +00:00
Compare commits
64 Commits
Author | SHA1 | Date | |
---|---|---|---|
2def365cae | |||
c8b2539414 | |||
c8a25eb9bf | |||
15bceb1715 | |||
8acc4108ae | |||
0f708f53c0 | |||
8d03ad8e15 | |||
33829768eb | |||
8cee6579e2 | |||
8eeb2a8de7 | |||
e4ce767444 | |||
00fd514da5 | |||
ba38d2b819 | |||
d0f83e6148 | |||
a040ad469e | |||
0c01866344 | |||
048c5198a2 | |||
f606916d97 | |||
aea85c3b73 | |||
5f904b3971 | |||
ac5d52a010 | |||
8644a937d0 | |||
a0ebb97bc5 | |||
19cd9b8507 | |||
fe653e91c8 | |||
a78ec72687 | |||
a462bed948 | |||
325518ba15 | |||
4b80912727 | |||
|
c78ad636c3 | ||
4fe7833977 | |||
24f9aeb229 | |||
976413e11b | |||
2480d875b4 | |||
5dff12ea70 | |||
e332dc63e8 | |||
a18e9bcc88 | |||
4b43edf54a | |||
e3aa2dd5ff | |||
98a03c25e6 | |||
7f618e7e45 | |||
84a7be4549 | |||
b2bad5f64c | |||
41f55c0920 | |||
edbf8a8ecf | |||
4852804581 | |||
22b1c35b3e | |||
d1e9ffd89b | |||
9c675ba48c | |||
ef3d3d5bde | |||
7e835af3f2 | |||
f153102978 | |||
5944c784ba | |||
2aa186450a | |||
70b53106ea | |||
b958189b0c | |||
acd488aab0 | |||
5378b7a820 | |||
1bb5d3ecb0 | |||
0d79e9c85e | |||
70382a63ed | |||
b3886cc6fc | |||
cfe525f274 | |||
96e8ec4b67 |
@@ -1 +1,2 @@
|
|||||||
target
|
target
|
||||||
|
node_modules
|
3
.github/workflows/docker.yml
vendored
3
.github/workflows/docker.yml
vendored
@@ -14,6 +14,8 @@ jobs:
|
|||||||
uses: docker/setup-qemu-action@v1
|
uses: docker/setup-qemu-action@v1
|
||||||
- name: Set up Docker Buildx
|
- name: Set up Docker Buildx
|
||||||
uses: docker/setup-buildx-action@v1
|
uses: docker/setup-buildx-action@v1
|
||||||
|
with:
|
||||||
|
install: true
|
||||||
- name: Docker Labels
|
- name: Docker Labels
|
||||||
id: meta
|
id: meta
|
||||||
uses: crazy-max/ghaction-docker-meta@v2
|
uses: crazy-max/ghaction-docker-meta@v2
|
||||||
@@ -32,6 +34,7 @@ jobs:
|
|||||||
id: docker_build
|
id: docker_build
|
||||||
uses: docker/build-push-action@v2
|
uses: docker/build-push-action@v2
|
||||||
with:
|
with:
|
||||||
|
platforms: linux/amd64,linux/arm64
|
||||||
push: true
|
push: true
|
||||||
tags: ${{ steps.meta.outputs.tags }}
|
tags: ${{ steps.meta.outputs.tags }}
|
||||||
- name: Image digest
|
- name: Image digest
|
||||||
|
1
.gitignore
vendored
1
.gitignore
vendored
@@ -8,3 +8,4 @@ node_modules
|
|||||||
/.svelte
|
/.svelte
|
||||||
/build
|
/build
|
||||||
/functions
|
/functions
|
||||||
|
.env
|
||||||
|
108
CHANGELOG.md
108
CHANGELOG.md
@@ -5,47 +5,137 @@ 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/),
|
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).
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||||
|
|
||||||
|
## [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
|
## [1.0.6] - 2021-05-04
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
|
||||||
- Always use encryption with random passwords included links
|
- Always use encryption with random passwords included links.
|
||||||
|
|
||||||
## [1.0.5] - 2021-05-03
|
## [1.0.5] - 2021-05-03
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
|
|
||||||
- Typos
|
- Typos.
|
||||||
|
|
||||||
## [1.0.4] - 2021-05-02
|
## [1.0.4] - 2021-05-02
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
|
||||||
- From scratch docker image
|
- From scratch docker image.
|
||||||
|
|
||||||
## [1.0.3] - 2021-05-02
|
## [1.0.3] - 2021-05-02
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
|
|
||||||
- Higher default text area
|
- Higher default text area.
|
||||||
- Mobile touchups
|
- Mobile touchups.
|
||||||
|
|
||||||
## [1.0.2] - 2021-05-02
|
## [1.0.2] - 2021-05-02
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
|
|
||||||
- SVG Icons
|
- SVG Icons.
|
||||||
|
|
||||||
## [1.0.1] - 2021-05-02
|
## [1.0.1] - 2021-05-02
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
|
||||||
- Dark mode support
|
- Dark mode support.
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
|
|
||||||
- Don't reload data on wrong password
|
- Don't reload data on wrong password.
|
||||||
|
|
||||||
## [1.0.0] - 2021-05-02
|
## [1.0.0] - 2021-05-02
|
||||||
|
|
||||||
Initial release
|
Initial release.
|
||||||
|
512
Cargo.lock
generated
512
Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "cryptgeon"
|
name = "cryptgeon"
|
||||||
version = "1.0.0"
|
version = "1.3.0"
|
||||||
authors = ["cupcakearmy <hi@nicco.io>"]
|
authors = ["cupcakearmy <hi@nicco.io>"]
|
||||||
edition = "2018"
|
edition = "2018"
|
||||||
|
|
||||||
@@ -18,4 +18,7 @@ serde_json = "1"
|
|||||||
lazy_static = "1"
|
lazy_static = "1"
|
||||||
ring = "0.16"
|
ring = "0.16"
|
||||||
bs62 = "0.1"
|
bs62 = "0.1"
|
||||||
memcache = "0.15"
|
memcache = "0.16"
|
||||||
|
byte-unit = "4"
|
||||||
|
dotenv = "0.15"
|
||||||
|
mime = "0.3"
|
||||||
|
13
Dockerfile
13
Dockerfile
@@ -1,16 +1,17 @@
|
|||||||
FROM node:16-alpine as CLIENT
|
FROM node:16-alpine as CLIENT
|
||||||
|
|
||||||
WORKDIR /tmp
|
WORKDIR /tmp
|
||||||
COPY ./client .
|
COPY ./client ./
|
||||||
|
|
||||||
RUN npm ci
|
RUN npm install -g pnpm
|
||||||
RUN npm run build
|
RUN pnpm install
|
||||||
|
RUN pnpm run build
|
||||||
|
|
||||||
FROM rust:1.51-alpine as RUST
|
FROM rust:1.51-alpine as RUST
|
||||||
|
|
||||||
WORKDIR /tmp
|
WORKDIR /tmp
|
||||||
RUN apk add libc-dev openssl-dev alpine-sdk
|
RUN apk add libc-dev openssl-dev alpine-sdk
|
||||||
COPY ./Cargo* .
|
COPY ./Cargo* ./
|
||||||
COPY ./src ./src
|
COPY ./src ./src
|
||||||
|
|
||||||
RUN cargo build --release
|
RUN cargo build --release
|
||||||
@@ -23,4 +24,6 @@ COPY --from=CLIENT /tmp/build ./client/build
|
|||||||
|
|
||||||
ENV MEMCACHE=memcached:11211
|
ENV MEMCACHE=memcached:11211
|
||||||
|
|
||||||
ENTRYPOINT [ "/app/cryptgeon" ]
|
EXPOSE 5000
|
||||||
|
|
||||||
|
ENTRYPOINT [ "/app/cryptgeon" ]
|
||||||
|
90
README.md
90
README.md
@@ -1,14 +1,21 @@
|
|||||||
<p align="center">
|
<p align="center">
|
||||||
<img src="./design/Github.png">
|
<img src="./design/Github.png" alt="logo">
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||

|
<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?
|
## 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
|
## Demo
|
||||||
|
|
||||||
@@ -17,20 +24,36 @@ Check out the demo and see for yourself https://cryptgeon.nicco.io.
|
|||||||
## Features
|
## Features
|
||||||
|
|
||||||
- server cannot decrypt contents due to client side encryption
|
- server cannot decrypt contents due to client side encryption
|
||||||
- view and time constrains
|
- view or time constraints
|
||||||
- in memory, no persistence
|
- in memory, no persistence
|
||||||
- obligatory dark mode support
|
- obligatory dark mode support
|
||||||
|
|
||||||
## How does it work?
|
## 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
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
|
## 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
|
## 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).
|
Docker is the easiest way. There is the [official image here](https://hub.docker.com/r/cupcakearmy/cryptgeon).
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
@@ -41,19 +64,64 @@ version: '3.7'
|
|||||||
services:
|
services:
|
||||||
memcached:
|
memcached:
|
||||||
image: memcached:1-alpine
|
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:
|
app:
|
||||||
image: cupcakearmy/cryptgeon:latest
|
image: cupcakearmy/cryptgeon:latest
|
||||||
|
depends_on:
|
||||||
|
- memcached
|
||||||
|
environment:
|
||||||
|
SIZE_LIMIT: 4M
|
||||||
ports:
|
ports:
|
||||||
- 80:5000
|
- 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
|
## Development
|
||||||
|
|
||||||
1. Clone
|
1. Clone
|
||||||
2. run `npm i` in the root and and client `client/` folders.
|
2. run `pnpm i` in the root and and client `client/` folders.
|
||||||
3. Run `npm run dev` to start development.
|
3. Run `pnpm run dev` to start development.
|
||||||
|
|
||||||
Running `npm run dev` in the root folder will start the following things
|
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
|
- rust backend with hot reload
|
||||||
- client 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
|
###### Attributions
|
||||||
|
|
||||||
|
1
client/.gitignore
vendored
1
client/.gitignore
vendored
@@ -1,5 +1,6 @@
|
|||||||
.DS_Store
|
.DS_Store
|
||||||
node_modules
|
node_modules
|
||||||
/.svelte
|
/.svelte
|
||||||
|
/.svelte-kit
|
||||||
/build
|
/build
|
||||||
/functions
|
/functions
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
├─ MIT: 43
|
├─ MIT: 46
|
||||||
├─ MIT*: 2
|
├─ MIT*: 2
|
||||||
├─ BSD-3-Clause: 2
|
├─ BSD-3-Clause: 2
|
||||||
├─ ISC: 1
|
├─ ISC: 1
|
||||||
|
|
1000
client/package-lock.json
generated
1000
client/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -4,21 +4,22 @@
|
|||||||
"dev": "svelte-kit dev",
|
"dev": "svelte-kit dev",
|
||||||
"build": "svelte-kit build",
|
"build": "svelte-kit build",
|
||||||
"preview": "svelte-kit preview",
|
"preview": "svelte-kit preview",
|
||||||
"licenses": "npx license-checker --summary > licenses.csv"
|
"licenses": "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",
|
"type": "module",
|
||||||
|
"devDependencies": {
|
||||||
|
"@sveltejs/adapter-static": "^1.0.0-next.22",
|
||||||
|
"@sveltejs/kit": "^1.0.0-next.202",
|
||||||
|
"svelte": "^3.44.3",
|
||||||
|
"svelte-preprocess": "^4.10.1",
|
||||||
|
"tslib": "^2.3.1",
|
||||||
|
"typescript": "^4.5.4",
|
||||||
|
"vite": "^2.7.4"
|
||||||
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@fontsource/fira-mono": "^4.2.2",
|
"@fontsource/fira-mono": "^4.5.0",
|
||||||
"axios": "^0.21.1",
|
"copy-to-clipboard": "^3.3.1",
|
||||||
"copy-to-clipboard": "^3.3.1"
|
"file-saver": "^2.0.5",
|
||||||
|
"pretty-bytes": "^5.6.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
638
client/pnpm-lock.yaml
generated
Normal file
638
client/pnpm-lock.yaml
generated
Normal file
@@ -0,0 +1,638 @@
|
|||||||
|
lockfileVersion: 5.3
|
||||||
|
|
||||||
|
specifiers:
|
||||||
|
'@fontsource/fira-mono': ^4.5.0
|
||||||
|
'@sveltejs/adapter-static': ^1.0.0-next.22
|
||||||
|
'@sveltejs/kit': ^1.0.0-next.202
|
||||||
|
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.4
|
||||||
|
|
||||||
|
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.22
|
||||||
|
'@sveltejs/kit': 1.0.0-next.202_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.4
|
||||||
|
|
||||||
|
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.0
|
||||||
|
dev: true
|
||||||
|
|
||||||
|
/@sveltejs/adapter-static/1.0.0-next.22:
|
||||||
|
resolution: {integrity: sha512-Dc1V9Z72dA7caVwNxxzl9Jhcq4uN9N1udA2GKNTLMu3aWX3Cq+v6C2CddY9Aazr+F9h6J0vi9AienuH+ySRXzQ==}
|
||||||
|
dev: true
|
||||||
|
|
||||||
|
/@sveltejs/kit/1.0.0-next.202_svelte@3.44.3:
|
||||||
|
resolution: {integrity: sha512-rXmJ0FplkWvD1CaeCfejRYhOJYrlmeUm5Fkw7gIKDdWPQev5rqOhd9B9ZvRpq35oMqCAwaOfK+e5S6k+83feEQ==}
|
||||||
|
engines: {node: '>=14.13'}
|
||||||
|
hasBin: true
|
||||||
|
peerDependencies:
|
||||||
|
svelte: ^3.44.0
|
||||||
|
dependencies:
|
||||||
|
'@sveltejs/vite-plugin-svelte': 1.0.0-next.32_svelte@3.44.3+vite@2.7.4
|
||||||
|
cheap-watch: 1.0.4
|
||||||
|
sade: 1.7.4
|
||||||
|
svelte: 3.44.3
|
||||||
|
vite: 2.7.4
|
||||||
|
transitivePeerDependencies:
|
||||||
|
- diff-match-patch
|
||||||
|
- less
|
||||||
|
- sass
|
||||||
|
- stylus
|
||||||
|
- supports-color
|
||||||
|
dev: true
|
||||||
|
|
||||||
|
/@sveltejs/vite-plugin-svelte/1.0.0-next.32_svelte@3.44.3+vite@2.7.4:
|
||||||
|
resolution: {integrity: sha512-Lhf5BxVylosHIW6U2s6WDQA39ycd+bXivC8gHsXCJeLzxoHj7Pv7XAOk25xRSXT4wHg9DWFMBQh2DFU0DxHZ2g==}
|
||||||
|
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.7_svelte@3.44.3
|
||||||
|
vite: 2.7.4
|
||||||
|
transitivePeerDependencies:
|
||||||
|
- supports-color
|
||||||
|
dev: true
|
||||||
|
|
||||||
|
/@types/node/17.0.1:
|
||||||
|
resolution: {integrity: sha512-NXKvBVUzIbs6ylBwmOwHFkZS2EXCcjnqr8ZCRNaXBkHAf+3mn/rPcJxwrzuc6movh8fxQAsUUfYklJ/EG+hZqQ==}
|
||||||
|
dev: true
|
||||||
|
|
||||||
|
/@types/pug/2.0.5:
|
||||||
|
resolution: {integrity: sha512-LOnASQoeNZMkzexRuyqcBBDZ6rS+rQxUMkmj5A0PkhhiSZivLIuz6Hxyr1mkGoEZEkk66faROmpMi4fFkrKsBA==}
|
||||||
|
dev: true
|
||||||
|
|
||||||
|
/@types/sass/1.43.1:
|
||||||
|
resolution: {integrity: sha512-BPdoIt1lfJ6B7rw35ncdwBZrAssjcwzI5LByIrYs+tpXlj/CAkuVdRsgZDdP4lq5EjyWzwxZCqAoFyHKFwp32g==}
|
||||||
|
dependencies:
|
||||||
|
'@types/node': 17.0.1
|
||||||
|
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
|
||||||
|
|
||||||
|
/cheap-watch/1.0.4:
|
||||||
|
resolution: {integrity: sha512-QR/9FrtRL5fjfUJBhAKCdi0lSRQ3rVRRum3GF9wDKp2TJbEIMGhUEr2yU8lORzm9Isdjx7/k9S0DFDx+z5VGtw==}
|
||||||
|
engines: {node: '>=8'}
|
||||||
|
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
|
||||||
|
|
||||||
|
/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.0:
|
||||||
|
resolution: {integrity: sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw==}
|
||||||
|
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.61.1:
|
||||||
|
resolution: {integrity: sha512-BbTXlEvB8d+XFbK/7E5doIcRtxWPRiqr0eb5vQ0+2paMM04Ye4PZY5nHOQef2ix24l/L0SpLd5hwcH15QHPdvA==}
|
||||||
|
engines: {node: '>=10.0.0'}
|
||||||
|
hasBin: true
|
||||||
|
optionalDependencies:
|
||||||
|
fsevents: 2.3.2
|
||||||
|
dev: true
|
||||||
|
|
||||||
|
/sade/1.7.4:
|
||||||
|
resolution: {integrity: sha512-y5yauMD93rX840MwUJr7C1ysLFBgMspsdTo4UVrDg3fXDvtwOyIqykhVAAm6fk/3au77773itJStObgK+LKaiA==}
|
||||||
|
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.7_svelte@3.44.3:
|
||||||
|
resolution: {integrity: sha512-pDrzgcWSoMaK6AJkBWkmgIsecW0GChxYZSZieIYfCP0v2oPyx2CYU/zm7TBIcjLVUPP714WxmViE9Thht4etog==}
|
||||||
|
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.5
|
||||||
|
'@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
|
||||||
|
|
||||||
|
/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.4:
|
||||||
|
resolution: {integrity: sha512-f+0426k9R/roz5mRNwJlQ+6UOnhCwIypJSbfgCmsVzVJe9jTTM5iRX2GWYUean+iqPBWaU/dYLryx9AoH2pmrw==}
|
||||||
|
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.61.1
|
||||||
|
optionalDependencies:
|
||||||
|
fsevents: 2.3.2
|
||||||
|
dev: true
|
||||||
|
|
||||||
|
/wrappy/1.0.2:
|
||||||
|
resolution: {integrity: sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=}
|
||||||
|
dev: true
|
@@ -7,29 +7,46 @@
|
|||||||
:root {
|
:root {
|
||||||
font-family: 'Fira Mono', monospace;
|
font-family: 'Fira Mono', monospace;
|
||||||
|
|
||||||
--ui-bg-0: #fefefe;
|
--ui-bg-0: #111;
|
||||||
--ui-bg-0-85: #fefefed9;
|
--ui-bg-0-85: #111111d9;
|
||||||
--ui-bg-1: #eee;
|
--ui-bg-1: #333;
|
||||||
--ui-bg-2: #e2e2e2;
|
--ui-bg-2: #444;
|
||||||
--ui-text-0: #111;
|
--ui-text-0: #fefefe;
|
||||||
--ui-text-1: #222;
|
--ui-text-1: #eee;
|
||||||
--ui-clr-primary: hsl(186, 65%, 55%);
|
--ui-clr-primary: hsl(186, 65%, 55%);
|
||||||
--ui-clr-error: hsl(357, 77%, 51%);
|
--ui-clr-error: hsl(357, 77%, 51%);
|
||||||
|
|
||||||
--ui-anim: all 150ms ease;
|
--ui-anim: all 150ms ease;
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (prefers-color-scheme: dark) {
|
@media (prefers-color-scheme: light) {
|
||||||
:root {
|
:root {
|
||||||
--ui-bg-0: #111;
|
--ui-bg-0: #fefefe;
|
||||||
--ui-bg-0-85: #111111d9;
|
--ui-bg-0-85: #fefefed9;
|
||||||
--ui-bg-1: #222;
|
--ui-bg-1: #eee;
|
||||||
--ui-bg-2: #282828;
|
--ui-bg-2: #e2e2e2;
|
||||||
--ui-text-0: #fefefe;
|
--ui-text-0: #111;
|
||||||
--ui-text-1: #eee;
|
--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 {
|
.error-text {
|
||||||
color: var(--ui-clr-error);
|
color: var(--ui-clr-error);
|
||||||
}
|
}
|
||||||
@@ -61,6 +78,8 @@ input,
|
|||||||
textarea,
|
textarea,
|
||||||
button {
|
button {
|
||||||
appearance: none;
|
appearance: none;
|
||||||
|
-webkit-appearance: none;
|
||||||
|
border-radius: 0;
|
||||||
transition: var(--ui-anim);
|
transition: var(--ui-anim);
|
||||||
font-family: inherit;
|
font-family: inherit;
|
||||||
font-size: inherit;
|
font-size: inherit;
|
||||||
@@ -78,3 +97,28 @@ fieldset {
|
|||||||
padding: 0;
|
padding: 0;
|
||||||
border: none;
|
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;
|
||||||
|
}
|
||||||
|
@@ -1,37 +1,74 @@
|
|||||||
import axios from 'axios'
|
export type NoteMeta = { type: 'text' | 'file' }
|
||||||
import { dev } from '$app/env'
|
|
||||||
|
|
||||||
const base = axios.create({ baseURL: dev ? 'http://localhost:5000' : undefined })
|
|
||||||
|
|
||||||
export type Note = {
|
export type Note = {
|
||||||
contents: string
|
contents: string
|
||||||
|
meta: NoteMeta
|
||||||
views?: number
|
views?: number
|
||||||
expiration?: number
|
expiration?: number
|
||||||
}
|
}
|
||||||
export type NoteInfo = {}
|
export type NoteInfo = {}
|
||||||
export type NotePublic = Pick<Note, 'contents'>
|
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) {
|
export async function create(note: Note) {
|
||||||
const { data } = await base({
|
const { meta, ...rest } = note
|
||||||
url: '/api/notes',
|
const body: NoteCreate = {
|
||||||
|
...rest,
|
||||||
|
meta: JSON.stringify(meta),
|
||||||
|
}
|
||||||
|
const data = await call({
|
||||||
|
url: 'notes/',
|
||||||
method: 'post',
|
method: 'post',
|
||||||
data: note,
|
body,
|
||||||
})
|
})
|
||||||
return data as { id: string }
|
return data as { id: string }
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function get(id: string) {
|
export async function get(id: string): Promise<NotePublic> {
|
||||||
const { data } = await base({
|
const data = await call({
|
||||||
url: `/api/notes/${id}`,
|
url: `notes/${id}`,
|
||||||
method: 'delete',
|
method: 'delete',
|
||||||
})
|
})
|
||||||
return data as NotePublic
|
const { contents, meta } = data
|
||||||
|
return {
|
||||||
|
contents,
|
||||||
|
meta: JSON.parse(meta) as NoteMeta,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function info(id: string) {
|
export async function info(id: string): Promise<NoteInfo> {
|
||||||
const { data } = await base({
|
const data = await call({
|
||||||
url: `/api/notes/${id}`,
|
url: `notes/${id}`,
|
||||||
method: 'get',
|
method: 'get',
|
||||||
})
|
})
|
||||||
return data as NoteInfo
|
return data
|
||||||
}
|
}
|
||||||
|
@@ -36,7 +36,7 @@ export function getKeyFromString(password: string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export async function getDerivedForKey(key: CryptoKey, salt: ArrayBuffer) {
|
export async function getDerivedForKey(key: CryptoKey, salt: ArrayBuffer) {
|
||||||
const iterations = 1_000
|
const iterations = 100_000
|
||||||
return window.crypto.subtle.deriveKey(
|
return window.crypto.subtle.deriveKey(
|
||||||
{
|
{
|
||||||
name: 'PBKDF2',
|
name: 'PBKDF2',
|
||||||
|
13
client/src/lib/files.ts
Normal file
13
client/src/lib/files.ts
Normal 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())
|
||||||
|
}
|
||||||
|
}
|
17
client/src/lib/stores/status.ts
Normal file
17
client/src/lib/stores/status.ts
Normal 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)
|
||||||
|
}
|
19
client/src/lib/ui/AboutParagraph.svelte
Normal file
19
client/src/lib/ui/AboutParagraph.svelte
Normal 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>
|
72
client/src/lib/ui/FileUpload.svelte
Normal file
72
client/src/lib/ui/FileUpload.svelte
Normal 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>
|
12
client/src/lib/ui/MaxSize.svelte
Normal file
12
client/src/lib/ui/MaxSize.svelte
Normal 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>
|
69
client/src/lib/ui/ShowNote.svelte
Normal file
69
client/src/lib/ui/ShowNote.svelte
Normal 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>
|
@@ -4,7 +4,7 @@
|
|||||||
export let color = true
|
export let color = true
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div>
|
<div {...$$restProps}>
|
||||||
<label class="switch">
|
<label class="switch">
|
||||||
<small>{label}</small>
|
<small>{label}</small>
|
||||||
<input type="checkbox" bind:checked={value} />
|
<input type="checkbox" bind:checked={value} />
|
||||||
|
@@ -7,28 +7,5 @@
|
|||||||
<small>
|
<small>
|
||||||
{label}
|
{label}
|
||||||
</small>
|
</small>
|
||||||
<textarea {...$$restProps} bind:value />
|
<textarea class="box" {...$$restProps} bind:value />
|
||||||
</label>
|
</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>
|
|
||||||
|
62
client/src/lib/ui/ThemeToggle.svelte
Normal file
62
client/src/lib/ui/ThemeToggle.svelte
Normal 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>
|
@@ -1,20 +1,23 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import type { Note } from '$lib/api'
|
import { create, Note, PayloadToLargeError } from '$lib/api'
|
||||||
import { create } from '$lib/api'
|
import { encrypt, getKeyFromString, getRandomBytes, Hex } from '$lib/crypto'
|
||||||
import { getKeyFromString, encrypt, Hex, getRandomBytes } from '$lib/crypto'
|
|
||||||
|
|
||||||
import Button from '$lib/ui/Button.svelte'
|
import Button from '$lib/ui/Button.svelte'
|
||||||
|
import FileUpload from '$lib/ui/FileUpload.svelte'
|
||||||
|
import MaxSize from '$lib/ui/MaxSize.svelte'
|
||||||
import Switch from '$lib/ui/Switch.svelte'
|
import Switch from '$lib/ui/Switch.svelte'
|
||||||
import TextArea from '$lib/ui/TextArea.svelte'
|
import TextArea from '$lib/ui/TextArea.svelte'
|
||||||
import TextInput from '$lib/ui/TextInput.svelte'
|
import TextInput from '$lib/ui/TextInput.svelte'
|
||||||
|
import { blur } from 'svelte/transition'
|
||||||
|
|
||||||
let note: Note = {
|
let note: Note = {
|
||||||
contents: '',
|
contents: '',
|
||||||
|
meta: { type: 'text' },
|
||||||
views: 1,
|
views: 1,
|
||||||
expiration: 60,
|
expiration: 60,
|
||||||
}
|
}
|
||||||
let result: { password: string; id: string } | null = null
|
let result: { password: string; id: string } | null = null
|
||||||
let advanced = false
|
let advanced = false
|
||||||
|
let file = false
|
||||||
let type = false
|
let type = false
|
||||||
let message = ''
|
let message = ''
|
||||||
let loading = false
|
let loading = false
|
||||||
@@ -31,6 +34,12 @@
|
|||||||
message = 'the note will expire and be destroyed after ' + fraction
|
message = 'the note will expire and be destroyed after ' + fraction
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$: note.meta.type = file ? 'file' : 'text'
|
||||||
|
|
||||||
|
$: if (!file) {
|
||||||
|
note.contents = ''
|
||||||
|
}
|
||||||
|
|
||||||
async function submit() {
|
async function submit() {
|
||||||
try {
|
try {
|
||||||
error = null
|
error = null
|
||||||
@@ -39,6 +48,7 @@
|
|||||||
const key = await getKeyFromString(password)
|
const key = await getKeyFromString(password)
|
||||||
const data: Note = {
|
const data: Note = {
|
||||||
contents: await encrypt(note.contents, key),
|
contents: await encrypt(note.contents, key),
|
||||||
|
meta: note.meta,
|
||||||
}
|
}
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
if (type) data.expiration = parseInt(note.expiration)
|
if (type) data.expiration = parseInt(note.expiration)
|
||||||
@@ -50,8 +60,12 @@
|
|||||||
password: password,
|
password: password,
|
||||||
id: response.id,
|
id: response.id,
|
||||||
}
|
}
|
||||||
} catch {
|
} catch (e) {
|
||||||
error = 'could not create note.'
|
if (e instanceof PayloadToLargeError) {
|
||||||
|
error = 'could not create not. note is to big'
|
||||||
|
} else {
|
||||||
|
error = 'could not create note. please try again.'
|
||||||
|
}
|
||||||
} finally {
|
} finally {
|
||||||
loading = false
|
loading = false
|
||||||
}
|
}
|
||||||
@@ -66,58 +80,88 @@
|
|||||||
<TextInput
|
<TextInput
|
||||||
type="text"
|
type="text"
|
||||||
readonly
|
readonly
|
||||||
value="{window.location.origin}/note/{result.id}/{result.password}"
|
label="share link"
|
||||||
|
value="{window.location.origin}/note/{result.id}#{result.password}"
|
||||||
copy
|
copy
|
||||||
|
data-testid="note-share-link"
|
||||||
/>
|
/>
|
||||||
<br />
|
<br />
|
||||||
<Button on:click={reset}>new</Button>
|
<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}
|
{: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}>
|
<form on:submit|preventDefault={submit}>
|
||||||
<fieldset disabled={loading}>
|
<fieldset disabled={loading}>
|
||||||
<TextArea label="note" bind:value={note.contents} placeholder="..." />
|
{#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">
|
<div class="bottom">
|
||||||
|
<Switch class="file" label="file" bind:value={file} />
|
||||||
<Switch label="advanced" bind:value={advanced} />
|
<Switch label="advanced" bind:value={advanced} />
|
||||||
<Button type="submit">create</Button>
|
<div class="grow" />
|
||||||
|
<div class="tr">
|
||||||
|
<small>max: <MaxSize /> </small>
|
||||||
|
<br />
|
||||||
|
<Button type="submit" data-testid="button-create">create</Button>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{#if error}
|
{#if error}
|
||||||
<div class="error-text">{error}</div>
|
<div class="error-text">{error}</div>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
||||||
<p><br />{message}</p>
|
<p>
|
||||||
|
|
||||||
<div class="advanced" class:hidden={!advanced}>
|
|
||||||
<br />
|
<br />
|
||||||
<div class="fields">
|
{#if loading}
|
||||||
<TextInput
|
loading...
|
||||||
type="number"
|
{:else}
|
||||||
label="views"
|
{message}
|
||||||
bind:value={note.views}
|
{/if}
|
||||||
disabled={type}
|
</p>
|
||||||
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>
|
|
||||||
|
|
||||||
<style>
|
{#if advanced}
|
||||||
.fields {
|
<div transition:blur={{ duration: 250 }}>
|
||||||
display: flex;
|
<br />
|
||||||
}
|
<div class="fields">
|
||||||
.spacer {
|
<TextInput
|
||||||
width: 3rem;
|
type="number"
|
||||||
}
|
label="views"
|
||||||
</style>
|
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>
|
</fieldset>
|
||||||
</form>
|
</form>
|
||||||
{/if}
|
{/if}
|
||||||
@@ -125,22 +169,27 @@
|
|||||||
<style>
|
<style>
|
||||||
.bottom {
|
.bottom {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: space-between;
|
|
||||||
align-items: flex-end;
|
align-items: flex-end;
|
||||||
margin-top: 0.5rem;
|
margin-top: 0.5rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.bottom :global(.file) {
|
||||||
|
margin-right: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.grow {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
.middle-switch {
|
.middle-switch {
|
||||||
margin: 0 1rem;
|
margin: 0 1rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.advanced {
|
.error-text {
|
||||||
max-height: 14em;
|
margin-top: 0.5rem;
|
||||||
overflow: hidden;
|
|
||||||
transition: var(--ui-anim);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.advanced.hidden {
|
.fields {
|
||||||
max-height: 0;
|
display: flex;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
37
client/src/lib/views/Footer.svelte
Normal file
37
client/src/lib/views/Footer.svelte
Normal 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>
|
@@ -8,9 +8,8 @@
|
|||||||
xmlns="http://www.w3.org/2000/svg"
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||||
xml:space="preserve"
|
xml:space="preserve"
|
||||||
xmlns:serif="http://www.serif.com/"
|
|
||||||
style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;"
|
style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2;"
|
||||||
><g
|
><g id="Logo"
|
||||||
><clipPath id="_clip1"><rect x="6.336" y="3.225" width="193.55" height="193.55" /></clipPath
|
><clipPath id="_clip1"><rect x="6.336" y="3.225" width="193.55" height="193.55" /></clipPath
|
||||||
><g clip-path="url(#_clip1)"
|
><g clip-path="url(#_clip1)"
|
||||||
><g
|
><g
|
||||||
@@ -42,10 +41,35 @@
|
|||||||
/></g
|
/></g
|
||||||
></g
|
></g
|
||||||
></g
|
></g
|
||||||
><text
|
><g
|
||||||
x="197.239px"
|
><path
|
||||||
y="127.131px"
|
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="font-family:'Sofia-Regular', 'Sofia';font-size:60.681px;">cryptgeon</text
|
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
|
></g
|
||||||
></svg
|
></svg
|
||||||
>
|
>
|
||||||
@@ -78,5 +102,6 @@
|
|||||||
width: 100%;
|
width: 100%;
|
||||||
max-width: 16rem;
|
max-width: 16rem;
|
||||||
transform: translateX(-1rem);
|
transform: translateX(-1rem);
|
||||||
|
fill: currentColor;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
@@ -1,46 +0,0 @@
|
|||||||
<script lang="ts">
|
|
||||||
import Header from '$lib/views/Header.svelte'
|
|
||||||
|
|
||||||
import '../app.css'
|
|
||||||
</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>
|
|
32
client/src/routes/__layout.svelte
Normal file
32
client/src/routes/__layout.svelte
Normal 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>
|
@@ -1,5 +1,8 @@
|
|||||||
<script context="module">
|
<script context="module">
|
||||||
import { browser, dev } from '$app/env'
|
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 hydrate = dev
|
||||||
export const router = browser
|
export const router = browser
|
||||||
export const prerender = true
|
export const prerender = true
|
||||||
@@ -13,43 +16,54 @@
|
|||||||
<h1>About</h1>
|
<h1>About</h1>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
<i>cryptgeon</i> is an secure, open source sharing note service inspired by
|
<i>cryptgeon</i> is a secure, open source sharing note / file service inspired by
|
||||||
<a href="https://privnote.com"><i>PrivNote</i></a>.
|
<a href="https://privnote.com"><i>PrivNote</i></a>.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p>
|
<AboutParagraph title="how does it work?">
|
||||||
<b>▶ how does it work?</b>
|
<span>
|
||||||
<br />
|
each note has a generated <code>id (256bit)</code> and <code>key 256(bit)</code>. The
|
||||||
each note has a 512bit generated <i>id</i> that is used to retrieve the note. data is stored in memory
|
<code>id</code>
|
||||||
and never persisted to disk.
|
is used to save & retrieve the note. the note is then encrypted with aes in gcm mode on the client
|
||||||
</p>
|
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>
|
||||||
|
|
||||||
<b>▶ Features</b>
|
<AboutParagraph title="features">
|
||||||
<ul>
|
<ul>
|
||||||
<li>server cannot decrypt contents due to client side encryption</li>
|
<li>server cannot decrypt contents due to client side encryption</li>
|
||||||
<li>view and time constrains</li>
|
<li>view and time constraints</li>
|
||||||
<li>in memory, no persistence</li>
|
<li>in memory, no persistence</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
</AboutParagraph>
|
||||||
|
|
||||||
<p>
|
<AboutParagraph title="tech stack">
|
||||||
<b>▶ tech stack</b>
|
<span>
|
||||||
<br />
|
the backend is written in rust and the frontend is svelte and typescript.
|
||||||
the backend is written in rust and the frontend is svelte and typescript.
|
<br />
|
||||||
<br />
|
you are welcomed to check & audit the
|
||||||
you are welcomed to check & audit the
|
<a href="https://github.com/cupcakearmy/cryptgeon" target="_blank" rel="noopener">
|
||||||
<a href="https://github.com/cupcakearmy/cryptgeon" target="_blank" rel="noopener">source code</a
|
source code
|
||||||
>.
|
</a>.
|
||||||
</p>
|
</span>
|
||||||
|
</AboutParagraph>
|
||||||
|
|
||||||
<p>
|
<AboutParagraph title="attribution">
|
||||||
<br />
|
<span>
|
||||||
<b>▶ attributions</b>
|
|
||||||
<br />
|
|
||||||
<small>
|
|
||||||
icons made by <a href="https://www.freepik.com" title="Freepik">freepik</a> from
|
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>
|
<a href="https://www.flaticon.com/" title="Flaticon">www.flaticon.com</a>
|
||||||
</small>
|
</span>
|
||||||
</p>
|
</AboutParagraph>
|
||||||
|
|
||||||
|
<AboutParagraph title="version">
|
||||||
|
<span>
|
||||||
|
{#if $status}
|
||||||
|
<code>v{$status.version}</code>
|
||||||
|
{/if}
|
||||||
|
</span>
|
||||||
|
</AboutParagraph>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
|
@@ -8,17 +8,15 @@
|
|||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import type { NotePublic } from '$lib/api'
|
import type { NotePublic } from '$lib/api'
|
||||||
import { info, get } from '$lib/api'
|
import { get, info } from '$lib/api'
|
||||||
import { decrypt, getKeyFromString } from '$lib/crypto'
|
import { decrypt, getKeyFromString } from '$lib/crypto'
|
||||||
import Button from '$lib/ui/Button.svelte'
|
import Button from '$lib/ui/Button.svelte'
|
||||||
import TextInput from '$lib/ui/TextInput.svelte'
|
import ShowNote from '$lib/ui/ShowNote.svelte'
|
||||||
import copy from 'copy-to-clipboard'
|
|
||||||
|
|
||||||
import { onMount } from 'svelte'
|
import { onMount } from 'svelte'
|
||||||
|
|
||||||
export let id: string
|
export let id: string
|
||||||
export let password: string
|
|
||||||
|
|
||||||
|
let password: string
|
||||||
let note: NotePublic | null = null
|
let note: NotePublic | null = null
|
||||||
let exists = false
|
let exists = false
|
||||||
|
|
||||||
@@ -29,6 +27,7 @@
|
|||||||
try {
|
try {
|
||||||
loading = true
|
loading = true
|
||||||
error = null
|
error = null
|
||||||
|
password = window.location.hash.slice(1)
|
||||||
await info(id)
|
await info(id)
|
||||||
exists = true
|
exists = true
|
||||||
} catch {
|
} catch {
|
||||||
@@ -41,50 +40,42 @@
|
|||||||
async function show() {
|
async function show() {
|
||||||
try {
|
try {
|
||||||
error = false
|
error = false
|
||||||
|
loading = true
|
||||||
const data = note || (await get(id)) // Don't get the content twice on wrong password.
|
const data = note || (await get(id)) // Don't get the content twice on wrong password.
|
||||||
const key = await getKeyFromString(password)
|
const key = await getKeyFromString(password)
|
||||||
data.contents = await decrypt(data.contents, key)
|
data.contents = await decrypt(data.contents, key)
|
||||||
note = data
|
note = data
|
||||||
} catch {
|
} catch {
|
||||||
error = true
|
error = true
|
||||||
|
} finally {
|
||||||
|
loading = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
{#if !loading}
|
{#if !loading}
|
||||||
{#if !exists}
|
{#if !exists}
|
||||||
<p class="error-text">note was not found or was already deleted.</p>
|
<p class="error-text" data-testid="note-not-found">
|
||||||
|
note was not found or was already deleted.
|
||||||
|
</p>
|
||||||
{:else if note && !error}
|
{:else if note && !error}
|
||||||
<p class="error-text">you will not get the chance to see the note again.</p>
|
<ShowNote {note} />
|
||||||
<div class="note">
|
|
||||||
{note.contents}
|
|
||||||
</div>
|
|
||||||
<br />
|
|
||||||
<Button on:click={() => copy(note.contents)}>copy to clipboard</Button>
|
|
||||||
{:else}
|
{:else}
|
||||||
<form on:submit|preventDefault={show}>
|
<form on:submit|preventDefault={show}>
|
||||||
<p>click below to show and delete the note if the counter has reached it's limit</p>
|
<fieldset>
|
||||||
<Button type="submit">show note</Button>
|
<p>click below to show and delete the note if the counter has reached it's limit</p>
|
||||||
{#if error}
|
<Button type="submit" data-testid="button-show">show note</Button>
|
||||||
<br />
|
{#if error}
|
||||||
<p class="error-text">
|
|
||||||
wrong password. could not decipher. probably a broken link. note was destroyed.
|
|
||||||
<br />
|
<br />
|
||||||
</p>
|
<p class="error-text">
|
||||||
{/if}
|
wrong password. could not decipher. probably a broken link. note was destroyed.
|
||||||
|
<br />
|
||||||
|
</p>
|
||||||
|
{/if}
|
||||||
|
</fieldset>
|
||||||
</form>
|
</form>
|
||||||
{/if}
|
{/if}
|
||||||
{/if}
|
{/if}
|
||||||
|
{#if loading}
|
||||||
<style>
|
<p>loading...</p>
|
||||||
.note {
|
{/if}
|
||||||
width: 100%;
|
|
||||||
margin: 0;
|
|
||||||
padding: 0;
|
|
||||||
border: 2px solid var(--ui-bg-1);
|
|
||||||
outline: none;
|
|
||||||
padding: 0.5rem;
|
|
||||||
white-space: pre;
|
|
||||||
overflow: auto;
|
|
||||||
}
|
|
||||||
</style>
|
|
1
client/static/icons/contrast-sharp.svg
Normal file
1
client/static/icons/contrast-sharp.svg
Normal 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 |
@@ -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',
|
|
||||||
},
|
|
||||||
}
|
|
13
client/svelte.config.js
Normal file
13
client/svelte.config.js
Normal 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',
|
||||||
|
},
|
||||||
|
}
|
5
cypress.json
Normal file
5
cypress.json
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"fixturesFolder": false,
|
||||||
|
"pluginsFile": false,
|
||||||
|
"supportFile": false
|
||||||
|
}
|
BIN
design/Logo.afdesign
(Stored with Git LFS)
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 |
@@ -6,11 +6,16 @@ version: '3.7'
|
|||||||
services:
|
services:
|
||||||
memcached:
|
memcached:
|
||||||
image: memcached:1-alpine
|
image: memcached:1-alpine
|
||||||
entrypoint: memcached -m 128
|
restart: unless-stopped
|
||||||
|
entrypoint: memcached -m 128M -I 4M
|
||||||
ports:
|
ports:
|
||||||
- 11211:11211
|
- 11211:11211
|
||||||
|
|
||||||
app:
|
app:
|
||||||
build: .
|
build: .
|
||||||
|
depends_on:
|
||||||
|
- memcached
|
||||||
|
environment:
|
||||||
|
SIZE_LIMIT: 4M
|
||||||
ports:
|
ports:
|
||||||
- 80:5000
|
- 80:5000
|
||||||
|
22
examples/nginx/docker-compose.yaml
Normal file
22
examples/nginx/docker-compose.yaml
Normal 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
|
13
examples/nginx/nginx-plain.conf
Normal file
13
examples/nginx/nginx-plain.conf
Normal 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;
|
||||||
|
}
|
||||||
|
}
|
29
examples/nginx/nginx-tls.conf
Normal file
29
examples/nginx/nginx-tls.conf
Normal 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;
|
||||||
|
}
|
||||||
|
}
|
1375
package-lock.json
generated
1375
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -2,10 +2,16 @@
|
|||||||
"scripts": {
|
"scripts": {
|
||||||
"dev:docker": "docker-compose up memcached",
|
"dev:docker": "docker-compose up memcached",
|
||||||
"dev:backend": "cargo watch -x 'run --bin cryptgeon'",
|
"dev:backend": "cargo watch -x 'run --bin cryptgeon'",
|
||||||
"dev:front": "npm --prefix client run dev",
|
"dev:front": "pnpm --prefix client run dev",
|
||||||
|
"dev:proxy": "node proxy.mjs",
|
||||||
"dev": "run-p dev:*"
|
"dev": "run-p dev:*"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"http-proxy": "^1.18.1",
|
||||||
"npm-run-all": "^4.1.5"
|
"npm-run-all": "^4.1.5"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"file-saver": "^2.0.5",
|
||||||
|
"pretty-bytes": "^5.6.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
504
pnpm-lock.yaml
generated
Normal file
504
pnpm-lock.yaml
generated
Normal file
@@ -0,0 +1,504 @@
|
|||||||
|
lockfileVersion: 5.3
|
||||||
|
|
||||||
|
specifiers:
|
||||||
|
file-saver: ^2.0.5
|
||||||
|
http-proxy: ^1.18.1
|
||||||
|
npm-run-all: ^4.1.5
|
||||||
|
pretty-bytes: ^5.6.0
|
||||||
|
|
||||||
|
dependencies:
|
||||||
|
file-saver: 2.0.5
|
||||||
|
pretty-bytes: 5.6.0
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
/file-saver/2.0.5:
|
||||||
|
resolution: {integrity: sha512-P9bmyZ3h/PRG+Nzga+rbdI4OEpNDzAVyy74uVO9ATgzLK6VtAsYybF/+TOCvrc0MO793d6+42lLyZTw7/ArVzA==}
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/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
|
||||||
|
|
||||||
|
/pretty-bytes/5.6.0:
|
||||||
|
resolution: {integrity: sha512-FFw039TmrBqFK8ma/7OL3sDz/VytdtJr044/QUJtH0wK9lb9jLq9tJyIxUwtQJHwar2BqtiA4iCWSwo9JLkzFg==}
|
||||||
|
engines: {node: '>=6'}
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/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
|
19
proxy.mjs
Normal file
19
proxy.mjs
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
import http from 'http'
|
||||||
|
import httpProxy from 'http-proxy'
|
||||||
|
|
||||||
|
function start() {
|
||||||
|
try {
|
||||||
|
const proxy = httpProxy.createProxyServer({})
|
||||||
|
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)
|
||||||
|
|
||||||
|
server.on('error', () => start())
|
||||||
|
} catch (e) {
|
||||||
|
start()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
start()
|
@@ -1,23 +1,27 @@
|
|||||||
use actix_web::{middleware, web, App, HttpServer};
|
use actix_web::{middleware, web, App, HttpServer};
|
||||||
|
use dotenv::dotenv;
|
||||||
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate lazy_static;
|
extern crate lazy_static;
|
||||||
|
|
||||||
mod client;
|
mod client;
|
||||||
mod note;
|
mod note;
|
||||||
|
mod size;
|
||||||
mod store;
|
mod store;
|
||||||
|
|
||||||
#[actix_web::main]
|
#[actix_web::main]
|
||||||
async fn main() -> std::io::Result<()> {
|
async fn main() -> std::io::Result<()> {
|
||||||
HttpServer::new(|| {
|
dotenv().ok();
|
||||||
|
return HttpServer::new(|| {
|
||||||
App::new()
|
App::new()
|
||||||
.wrap(middleware::Compress::default())
|
.wrap(middleware::Compress::default())
|
||||||
.wrap(middleware::DefaultHeaders::default())
|
.wrap(middleware::DefaultHeaders::default())
|
||||||
|
.configure(size::init)
|
||||||
.configure(note::init)
|
.configure(note::init)
|
||||||
.configure(client::init)
|
.configure(client::init)
|
||||||
.default_service(web::resource("").route(web::get().to(client::fallback_fn)))
|
.default_service(web::resource("").route(web::get().to(client::fallback_fn)))
|
||||||
})
|
})
|
||||||
.bind("0.0.0.0:5000")?
|
.bind("0.0.0.0:5000")?
|
||||||
.run()
|
.run()
|
||||||
.await
|
.await;
|
||||||
}
|
}
|
||||||
|
@@ -4,9 +4,10 @@ use serde::{Deserialize, Serialize};
|
|||||||
|
|
||||||
#[derive(Serialize, Deserialize, Clone)]
|
#[derive(Serialize, Deserialize, Clone)]
|
||||||
pub struct Note {
|
pub struct Note {
|
||||||
|
pub meta: String,
|
||||||
pub contents: String,
|
pub contents: String,
|
||||||
pub views: Option<u8>,
|
pub views: Option<u8>,
|
||||||
pub expiration: Option<u64>,
|
pub expiration: Option<u32>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Clone)]
|
#[derive(Serialize, Deserialize, Clone)]
|
||||||
@@ -14,11 +15,12 @@ pub struct NoteInfo {}
|
|||||||
|
|
||||||
#[derive(Serialize, Deserialize, Clone)]
|
#[derive(Serialize, Deserialize, Clone)]
|
||||||
pub struct NotePublic {
|
pub struct NotePublic {
|
||||||
|
pub meta: String,
|
||||||
pub contents: String,
|
pub contents: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn generate_id() -> 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 = ring::rand::SystemRandom::new();
|
||||||
let _ = sr.fill(&mut id);
|
let _ = sr.fill(&mut id);
|
||||||
return bs62::encode_data(&id);
|
return bs62::encode_data(&id);
|
||||||
|
@@ -3,13 +3,14 @@ use serde::{Deserialize, Serialize};
|
|||||||
use std::time::SystemTime;
|
use std::time::SystemTime;
|
||||||
|
|
||||||
use crate::note::{generate_id, Note, NoteInfo, NotePublic};
|
use crate::note::{generate_id, Note, NoteInfo, NotePublic};
|
||||||
|
use crate::size::LIMIT;
|
||||||
use crate::store;
|
use crate::store;
|
||||||
|
|
||||||
fn now() -> u64 {
|
pub fn now() -> u32 {
|
||||||
SystemTime::now()
|
SystemTime::now()
|
||||||
.duration_since(SystemTime::UNIX_EPOCH)
|
.duration_since(SystemTime::UNIX_EPOCH)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.as_secs()
|
.as_secs() as u32
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize)]
|
#[derive(Serialize, Deserialize)]
|
||||||
@@ -17,7 +18,7 @@ struct NotePath {
|
|||||||
id: String,
|
id: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[get("/notes/{id}")]
|
#[get("/{id}")]
|
||||||
async fn one(path: web::Path<NotePath>) -> impl Responder {
|
async fn one(path: web::Path<NotePath>) -> impl Responder {
|
||||||
let p = path.into_inner();
|
let p = path.into_inner();
|
||||||
let note = store::get(&p.id);
|
let note = store::get(&p.id);
|
||||||
@@ -32,14 +33,11 @@ struct CreateResponse {
|
|||||||
id: String,
|
id: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[post("/notes")]
|
#[post("/")]
|
||||||
async fn create(note: web::Json<Note>) -> impl Responder {
|
async fn create(note: web::Json<Note>) -> impl Responder {
|
||||||
let mut n = note.into_inner();
|
let mut n = note.into_inner();
|
||||||
let id = generate_id();
|
let id = generate_id();
|
||||||
let bad_req = HttpResponse::BadRequest().finish();
|
let bad_req = HttpResponse::BadRequest().finish();
|
||||||
if n.contents.chars().count() > 8192 {
|
|
||||||
return bad_req;
|
|
||||||
}
|
|
||||||
if n.views == None && n.expiration == None {
|
if n.views == None && n.expiration == None {
|
||||||
return bad_req;
|
return bad_req;
|
||||||
}
|
}
|
||||||
@@ -56,7 +54,8 @@ async fn create(note: web::Json<Note>) -> impl Responder {
|
|||||||
if e > 360 {
|
if e > 360 {
|
||||||
return bad_req;
|
return bad_req;
|
||||||
}
|
}
|
||||||
n.expiration = Some(now() + (e * 60))
|
let expiration = now() + (e * 60);
|
||||||
|
n.expiration = Some(expiration);
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
@@ -64,7 +63,7 @@ async fn create(note: web::Json<Note>) -> impl Responder {
|
|||||||
return HttpResponse::Ok().json(CreateResponse { id: id });
|
return HttpResponse::Ok().json(CreateResponse { id: id });
|
||||||
}
|
}
|
||||||
|
|
||||||
#[delete("/notes/{id}")]
|
#[delete("/{id}")]
|
||||||
async fn delete(path: web::Path<NotePath>) -> impl Responder {
|
async fn delete(path: web::Path<NotePath>) -> impl Responder {
|
||||||
let p = path.into_inner();
|
let p = path.into_inner();
|
||||||
let note = store::get(&p.id);
|
let note = store::get(&p.id);
|
||||||
@@ -87,9 +86,11 @@ async fn delete(path: web::Path<NotePath>) -> impl Responder {
|
|||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let n = now();
|
||||||
match changed.expiration {
|
match changed.expiration {
|
||||||
Some(e) => {
|
Some(e) => {
|
||||||
if e > now() {
|
if e < n {
|
||||||
store::del(&p.id.clone());
|
store::del(&p.id.clone());
|
||||||
return HttpResponse::BadRequest().finish();
|
return HttpResponse::BadRequest().finish();
|
||||||
}
|
}
|
||||||
@@ -98,16 +99,39 @@ async fn delete(path: web::Path<NotePath>) -> impl Responder {
|
|||||||
}
|
}
|
||||||
return HttpResponse::Ok().json(NotePublic {
|
return HttpResponse::Ok().json(NotePublic {
|
||||||
contents: changed.contents,
|
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) {
|
pub fn init(cfg: &mut web::ServiceConfig) {
|
||||||
cfg.service(
|
cfg.service(
|
||||||
web::scope("/api")
|
web::scope("/api")
|
||||||
.service(create)
|
.service(
|
||||||
.service(delete)
|
web::scope("/notes")
|
||||||
.service(one),
|
.service(one)
|
||||||
|
.service(create)
|
||||||
|
.service(delete)
|
||||||
|
.service(status),
|
||||||
|
)
|
||||||
|
.service(status),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
20
src/size.rs
Normal file
20
src/size.rs
Normal 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);
|
||||||
|
}
|
@@ -1,5 +1,6 @@
|
|||||||
use memcache;
|
use memcache;
|
||||||
|
|
||||||
|
use crate::note::now;
|
||||||
use crate::note::Note;
|
use crate::note::Note;
|
||||||
|
|
||||||
lazy_static! {
|
lazy_static! {
|
||||||
@@ -12,7 +13,11 @@ lazy_static! {
|
|||||||
|
|
||||||
pub fn set(id: &String, note: &Note) {
|
pub fn set(id: &String, note: &Note) {
|
||||||
let serialized = serde_json::to_string(¬e.clone()).unwrap();
|
let serialized = serde_json::to_string(¬e.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> {
|
pub fn get(id: &String) -> Option<Note> {
|
||||||
|
Reference in New Issue
Block a user