mirror of
https://github.com/cupcakearmy/cryptgeon.git
synced 2026-06-10 11:16:48 +00:00
Merge branch 'main' into main
This commit is contained in:
@@ -10,10 +10,10 @@ jobs:
|
||||
cli:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- uses: pnpm/action-setup@v2
|
||||
- uses: actions/setup-node@v3
|
||||
- uses: pnpm/action-setup@v6
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
cache: 'pnpm'
|
||||
node-version-file: '.nvmrc'
|
||||
@@ -31,14 +31,14 @@ jobs:
|
||||
docker:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: docker/setup-qemu-action@v2
|
||||
- uses: docker/setup-buildx-action@v2
|
||||
- uses: actions/checkout@v4
|
||||
- uses: docker/setup-qemu-action@v4
|
||||
- uses: docker/setup-buildx-action@v4
|
||||
with:
|
||||
install: true
|
||||
- name: Docker Labels
|
||||
id: meta
|
||||
uses: docker/metadata-action@v4
|
||||
uses: docker/metadata-action@v6
|
||||
with:
|
||||
images: cupcakearmy/cryptgeon
|
||||
tags: |
|
||||
@@ -46,12 +46,12 @@ jobs:
|
||||
type=semver,pattern={{major}}.{{minor}}
|
||||
type=semver,pattern={{major}}
|
||||
- name: Login to DockerHub
|
||||
uses: docker/login-action@v2
|
||||
uses: docker/login-action@v4
|
||||
with:
|
||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||
- name: Build and push
|
||||
uses: docker/build-push-action@v4
|
||||
uses: docker/build-push-action@v7
|
||||
with:
|
||||
platforms: linux/amd64,linux/arm64
|
||||
push: true
|
||||
|
||||
@@ -13,15 +13,15 @@ jobs:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
# Node
|
||||
- uses: pnpm/action-setup@v4
|
||||
- uses: pnpm/action-setup@v6
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
cache: 'pnpm'
|
||||
node-version-file: '.nvmrc'
|
||||
|
||||
# Docker
|
||||
- uses: docker/setup-qemu-action@v3
|
||||
- uses: docker/setup-buildx-action@v3
|
||||
- uses: docker/setup-qemu-action@v4
|
||||
- uses: docker/setup-buildx-action@v4
|
||||
with:
|
||||
install: true
|
||||
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
# Contributing
|
||||
|
||||
## Requirements
|
||||
|
||||
- [mise](https://mise.jdx.dev) — manages pnpm, rust, node (see `mise.toml`)
|
||||
- docker or [colima](https://github.com/abiosoft/colima) (for redis)
|
||||
|
||||
## Setup
|
||||
|
||||
```bash
|
||||
mise install
|
||||
pnpm install
|
||||
```
|
||||
|
||||
## Development
|
||||
|
||||
```bash
|
||||
pnpm run dev
|
||||
```
|
||||
|
||||
Make sure docker/colima is running. This starts redis, the rust backend, the web client, and the CLI. The app is at [localhost:3000](http://localhost:3000).
|
||||
|
||||
## Tests
|
||||
|
||||
End-to-end tests with Playwright.
|
||||
|
||||
```sh
|
||||
pnpm run test:prepare
|
||||
pnpm run test:local
|
||||
```
|
||||
|
||||
## Release
|
||||
|
||||
1. Update version across packages:
|
||||
|
||||
```sh
|
||||
./version.mjs <semver>
|
||||
```
|
||||
|
||||
2. Create and push the tag:
|
||||
|
||||
```sh
|
||||
git tag v<semver>
|
||||
git push --tags
|
||||
```
|
||||
|
||||
The CI workflow publishes the CLI to npm and the Docker image to Docker Hub automatically.
|
||||
+3
-3
@@ -1,5 +1,5 @@
|
||||
# FRONTEND
|
||||
FROM node:22-alpine as client
|
||||
FROM node:24-alpine AS client
|
||||
ENV PNPM_HOME="/pnpm"
|
||||
ENV PATH="$PNPM_HOME:$PATH"
|
||||
RUN corepack enable
|
||||
@@ -11,7 +11,7 @@ RUN pnpm run build
|
||||
|
||||
|
||||
# BACKEND
|
||||
FROM rust:1.85-alpine as backend
|
||||
FROM rust:1.95-alpine AS backend
|
||||
WORKDIR /tmp
|
||||
RUN apk add --no-cache libc-dev openssl-dev alpine-sdk
|
||||
COPY ./packages/backend ./
|
||||
@@ -19,7 +19,7 @@ RUN RUSTFLAGS="-Ctarget-feature=-crt-static" cargo build --release
|
||||
|
||||
|
||||
# RUNNER
|
||||
FROM alpine:3.19
|
||||
FROM alpine:3
|
||||
WORKDIR /app
|
||||
RUN apk add --no-cache curl libgcc
|
||||
COPY --from=backend /tmp/target/release/cryptgeon .
|
||||
|
||||
@@ -162,53 +162,9 @@ There is a [guide](https://mariushosting.com/how-to-install-cryptgeon-on-your-sy
|
||||
- Italian by [@nicfab](https://notes.nicfab.eu/it/posts/cryptgeon/)
|
||||
- English by [@nicfab](https://notes.nicfab.eu/en/posts/cryptgeon/)
|
||||
|
||||
## Development
|
||||
## Contributing
|
||||
|
||||
**Requirements**
|
||||
|
||||
- `pnpm`: `>=9`
|
||||
- `node`: `>=22`
|
||||
- `rust`: edition `2021`
|
||||
|
||||
**Install**
|
||||
|
||||
```bash
|
||||
pnpm install
|
||||
|
||||
# Also you need cargo watch if you don't already have it installed.
|
||||
# https://lib.rs/crates/cargo-watch
|
||||
cargo install cargo-watch
|
||||
```
|
||||
|
||||
**Run**
|
||||
|
||||
Make sure you have docker running.
|
||||
|
||||
```bash
|
||||
pnpm run dev
|
||||
```
|
||||
|
||||
Running `pnpm run dev` in the root folder will start the following things:
|
||||
|
||||
- redis docker container
|
||||
- rust backend
|
||||
- client
|
||||
- cli
|
||||
|
||||
You can see the app under [localhost:3000](http://localhost:3000).
|
||||
|
||||
> There is a Postman collection with some example requests [available in the repo](./Cryptgeon.postman_collection.json)
|
||||
|
||||
### Tests
|
||||
|
||||
Tests are end to end tests written with Playwright.
|
||||
|
||||
```sh
|
||||
pnpm run test:prepare
|
||||
|
||||
# Use the test or test:local script. The local version only runs in one browser for quicker development.
|
||||
pnpm run test:local
|
||||
```
|
||||
See [CONTRIBUTING.md](./CONTRIBUTING.md).
|
||||
|
||||
## Security
|
||||
|
||||
|
||||
+8
-52
@@ -43,7 +43,7 @@ Puedes revisar la documentación sobre el CLI en este [readme](./packages/cli/RE
|
||||
|
||||
- enviar texto o archivos
|
||||
- el servidor no puede desencriptar el contenido debido a que la encriptación se hace del lado del cliente
|
||||
- restriccion de vistas o de tiempo
|
||||
- restricción de vistas o de tiempo
|
||||
- en memoria, sin persistencia
|
||||
- compatibilidad obligatoria con el modo oscuro
|
||||
|
||||
@@ -66,7 +66,7 @@ se usa para guardar y recuperar la nota. Después la nota es encriptada con la <
|
||||
| `MAX_VIEWS` | `100` | Número máximo de vistas. |
|
||||
| `MAX_EXPIRATION` | `360` | Tiempo máximo de expiración en minutos. |
|
||||
| `ALLOW_ADVANCED` | `true` | Permitir configuración personalizada. Si se establece en `false` todas las notas serán de una sola vista. |
|
||||
| `ID_LENGTH` | `32` | Establece el tamaño en bytes de la `id` de la nota. Por defecto es de `32` bytes. Esto es util para reducir el tamaño del link. _Esta configuración no afecta el nivel de encriptación_. |
|
||||
| `ID_LENGTH` | `32` | Establece el tamaño en bytes de la `id` de la nota. Por defecto es de `32` bytes. Esto es útil para reducir el tamaño del link. _Esta configuración no afecta el nivel de encriptación_. |
|
||||
| `VERBOSITY` | `warn` | Nivel de verbosidad del backend. [Posibles valores](https://docs.rs/env_logger/latest/env_logger/#enabling-logging): `error`, `warn`, `info`, `debug`, `trace` |
|
||||
| `THEME_IMAGE` | `""` | Imagen personalizada para reemplazar el logo. Debe ser accesible públicamente. |
|
||||
| `THEME_TEXT` | `""` | Texto personalizado para reemplazar la descripción bajo el logo. |
|
||||
@@ -75,18 +75,18 @@ se usa para guardar y recuperar la nota. Después la nota es encriptada con la <
|
||||
|
||||
## Despliegue
|
||||
|
||||
> ℹ️ Se requiere `https` de lo contrario el navegador no soportará las funciones de encriptacón.
|
||||
> ℹ️ Se requiere `https` de lo contrario el navegador no soportará las funciones de encriptación.
|
||||
|
||||
> ℹ️ Hay un endpoint para verificar el estado, lo encontramos en `/api/health/`. Regresa un código 200 o 503.
|
||||
|
||||
### Docker
|
||||
|
||||
Docker es la manera más fácil. Aquí encontramos [la imágen oficial](https://hub.docker.com/r/cupcakearmy/cryptgeon).
|
||||
Docker es la manera más fácil. Aquí encontramos [la imagen oficial](https://hub.docker.com/r/cupcakearmy/cryptgeon).
|
||||
|
||||
```yaml
|
||||
# docker-compose.yml
|
||||
|
||||
version: '3.8'
|
||||
version: "3.8"
|
||||
|
||||
services:
|
||||
redis:
|
||||
@@ -141,57 +141,13 @@ Hay una [guía](https://mariushosting.com/how-to-install-cryptgeon-on-your-synol
|
||||
- En inglés, por [DB Tech](https://www.youtube.com/watch?v=S0jx7wpOfNM) [Previous Video](https://www.youtube.com/watch?v=JhpIatD06vE)
|
||||
- En alemán, por [ApfelCast](https://www.youtube.com/watch?v=84ZMbE9AkHg)
|
||||
|
||||
## Desarrollo
|
||||
## Contribuir
|
||||
|
||||
**Requisitos**
|
||||
|
||||
- `pnpm`: `>=6`
|
||||
- `node`: `>=18`
|
||||
- `rust`: edition `2021`
|
||||
|
||||
**Instalación**
|
||||
|
||||
```bash
|
||||
pnpm install
|
||||
|
||||
# También necesitas cargo-watch, si no lo tienes instalado.
|
||||
# https://lib.rs/crates/cargo-watch
|
||||
cargo install cargo-watch
|
||||
```
|
||||
|
||||
**Ejecutar**
|
||||
|
||||
Asegurate de que docker se esté ejecutando.
|
||||
|
||||
```bash
|
||||
pnpm run dev
|
||||
```
|
||||
|
||||
Ejecutando `pnpm run dev` en la carpeta raíz iniciará lo siguiente:
|
||||
|
||||
- redis docker container
|
||||
- rust backend
|
||||
- client
|
||||
- cli
|
||||
|
||||
Puedes ver la app en [localhost:3000](http://localhost:3000).
|
||||
|
||||
> Existe una colección de Postman con algunas peticiones de ejemplo [disponible en el repo](./Cryptgeon.postman_collection.json)
|
||||
|
||||
### Tests
|
||||
|
||||
Los tests son end-to-end tests escritos con Playwright.
|
||||
|
||||
```sh
|
||||
pnpm run test:prepare
|
||||
|
||||
# Usa el script test o test:local. La versión local solo corre en el navegador para acelerar el desarrollo.
|
||||
pnpm run test:local
|
||||
```
|
||||
Ver [CONTRIBUTING.md](./CONTRIBUTING.md).
|
||||
|
||||
## Seguridad
|
||||
|
||||
Por favor dirigite a la sección de seguridad [aquí](./SECURITY.md).
|
||||
Por favor dirígete a la sección de seguridad [aquí](./SECURITY.md).
|
||||
|
||||
---
|
||||
|
||||
|
||||
+13
-58
@@ -47,15 +47,15 @@ _加密鸽_ 是一个受 [_PrivNote_](https://privnote.com)项目启发的安全
|
||||
|
||||
## 环境变量
|
||||
|
||||
| 变量名称 | 默认值 | 描述 |
|
||||
| ----------------- | ---------------- | --------------------------------------------------------------------------------- |
|
||||
| `REDIS` | `redis://redis/` | Redis 连接 URL。 |
|
||||
| `SIZE_LIMIT` | `1 KiB` | 最大请求体(body)限制。有关支持的数值请查看 [字节单位](https://docs.rs/byte-unit/) |
|
||||
| `MAX_VIEWS` | `100` | 密信最多查看次数限制 |
|
||||
| ` MAX_EXPIRATION` | `360` | 密信最长过期时间限制(分钟) |
|
||||
| `ALLOW_ADVANCED` | `true` | 是否允许自定义设置,该项如果设为`false`,则不会显示自定义设置模块 |
|
||||
| `THEME_IMAGE` | `""` | 自定义 Logo 图片,你在这里填写的的图片链接必须是可以公开访问的。 |
|
||||
| `THEME_TEXT` | `""` | 自定义在 Logo 下方的文本。 |
|
||||
| 变量名称 | 默认值 | 描述 |
|
||||
| ---------------- | ---------------- | --------------------------------------------------------------------------------- |
|
||||
| `REDIS` | `redis://redis/` | Redis 连接 URL。 |
|
||||
| `SIZE_LIMIT` | `1 KiB` | 最大请求体(body)限制。有关支持的数值请查看 [字节单位](https://docs.rs/byte-unit/) |
|
||||
| `MAX_VIEWS` | `100` | 密信最多查看次数限制 |
|
||||
| `MAX_EXPIRATION` | `360` | 密信最长过期时间限制(分钟) |
|
||||
| `ALLOW_ADVANCED` | `true` | 是否允许自定义设置,该项如果设为`false`,则不会显示自定义设置模块 |
|
||||
| `THEME_IMAGE` | `""` | 自定义 Logo 图片,你在这里填写的的图片链接必须是可以公开访问的。 |
|
||||
| `THEME_TEXT` | `""` | 自定义在 Logo 下方的文本。 |
|
||||
|
||||
## 部署
|
||||
|
||||
@@ -69,7 +69,7 @@ Docker 是最简单的部署方式。这里是[官方镜像的地址](https://hu
|
||||
|
||||
```yaml
|
||||
# docker-compose.yml
|
||||
version: '3.8'
|
||||
version: "3.8"
|
||||
|
||||
services:
|
||||
redis:
|
||||
@@ -107,7 +107,7 @@ services:
|
||||
- 域名 `example.org`
|
||||
|
||||
```yaml
|
||||
version: '3.8'
|
||||
version: "3.8"
|
||||
|
||||
networks:
|
||||
proxy:
|
||||
@@ -140,54 +140,9 @@ services:
|
||||
- traefik.http.routers.cryptgeon.tls.certresolver=le
|
||||
```
|
||||
|
||||
## 开发
|
||||
## 贡献
|
||||
|
||||
**环境要求**
|
||||
|
||||
- `pnpm`: `>=6`
|
||||
- `node`: `>=14`
|
||||
- `rust`: edition `2021`
|
||||
|
||||
**安装**
|
||||
|
||||
```bash
|
||||
pnpm install
|
||||
pnpm --prefix frontend install
|
||||
|
||||
# 你还需要安装CargoWatch.
|
||||
# https://lib.rs/crates/cargo-watch
|
||||
cargo install cargo-watch
|
||||
```
|
||||
|
||||
**运行**
|
||||
|
||||
确保你的 Docker 正在运行
|
||||
|
||||
```bash
|
||||
pnpm run dev
|
||||
```
|
||||
|
||||
在根目录执行 `pnpm run dev` 会开启下列服务:
|
||||
|
||||
- 一个 redis docker 容器
|
||||
- 无热重载的 rust 后端
|
||||
- 可热重载的客户端
|
||||
|
||||
你可以通过 3000 端口进入该应用,即 [localhost:3000](http://localhost:3000).
|
||||
|
||||
## 测试
|
||||
|
||||
这些测试是用 Playwright 实现的一些端到端测试用例。
|
||||
|
||||
```sh
|
||||
pnpm run test:prepare
|
||||
docker compose up redis -d
|
||||
pnpm run test:server
|
||||
|
||||
# 在另一个终端中:
|
||||
# 使用test或者test:local script。为了更快的开发,本地版本只会在一个浏览器中运行。
|
||||
pnpm run test:local
|
||||
```
|
||||
参见 [CONTRIBUTING.md](./CONTRIBUTING.md)。
|
||||
|
||||
###### Attributions
|
||||
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
[tools]
|
||||
pnpm = "11.5.0"
|
||||
rust = "1.95"
|
||||
watchexec = "latest"
|
||||
# Node loaded below from .nvmrc
|
||||
|
||||
[settings]
|
||||
idiomatic_version_file_enable_tools = ["node"]
|
||||
+5
-4
@@ -8,14 +8,15 @@
|
||||
"test": "playwright test --project=chrome --project=firefox --project=safari",
|
||||
"test:local": "playwright test --project=chrome",
|
||||
"test:server": "run-s docker:up",
|
||||
"test:prepare": "run-p build docker:build",
|
||||
"test:dl-browsers": "playwright install",
|
||||
"test:prepare": "run-p test:dl-browsers build docker:build",
|
||||
"build": "pnpm run --recursive --filter=!@cryptgeon/backend build"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@playwright/test": "^1.46.1",
|
||||
"@types/node": "^22.5.0",
|
||||
"@playwright/test": "^1.60.0",
|
||||
"@types/node": "^24.12.4",
|
||||
"npm-run-all": "^4.1.5",
|
||||
"shelljs": "^0.8.5"
|
||||
},
|
||||
"packageManager": "pnpm@10.3.0"
|
||||
"packageManager": "pnpm@11.5.0"
|
||||
}
|
||||
|
||||
Generated
+649
-422
File diff suppressed because it is too large
Load Diff
@@ -2,8 +2,8 @@
|
||||
name = "cryptgeon"
|
||||
version = "2.9.1"
|
||||
authors = ["cupcakearmy <hi@nicco.io>"]
|
||||
edition = "2021"
|
||||
rust-version = "1.85"
|
||||
edition = "2024"
|
||||
rust-version = "1.95"
|
||||
|
||||
[[bin]]
|
||||
name = "cryptgeon"
|
||||
@@ -11,12 +11,12 @@ path = "src/main.rs"
|
||||
|
||||
[dependencies]
|
||||
# Core
|
||||
axum = "0.7.5"
|
||||
serde = { version = "1.0.208", features = ["derive"] }
|
||||
tokio = { version = "1.39.3", features = ["full"] }
|
||||
tower = "0.5.0"
|
||||
tower-http = { version = "0.5.2", features = ["full"] }
|
||||
redis = { version = "0.25.2", features = ["tls-native-tls"] }
|
||||
axum = "0.8"
|
||||
serde = { version = "1", features = ["derive"] }
|
||||
tokio = { version = "1", features = ["full"] }
|
||||
tower = "0.5"
|
||||
tower-http = { version = "0.6", features = ["full"] }
|
||||
redis = { version = "1", features = ["tls-native-tls"] }
|
||||
|
||||
# Utility
|
||||
serde_json = "1"
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
"private": true,
|
||||
"name": "@cryptgeon/backend",
|
||||
"scripts": {
|
||||
"dev": "cargo watch -x 'run --bin cryptgeon'",
|
||||
"dev": "watchexec -r -e rs cargo run",
|
||||
"build": "cargo build --release",
|
||||
"test:server": "SIZE_LIMIT=10MiB LISTEN_ADDR=0.0.0.0:3000 cargo run",
|
||||
"test:prepare": "cargo build"
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
use std::{collections::HashMap, sync::Arc};
|
||||
|
||||
use axum::{
|
||||
Router, ServiceExt,
|
||||
extract::{DefaultBodyLimit, Request},
|
||||
routing::{delete, get, post},
|
||||
Router, ServiceExt,
|
||||
};
|
||||
use dotenv::dotenv;
|
||||
use lock::SharedState;
|
||||
@@ -41,14 +41,14 @@ async fn main() {
|
||||
|
||||
let notes_routes = Router::new()
|
||||
.route("/", post(note::create))
|
||||
.route("/:id", delete(note::delete))
|
||||
.route("/:id", get(note::preview));
|
||||
.route("/{id}", delete(note::delete))
|
||||
.route("/{id}", get(note::preview));
|
||||
let health_routes = Router::new().route("/live", get(health::report_health));
|
||||
let status_routes = Router::new().route("/status", get(status::get_status));
|
||||
let api_routes = Router::new()
|
||||
.nest("/notes", notes_routes)
|
||||
.nest("/", health_routes)
|
||||
.nest("/", status_routes);
|
||||
.merge(health_routes)
|
||||
.merge(status_routes);
|
||||
|
||||
let index = format!("{}{}", config::FRONTEND_PATH.to_string(), "/index.html");
|
||||
let serve_dir =
|
||||
|
||||
@@ -30,16 +30,16 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@commander-js/extra-typings": "^12.1.0",
|
||||
"@types/inquirer": "^9.0.7",
|
||||
"@types/inquirer": "^9.0.9",
|
||||
"@types/mime": "^4.0.0",
|
||||
"@types/node": "^20.11.24",
|
||||
"@types/node": "^20.19.41",
|
||||
"commander": "^12.1.0",
|
||||
"inquirer": "^9.2.15",
|
||||
"mime": "^4.0.1",
|
||||
"inquirer": "^9.3.8",
|
||||
"mime": "^4.1.0",
|
||||
"occulto": "^2.0.6",
|
||||
"pretty-bytes": "^6.1.1",
|
||||
"tsup": "^8.2.4",
|
||||
"typescript": "^5.3.3"
|
||||
"tsup": "^8.5.1",
|
||||
"typescript": "^5.9.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
"advanced": "avanzato",
|
||||
"create": "crea",
|
||||
"loading": "carica",
|
||||
"mode": "modalita",
|
||||
"mode": "modalità",
|
||||
"views": "{n, plural, =0 {viste} =1 {1 vista} other {# viste}}",
|
||||
"minutes": "{n, plural, =0 {minuti} =1 {1 minuto} other {# minuti}}",
|
||||
"max": "max",
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
"uploading": "アップロード中",
|
||||
"downloading": "ダウンロード中",
|
||||
"qr_code": "QRコード",
|
||||
"password": "暗号"
|
||||
"password": "パスワード"
|
||||
},
|
||||
"home": {
|
||||
"intro": "<i>完全に暗号化された</i> 、安全なメモやファイルをワンクリックで簡単に送信できます。メモを作成してリンクを共有するだけです。",
|
||||
@@ -46,7 +46,7 @@
|
||||
},
|
||||
"explanation": "カウンターが上限に達した場合、ノートの表示と削除を行うには、以下をクリックします。",
|
||||
"show_note": "メモを表示",
|
||||
"warning_will_not_see_again": "あなた <b>できません</b> このノートをもう一度見る",
|
||||
"warning_will_not_see_again": "このノートを再度表示することは<b>できません</b>",
|
||||
"download_all": "すべてダウンロード",
|
||||
"links_found": "メモ内にあるリンク:"
|
||||
},
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
"errors": {
|
||||
"note_to_big": "nie można utworzyć notatki. notatka jest za duża",
|
||||
"note_error": "nie można utworzyć notatki. spróbuj ponownie.",
|
||||
"max": "maks .: {n}",
|
||||
"max": "maks.: {n}",
|
||||
"empty_content": "notatka jest pusta."
|
||||
},
|
||||
"messages": {
|
||||
|
||||
@@ -1,58 +1,58 @@
|
||||
{
|
||||
"common": {
|
||||
"note": "заметка",
|
||||
"file": "файл",
|
||||
"advanced": "расширенные",
|
||||
"create": "создать",
|
||||
"loading": "загрузка",
|
||||
"mode": "режим",
|
||||
"views": "{n, plural, =0 {просмотры} =1 {1 просмотр} other {# просмотры}}",
|
||||
"minutes": "{n, plural, =0 {минут} =1 {1 минута} other {# минуты}}",
|
||||
"max": "макс",
|
||||
"share_link": "поделиться ссылкой",
|
||||
"copy_clipboard": "скопировать в буфер обмена",
|
||||
"copied_to_clipboard": "скопировано в буфер обмена",
|
||||
"encrypting": "шифрование",
|
||||
"decrypting": "расшифровка",
|
||||
"uploading": "загрузка",
|
||||
"downloading": "скачивание",
|
||||
"qr_code": "qr код",
|
||||
"password": "пароль"
|
||||
},
|
||||
"home": {
|
||||
"intro": "Легко отправляйте <i>полностью зашифрованные</i> защищенные заметки или файлы одним щелчком мыши. Просто создайте заметку и поделитесь ссылкой.",
|
||||
"explanation": "заметка истечет и будет уничтожена после {type}.",
|
||||
"new_note": "новая заметка",
|
||||
"new_note_notice": "<b>доступность:</b><br />сохранение заметки не гарантируется, поскольку все хранится в оперативной памяти; если она заполнится, самые старые заметки будут удалены.<br />( вероятно, все будет в порядке, просто будьте осторожны.)",
|
||||
"errors": {
|
||||
"note_to_big": "нельзя создать новую заметку. заметка слишком большая",
|
||||
"note_error": "нельзя создать новую заметку. пожалйста попробуйте позднее.",
|
||||
"max": "макс: {n}",
|
||||
"empty_content": "пустая заметка."
|
||||
},
|
||||
"messages": {
|
||||
"note_created": "заметка создана."
|
||||
},
|
||||
"advanced": {
|
||||
"explanation": "По умолчанию для каждой заметки используется безопасно сгенерированный пароль. Однако вы также можете выбрать свой собственный пароль, который не включен в ссылку.",
|
||||
"custom_password": "пользовательский пароль"
|
||||
}
|
||||
},
|
||||
"show": {
|
||||
"errors": {
|
||||
"not_found": "заметка не найдена или была удалена.",
|
||||
"decryption_failed": "неправильный пароль. не смог расшифровать. возможно ссылка битая. записка уничтожена.",
|
||||
"unsupported_type": "неподдерживаемый тип заметки."
|
||||
},
|
||||
"explanation": "щелкните ниже, чтобы показать и удалить примечание, если счетчик достиг предела",
|
||||
"show_note": "показать заметку",
|
||||
"warning_will_not_see_again": "вы <b>не сможете</b> больше просмотреть заметку.",
|
||||
"download_all": "скачать всё",
|
||||
"links_found": "ссылки внутри заметки:"
|
||||
},
|
||||
"file_upload": {
|
||||
"selected_files": "Выбранные файлы",
|
||||
"no_files_selected": "Файлы не выбраны",
|
||||
"clear": "Сброс"
|
||||
}
|
||||
"common": {
|
||||
"note": "заметка",
|
||||
"file": "файл",
|
||||
"advanced": "расширенные",
|
||||
"create": "создать",
|
||||
"loading": "загрузка",
|
||||
"mode": "режим",
|
||||
"views": "{n, plural, =0 {просмотры} =1 {1 просмотр} other {# просмотры}}",
|
||||
"minutes": "{n, plural, =0 {минут} =1 {1 минута} other {# минуты}}",
|
||||
"max": "макс",
|
||||
"share_link": "поделиться ссылкой",
|
||||
"copy_clipboard": "скопировать в буфер обмена",
|
||||
"copied_to_clipboard": "скопировано в буфер обмена",
|
||||
"encrypting": "шифрование",
|
||||
"decrypting": "расшифровка",
|
||||
"uploading": "загрузка",
|
||||
"downloading": "скачивание",
|
||||
"qr_code": "qr код",
|
||||
"password": "пароль"
|
||||
},
|
||||
"home": {
|
||||
"intro": "Легко отправляйте <i>полностью зашифрованные</i> защищенные заметки или файлы одним щелчком мыши. Просто создайте заметку и поделитесь ссылкой.",
|
||||
"explanation": "заметка истечет и будет уничтожена после {type}.",
|
||||
"new_note": "новая заметка",
|
||||
"new_note_notice": "<b>доступность:</b><br />сохранение заметки не гарантируется, поскольку все хранится в оперативной памяти; если она заполнится, самые старые заметки будут удалены.<br />( вероятно, все будет в порядке, просто будьте осторожны.)",
|
||||
"errors": {
|
||||
"note_to_big": "нельзя создать новую заметку. заметка слишком большая",
|
||||
"note_error": "нельзя создать новую заметку. пожалуйста попробуйте позже.",
|
||||
"max": "макс: {n}",
|
||||
"empty_content": "пустая заметка."
|
||||
},
|
||||
"messages": {
|
||||
"note_created": "заметка создана."
|
||||
},
|
||||
"advanced": {
|
||||
"explanation": "По умолчанию для каждой заметки используется безопасно сгенерированный пароль. Однако вы также можете выбрать свой собственный пароль, который не включен в ссылку.",
|
||||
"custom_password": "пользовательский пароль"
|
||||
}
|
||||
},
|
||||
"show": {
|
||||
"errors": {
|
||||
"not_found": "заметка не найдена или была удалена.",
|
||||
"decryption_failed": "неправильный пароль. не смог расшифровать. возможно ссылка битая. заметка уничтожена.",
|
||||
"unsupported_type": "неподдерживаемый тип заметки."
|
||||
},
|
||||
"explanation": "щелкните ниже, чтобы показать и удалить заметку, если счетчик достиг предела",
|
||||
"show_note": "показать заметку",
|
||||
"warning_will_not_see_again": "вы <b>не сможете</b> больше просмотреть заметку.",
|
||||
"download_all": "скачать всё",
|
||||
"links_found": "ссылки внутри заметки:"
|
||||
},
|
||||
"file_upload": {
|
||||
"selected_files": "Выбранные файлы",
|
||||
"no_files_selected": "Файлы не выбраны",
|
||||
"clear": "Сброс"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,24 +14,24 @@
|
||||
"type": "module",
|
||||
"devDependencies": {
|
||||
"@lokalise/node-api": "^13.2.1",
|
||||
"@sveltejs/adapter-static": "^3.0.8",
|
||||
"@sveltejs/kit": "^2.17.3",
|
||||
"@sveltejs/vite-plugin-svelte": "^5.0.3",
|
||||
"@sveltejs/adapter-static": "^3.0.10",
|
||||
"@sveltejs/kit": "^2.61.1",
|
||||
"@sveltejs/vite-plugin-svelte": "^7.1.2",
|
||||
"@zerodevx/svelte-toast": "^0.9.6",
|
||||
"adm-zip": "^0.5.16",
|
||||
"dotenv": "^16.4.7",
|
||||
"svelte": "^5.20.5",
|
||||
"svelte-check": "^4.1.4",
|
||||
"adm-zip": "^0.5.17",
|
||||
"dotenv": "^17.4.2",
|
||||
"svelte": "^5.55.9",
|
||||
"svelte-check": "^4.4.8",
|
||||
"svelte-intl-precompile": "^0.12.3",
|
||||
"tslib": "^2.8.1",
|
||||
"typescript": "^5.7.3",
|
||||
"vite": "^6.2.0"
|
||||
"typescript": "^6.0.3",
|
||||
"vite": "^8.0.14"
|
||||
},
|
||||
"dependencies": {
|
||||
"@fontsource/fira-mono": "^5.1.1",
|
||||
"@fontsource/fira-mono": "^5.2.7",
|
||||
"cryptgeon": "workspace:*",
|
||||
"occulto": "^2.0.6",
|
||||
"pretty-bytes": "^6.1.1",
|
||||
"qrious": "^4.0.2"
|
||||
"pretty-bytes": "^7.1.0",
|
||||
"uqr": "^0.1.3"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
import { status } from '$lib/stores/status'
|
||||
import Button from '$lib/ui/Button.svelte'
|
||||
import TextInput from '$lib/ui/TextInput.svelte'
|
||||
import Canvas from './Canvas.svelte'
|
||||
import QR from './QR.svelte'
|
||||
|
||||
interface Props {
|
||||
result: NoteResult
|
||||
@@ -18,8 +18,11 @@
|
||||
|
||||
let { result }: Props = $props()
|
||||
|
||||
let url = $state(`${window.location.origin}/note/${result.id}`)
|
||||
if (result.password) url += `#${result.password}`
|
||||
let url = $derived.by(() => {
|
||||
let url = `${window.location.origin}/note/${result.id}`
|
||||
if (result.password) url += `#${result.password}`
|
||||
return url
|
||||
})
|
||||
|
||||
function reset() {
|
||||
window.location.reload()
|
||||
@@ -36,7 +39,7 @@
|
||||
/>
|
||||
|
||||
<div>
|
||||
<Canvas value={url} />
|
||||
<QR value={url} />
|
||||
</div>
|
||||
|
||||
{#if $status?.theme_new_note_notice}
|
||||
|
||||
+14
-15
@@ -1,9 +1,7 @@
|
||||
<script lang="ts">
|
||||
// @ts-ignore
|
||||
import QR from 'qrious'
|
||||
import { t } from 'svelte-intl-precompile'
|
||||
|
||||
import { getCSSVariable } from '$lib/utils'
|
||||
import { t } from 'svelte-intl-precompile'
|
||||
import { renderSVG } from 'uqr'
|
||||
|
||||
interface Props {
|
||||
value: string
|
||||
@@ -11,35 +9,36 @@
|
||||
|
||||
let { value }: Props = $props()
|
||||
|
||||
let canvas: HTMLCanvasElement | null = $state(null)
|
||||
let qr: string | null = $state(null)
|
||||
|
||||
$effect(() => {
|
||||
new QR({
|
||||
value,
|
||||
level: 'Q',
|
||||
size: 800,
|
||||
background: getCSSVariable('--ui-bg-0'),
|
||||
foreground: getCSSVariable('--ui-text-0'),
|
||||
element: canvas,
|
||||
qr = renderSVG(value, {
|
||||
ecc: 'Q',
|
||||
blackColor: getCSSVariable('--ui-bg-0'),
|
||||
whiteColor: getCSSVariable('--ui-text-0'),
|
||||
})
|
||||
})
|
||||
</script>
|
||||
|
||||
<small>{$t('common.qr_code')}</small>
|
||||
<div>
|
||||
<canvas bind:this={canvas}></canvas>
|
||||
{#if qr}
|
||||
{@html qr}
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
<style>
|
||||
div {
|
||||
padding: 0.5rem;
|
||||
padding: 0.25rem;
|
||||
width: fit-content;
|
||||
border: 2px solid var(--ui-bg-1);
|
||||
background-color: var(--ui-bg-0);
|
||||
margin-top: 0.125rem;
|
||||
overflow: hidden;
|
||||
aspect-ratio: 1;
|
||||
}
|
||||
|
||||
canvas {
|
||||
div :global(svg) {
|
||||
width: 100%;
|
||||
height: auto;
|
||||
}
|
||||
@@ -32,6 +32,7 @@
|
||||
let files: FileDTO[] = $state([])
|
||||
|
||||
async function downloadFile(file: FileDTO) {
|
||||
// @ts-ignore
|
||||
const f = new File([file.contents], file.name, {
|
||||
type: file.type,
|
||||
})
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
...rest
|
||||
}: HTMLInputAttributes & Props = $props()
|
||||
|
||||
// svelte-ignore state_referenced_locally
|
||||
const initialType = $state(rest.type)
|
||||
const isPassword = initialType === 'password'
|
||||
let hidden = $state(true)
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
|
||||
let { data }: Props = $props()
|
||||
|
||||
let id = data.id
|
||||
let id = $derived(data.id)
|
||||
let password: string | null = $state<string | null>(null)
|
||||
let note: DecryptedNote | null = $state(null)
|
||||
let exists = $state(false)
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
"extends": "./.svelte-kit/tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"strict": true,
|
||||
"allowSyntheticDefaultImports": true
|
||||
}
|
||||
"allowSyntheticDefaultImports": true,
|
||||
"skipLibCheck": true,
|
||||
},
|
||||
}
|
||||
|
||||
Generated
+1912
-1551
File diff suppressed because it is too large
Load Diff
@@ -1,2 +1,7 @@
|
||||
packages:
|
||||
- "packages/**"
|
||||
|
||||
allowBuilds:
|
||||
esbuild: true
|
||||
|
||||
minimumReleaseAge: 10080 # One week
|
||||
|
||||
Reference in New Issue
Block a user