restructuring (#56)
* restructuring * pin svelte kit version & parallel execution * update svelte kit * correct test result assets * add timeout * correct locale path * simplify crypto * fix for #58 * add verbosity flag * disable flaky test
8
.github/workflows/test.yaml
vendored
@ -23,14 +23,14 @@ jobs:
|
|||||||
- name: Prepare
|
- name: Prepare
|
||||||
run: |
|
run: |
|
||||||
pnpm install
|
pnpm install
|
||||||
pnpm run ci:prepare
|
pnpm run test:prepare
|
||||||
- name: Install Playwright
|
- name: Install Playwright
|
||||||
run: npx playwright install --with-deps
|
run: npx playwright install --with-deps
|
||||||
- name: Run your tests
|
- name: Run your tests
|
||||||
run: pnpm run test
|
run: pnpm run test:run
|
||||||
- name: Upload test results
|
- name: Upload test results
|
||||||
if: always()
|
if: always()
|
||||||
uses: actions/upload-artifact@v2
|
uses: actions/upload-artifact@v2
|
||||||
with:
|
with:
|
||||||
name: playwright-report
|
name: test-results
|
||||||
path: playwright-report
|
path: test-results
|
||||||
|
2
.vscode/settings.json
vendored
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"cSpell.words": ["ciphertext", "cryptgeon"],
|
"cSpell.words": ["ciphertext", "cryptgeon"],
|
||||||
"i18n-ally.localesPaths": ["frontend/locales"],
|
"i18n-ally.localesPaths": ["packages/frontend/locales"],
|
||||||
"i18n-ally.enabledFrameworks": ["svelte"],
|
"i18n-ally.enabledFrameworks": ["svelte"],
|
||||||
"i18n-ally.keystyle": "nested"
|
"i18n-ally.keystyle": "nested"
|
||||||
}
|
}
|
||||||
|
10
CHANGELOG.md
@ -5,6 +5,16 @@ 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).
|
||||||
|
|
||||||
|
## [2.0.3] - 2022-10-07
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- Flag for verbosity.
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- #58 Fixed bug in the max views frontend form.
|
||||||
|
|
||||||
## [2.0.2] - 2022-07-20
|
## [2.0.2] - 2022-07-20
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
FROM node:16-alpine as client
|
FROM node:16-alpine as client
|
||||||
WORKDIR /tmp
|
WORKDIR /tmp
|
||||||
RUN npm install -g pnpm@7
|
RUN npm install -g pnpm@7
|
||||||
COPY ./frontend ./
|
COPY ./packages/frontend ./
|
||||||
RUN pnpm install
|
RUN pnpm install
|
||||||
RUN pnpm exec svelte-kit sync
|
RUN pnpm exec svelte-kit sync
|
||||||
RUN pnpm run build
|
RUN pnpm run build
|
||||||
@ -12,9 +12,9 @@ RUN pnpm run build
|
|||||||
FROM rust:1.61-alpine as backend
|
FROM rust:1.61-alpine as backend
|
||||||
WORKDIR /tmp
|
WORKDIR /tmp
|
||||||
RUN apk add libc-dev openssl-dev alpine-sdk
|
RUN apk add libc-dev openssl-dev alpine-sdk
|
||||||
COPY ./backend/Cargo.* ./
|
COPY ./packages/backend/Cargo.* ./
|
||||||
RUN cargo fetch
|
RUN cargo fetch
|
||||||
COPY ./backend ./
|
COPY ./packages/backend ./
|
||||||
RUN cargo build --release
|
RUN cargo build --release
|
||||||
|
|
||||||
|
|
||||||
|
@ -59,6 +59,7 @@ of the notes even if it tried to.
|
|||||||
| `ALLOW_ADVANCED` | `true` | Allow custom configuration. If set to `false` all notes will be one view only. |
|
| `ALLOW_ADVANCED` | `true` | Allow custom configuration. If set to `false` all notes will be one view only. |
|
||||||
| `THEME_IMAGE` | `""` | Custom image for replacing the logo. Must be publicly reachable |
|
| `THEME_IMAGE` | `""` | Custom image for replacing the logo. Must be publicly reachable |
|
||||||
| `THEME_TEXT` | `""` | Custom text for replacing the description below the logo |
|
| `THEME_TEXT` | `""` | Custom text for replacing the description below the logo |
|
||||||
|
| `VERBOSITY` | `warn` | Verbosity level for the backend. [Possible values](https://docs.rs/env_logger/latest/env_logger/#enabling-logging) are: `error`, `warn`, `info`, `debug`, `trace` |
|
||||||
|
|
||||||
## Deployment
|
## Deployment
|
||||||
|
|
||||||
@ -146,9 +147,9 @@ You can see the app under [localhost:1234](http://localhost:1234).
|
|||||||
Tests are end to end tests written with Playwright.
|
Tests are end to end tests written with Playwright.
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
pnpm run ci:prepare
|
pnpm run test:prepare
|
||||||
docker compose up redis -d
|
docker compose up redis -d
|
||||||
pnpm run ci:server
|
pnpm run test:server
|
||||||
|
|
||||||
# In another terminal.
|
# In another terminal.
|
||||||
# Use the test or test:local script. The local version only runs in one browser for quicker development.
|
# Use the test or test:local script. The local version only runs in one browser for quicker development.
|
||||||
|
@ -47,15 +47,15 @@ _加密鸽_ 是一个受 [_PrivNote_](https://privnote.com)项目启发的安全
|
|||||||
|
|
||||||
## 环境变量
|
## 环境变量
|
||||||
|
|
||||||
| 变量名称 | 默认值 | 描述 |
|
| 变量名称 | 默认值 | 描述 |
|
||||||
| ----------------- | ---------------- | --------------------------------------------------------------------------------- |
|
| ----------------- | ---------------- | --------------------------------------------------------------------------------- |
|
||||||
| `REDIS` | `redis://redis/` | Redis 连接 URL。 |
|
| `REDIS` | `redis://redis/` | Redis 连接 URL。 |
|
||||||
| `SIZE_LIMIT` | `1 KiB` | 最大请求体(body)限制。有关支持的数值请查看 [字节单位](https://docs.rs/byte-unit/) |
|
| `SIZE_LIMIT` | `1 KiB` | 最大请求体(body)限制。有关支持的数值请查看 [字节单位](https://docs.rs/byte-unit/) |
|
||||||
| `MAX_VIEWS` | `100` | 密信最多查看次数限制 |
|
| `MAX_VIEWS` | `100` | 密信最多查看次数限制 |
|
||||||
| ` MAX_EXPIRATION` | `360` | 密信最长过期时间限制(分钟) |
|
| ` MAX_EXPIRATION` | `360` | 密信最长过期时间限制(分钟) |
|
||||||
| `ALLOW_ADVANCED` | `true` | 是否允许自定义设置,该项如果设为`false`,则不会显示自定义设置模块 |
|
| `ALLOW_ADVANCED` | `true` | 是否允许自定义设置,该项如果设为`false`,则不会显示自定义设置模块 |
|
||||||
| `THEME_IMAGE` | `""` | 自定义Logo图片,你在这里填写的的图片链接必须是可以公开访问的。 |
|
| `THEME_IMAGE` | `""` | 自定义 Logo 图片,你在这里填写的的图片链接必须是可以公开访问的。 |
|
||||||
| `THEME_TEXT` | `""` | 自定义在Logo下方的文本。 |
|
| `THEME_TEXT` | `""` | 自定义在 Logo 下方的文本。 |
|
||||||
|
|
||||||
## 部署
|
## 部署
|
||||||
|
|
||||||
@ -148,7 +148,7 @@ cargo install cargo-watch
|
|||||||
|
|
||||||
确保你的 Docker 正在运行
|
确保你的 Docker 正在运行
|
||||||
|
|
||||||
> 如果你用的是 `macOS` 的话你可能需要关闭AirPlay接收功能因为该功能需要占用5000端口...)
|
> 如果你用的是 `macOS` 的话你可能需要关闭 AirPlay 接收功能因为该功能需要占用 5000 端口...)
|
||||||
> https://developer.apple.com/forums/thread/682332
|
> https://developer.apple.com/forums/thread/682332
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
@ -165,12 +165,12 @@ pnpm run dev
|
|||||||
|
|
||||||
## 测试
|
## 测试
|
||||||
|
|
||||||
这些测试是用Playwright实现的一些端到端测试用例。
|
这些测试是用 Playwright 实现的一些端到端测试用例。
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
pnpm run ci:prepare
|
pnpm run test:prepare
|
||||||
docker compose up redis -d
|
docker compose up redis -d
|
||||||
pnpm run ci:server
|
pnpm run test:server
|
||||||
|
|
||||||
# 在另一个终端中:
|
# 在另一个终端中:
|
||||||
# 使用test或者test:local script。为了更快的开发,本地版本只会在一个浏览器中运行。
|
# 使用test或者test:local script。为了更快的开发,本地版本只会在一个浏览器中运行。
|
||||||
|
@ -10,10 +10,11 @@ services:
|
|||||||
- 6379:6379
|
- 6379:6379
|
||||||
|
|
||||||
app:
|
app:
|
||||||
build: .
|
# build: .
|
||||||
|
image: cupcakearmy/cryptgeon
|
||||||
depends_on:
|
depends_on:
|
||||||
- redis
|
- redis
|
||||||
environment:
|
environment:
|
||||||
SIZE_LIMIT: 128 MiB
|
SIZE_LIMIT: 10 MiB
|
||||||
ports:
|
ports:
|
||||||
- 1234:5000
|
- 1234:5000
|
||||||
|
1615
frontend/pnpm-lock.yaml
generated
15
package.json
@ -1,20 +1,17 @@
|
|||||||
{
|
{
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev:docker": "docker-compose up redis",
|
"dev:docker": "docker-compose up redis",
|
||||||
"dev:backend": "cd backend && cargo watch -x 'run --bin cryptgeon'",
|
"dev:packages": "pnpm --parallel run dev",
|
||||||
"dev:front": "pnpm --prefix frontend run dev",
|
|
||||||
"dev:proxy": "node proxy.mjs",
|
"dev:proxy": "node proxy.mjs",
|
||||||
"dev": "run-p dev:*",
|
"dev": "run-p dev:*",
|
||||||
"test": "playwright test --project chrome firefox safari",
|
"test:run": "playwright test --project chrome firefox safari",
|
||||||
"test:local": "playwright test --project local",
|
"test:local": "playwright test --project local",
|
||||||
"ci:server": "cd backend && SIZE_LIMIT=10MiB LISTEN_ADDR=0.0.0.0:1234 cargo run",
|
"test:server": "pnpm --parallel run test:server",
|
||||||
"ci:prepare": "run-p ci:prepare:*",
|
"test:prepare": "pnpm --parallel run test:prepare"
|
||||||
"ci:prepare:backend": "cd backend && cargo build",
|
|
||||||
"ci:prepare:front": "pnpm --prefix frontend install && pnpm --prefix frontend run build"
|
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@playwright/test": "^1.23.4",
|
"@playwright/test": "^1.25.1",
|
||||||
"@types/node": "16",
|
"@types/node": "^16.11.57",
|
||||||
"http-proxy": "^1.18.1",
|
"http-proxy": "^1.18.1",
|
||||||
"npm-run-all": "^4.1.5"
|
"npm-run-all": "^4.1.5"
|
||||||
}
|
}
|
||||||
|
2
backend/Cargo.lock → packages/backend/Cargo.lock
generated
@ -424,7 +424,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cryptgeon"
|
name = "cryptgeon"
|
||||||
version = "2.0.2"
|
version = "2.0.3"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"actix-files",
|
"actix-files",
|
||||||
"actix-web",
|
"actix-web",
|
@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "cryptgeon"
|
name = "cryptgeon"
|
||||||
version = "2.0.2"
|
version = "2.0.3"
|
||||||
authors = ["cupcakearmy <hi@nicco.io>"]
|
authors = ["cupcakearmy <hi@nicco.io>"]
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|
10
packages/backend/package.json
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
{
|
||||||
|
"name": "backend",
|
||||||
|
"private": true,
|
||||||
|
"scripts": {
|
||||||
|
"dev": "cargo watch -x 'run --bin cryptgeon'",
|
||||||
|
"build": "cargo build --release",
|
||||||
|
"test:server": "SIZE_LIMIT=10MiB LISTEN_ADDR=0.0.0.0:1234 cargo run",
|
||||||
|
"test:prepare": "cargo build"
|
||||||
|
}
|
||||||
|
}
|
@ -9,6 +9,7 @@ lazy_static! {
|
|||||||
std::env::var("FRONTEND_PATH").unwrap_or("../frontend/build".to_string());
|
std::env::var("FRONTEND_PATH").unwrap_or("../frontend/build".to_string());
|
||||||
pub static ref LISTEN_ADDR: String =
|
pub static ref LISTEN_ADDR: String =
|
||||||
std::env::var("LISTEN_ADDR").unwrap_or("0.0.0.0:5000".to_string());
|
std::env::var("LISTEN_ADDR").unwrap_or("0.0.0.0:5000".to_string());
|
||||||
|
pub static ref VERBOSITY: String = std::env::var("VERBOSITY").unwrap_or("warn".to_string());
|
||||||
}
|
}
|
||||||
|
|
||||||
// CONFIG
|
// CONFIG
|
@ -18,10 +18,11 @@ mod store;
|
|||||||
#[actix_web::main]
|
#[actix_web::main]
|
||||||
async fn main() -> std::io::Result<()> {
|
async fn main() -> std::io::Result<()> {
|
||||||
dotenv().ok();
|
dotenv().ok();
|
||||||
env_logger::init_from_env(env_logger::Env::new().default_filter_or("warning"));
|
env_logger::init_from_env(env_logger::Env::new().default_filter_or(config::VERBOSITY.as_str()));
|
||||||
|
|
||||||
return HttpServer::new(|| {
|
return HttpServer::new(|| {
|
||||||
App::new()
|
App::new()
|
||||||
.wrap(Logger::new("%a \"%r\" %s %b %T"))
|
.wrap(Logger::new("\"%r\" %s %b %T"))
|
||||||
.wrap(middleware::Compress::default())
|
.wrap(middleware::Compress::default())
|
||||||
.wrap(middleware::DefaultHeaders::default())
|
.wrap(middleware::DefaultHeaders::default())
|
||||||
.configure(size::init)
|
.configure(size::init)
|
@ -7,5 +7,6 @@ pub fn init(cfg: &mut web::ServiceConfig) {
|
|||||||
let plain = web::PayloadConfig::default()
|
let plain = web::PayloadConfig::default()
|
||||||
.limit(*config::LIMIT)
|
.limit(*config::LIMIT)
|
||||||
.mimetype(mime::STAR_STAR);
|
.mimetype(mime::STAR_STAR);
|
||||||
|
// cfg.app_data(plain);
|
||||||
cfg.app_data(json).app_data(plain);
|
cfg.app_data(json).app_data(plain);
|
||||||
}
|
}
|
@ -1,8 +1,8 @@
|
|||||||
├─ MIT: 12
|
├─ MIT: 13
|
||||||
|
├─ ISC: 2
|
||||||
├─ BSD-3-Clause: 1
|
├─ BSD-3-Clause: 1
|
||||||
├─ (MPL-2.0 OR Apache-2.0): 1
|
├─ (MPL-2.0 OR Apache-2.0): 1
|
||||||
├─ BSD-2-Clause: 1
|
├─ BSD-2-Clause: 1
|
||||||
├─ ISC: 1
|
|
||||||
├─ 0BSD: 1
|
├─ 0BSD: 1
|
||||||
└─ Apache-2.0: 1
|
└─ Apache-2.0: 1
|
||||||
|
|
|
@ -6,13 +6,14 @@
|
|||||||
"preview": "vite preview --port 3000",
|
"preview": "vite preview --port 3000",
|
||||||
"check": "svelte-check --tsconfig tsconfig.json",
|
"check": "svelte-check --tsconfig tsconfig.json",
|
||||||
"licenses": "license-checker --summary > licenses.csv",
|
"licenses": "license-checker --summary > licenses.csv",
|
||||||
"locale:download": "node scripts/locale.js"
|
"locale:download": "node scripts/locale.js",
|
||||||
|
"test:prepare": "pnpm run build"
|
||||||
},
|
},
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@lokalise/node-api": "^7.3.1",
|
"@lokalise/node-api": "^7.3.1",
|
||||||
"@sveltejs/adapter-static": "^1.0.0-next.38",
|
"@sveltejs/adapter-static": "1.0.0-next.42",
|
||||||
"@sveltejs/kit": "^1.0.0-next.384",
|
"@sveltejs/kit": "1.0.0-next.480",
|
||||||
"@types/dompurify": "^2.3.3",
|
"@types/dompurify": "^2.3.3",
|
||||||
"@types/file-saver": "^2.0.5",
|
"@types/file-saver": "^2.0.5",
|
||||||
"@zerodevx/svelte-toast": "^0.7.2",
|
"@zerodevx/svelte-toast": "^0.7.2",
|
@ -35,6 +35,31 @@ export class ArrayBufferUtils {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export class Keys {
|
||||||
|
public static async generateKey(size: 128 | 192 | 256 = 256): Promise<CryptoKey> {
|
||||||
|
const key = await window.crypto.subtle.generateKey(
|
||||||
|
{
|
||||||
|
name: 'AES-GCM',
|
||||||
|
length: size,
|
||||||
|
},
|
||||||
|
true,
|
||||||
|
['encrypt', 'decrypt']
|
||||||
|
)
|
||||||
|
return key
|
||||||
|
}
|
||||||
|
|
||||||
|
public static async export(key: CryptoKey): Promise<string> {
|
||||||
|
return Hex.encode(await window.crypto.subtle.exportKey('raw', key))
|
||||||
|
}
|
||||||
|
|
||||||
|
public static async import(key: string): Promise<CryptoKey> {
|
||||||
|
return window.crypto.subtle.importKey('raw', Hex.decode(key), { name: 'AES-GCM' }, true, [
|
||||||
|
'encrypt',
|
||||||
|
'decrypt',
|
||||||
|
])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export class Crypto {
|
export class Crypto {
|
||||||
private static ALG = 'AES-GCM'
|
private static ALG = 'AES-GCM'
|
||||||
private static DELIMITER = ':::'
|
private static DELIMITER = ':::'
|
||||||
@ -43,55 +68,22 @@ export class Crypto {
|
|||||||
return window.crypto.getRandomValues(new Uint8Array(size))
|
return window.crypto.getRandomValues(new Uint8Array(size))
|
||||||
}
|
}
|
||||||
|
|
||||||
public static getKeyFromString(password: string) {
|
|
||||||
return window.crypto.subtle.importKey(
|
|
||||||
'raw',
|
|
||||||
new TextEncoder().encode(password),
|
|
||||||
'PBKDF2',
|
|
||||||
false,
|
|
||||||
['deriveBits', 'deriveKey']
|
|
||||||
)
|
|
||||||
}
|
|
||||||
public static async getDerivedForKey(key: CryptoKey, salt: ArrayBuffer) {
|
|
||||||
const iterations = 100_000
|
|
||||||
return window.crypto.subtle.deriveKey(
|
|
||||||
{
|
|
||||||
name: 'PBKDF2',
|
|
||||||
salt,
|
|
||||||
iterations,
|
|
||||||
hash: 'SHA-512',
|
|
||||||
},
|
|
||||||
key,
|
|
||||||
{ name: this.ALG, length: 256 },
|
|
||||||
true,
|
|
||||||
['encrypt', 'decrypt']
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
public static async encrypt(plaintext: ArrayBuffer, key: CryptoKey): Promise<string> {
|
public static async encrypt(plaintext: ArrayBuffer, key: CryptoKey): Promise<string> {
|
||||||
const salt = this.getRandomBytes(16)
|
const iv = this.getRandomBytes(12) // AES-GCM needs a 96bit IV
|
||||||
const derived = await this.getDerivedForKey(key, salt)
|
|
||||||
const iv = this.getRandomBytes(16)
|
|
||||||
const encrypted: ArrayBuffer = await window.crypto.subtle.encrypt(
|
const encrypted: ArrayBuffer = await window.crypto.subtle.encrypt(
|
||||||
{ name: this.ALG, iv },
|
{ name: this.ALG, iv },
|
||||||
derived,
|
key,
|
||||||
plaintext
|
plaintext
|
||||||
)
|
)
|
||||||
const data = [
|
const data = [Hex.encode(iv), await ArrayBufferUtils.toString(encrypted)].join(this.DELIMITER)
|
||||||
Hex.encode(salt),
|
|
||||||
Hex.encode(iv),
|
|
||||||
await ArrayBufferUtils.toString(encrypted),
|
|
||||||
].join(this.DELIMITER)
|
|
||||||
return data
|
return data
|
||||||
}
|
}
|
||||||
|
|
||||||
public static async decrypt(ciphertext: string, key: CryptoKey): Promise<ArrayBuffer> {
|
public static async decrypt(ciphertext: string, key: CryptoKey): Promise<ArrayBuffer> {
|
||||||
const splitted = ciphertext.split(this.DELIMITER)
|
const splitted = ciphertext.split(this.DELIMITER)
|
||||||
const salt = Hex.decode(splitted[0])
|
const iv = Hex.decode(splitted[0])
|
||||||
const iv = Hex.decode(splitted[1])
|
const encrypted = await ArrayBufferUtils.fromString(splitted[1])
|
||||||
const encrypted = await ArrayBufferUtils.fromString(splitted[2])
|
const plaintext = await window.crypto.subtle.decrypt({ name: this.ALG, iv }, key, encrypted)
|
||||||
const derived = await this.getDerivedForKey(key, salt)
|
|
||||||
const plaintext = await window.crypto.subtle.decrypt({ name: this.ALG, iv }, derived, encrypted)
|
|
||||||
return plaintext
|
return plaintext
|
||||||
}
|
}
|
||||||
}
|
}
|
Before Width: | Height: | Size: 287 B After Width: | Height: | Size: 287 B |
Before Width: | Height: | Size: 325 B After Width: | Height: | Size: 325 B |
Before Width: | Height: | Size: 736 B After Width: | Height: | Size: 736 B |
Before Width: | Height: | Size: 483 B After Width: | Height: | Size: 483 B |
Before Width: | Height: | Size: 732 B After Width: | Height: | Size: 732 B |
@ -19,7 +19,7 @@
|
|||||||
disabled={timeExpiration}
|
disabled={timeExpiration}
|
||||||
max={$status?.max_views}
|
max={$status?.max_views}
|
||||||
validate={(v) =>
|
validate={(v) =>
|
||||||
($status && v < $status?.max_views) ||
|
($status && v <= $status?.max_views) ||
|
||||||
$t('home.errors.max', { values: { n: $status?.max_views ?? 0 } })}
|
$t('home.errors.max', { values: { n: $status?.max_views ?? 0 } })}
|
||||||
/>
|
/>
|
||||||
<div class="middle-switch">
|
<div class="middle-switch">
|
Before Width: | Height: | Size: 784 B After Width: | Height: | Size: 784 B |
@ -24,7 +24,7 @@
|
|||||||
hidden = !hidden
|
hidden = !hidden
|
||||||
}
|
}
|
||||||
function randomFN() {
|
function randomFN() {
|
||||||
value = Hex.encode(Crypto.getRandomBytes(20))
|
value = Hex.encode(Crypto.getRandomBytes(32))
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
@ -5,7 +5,7 @@
|
|||||||
import { Adapters } from '$lib/adapters'
|
import { Adapters } from '$lib/adapters'
|
||||||
import type { FileDTO, Note } from '$lib/api'
|
import type { FileDTO, Note } from '$lib/api'
|
||||||
import { create, PayloadToLargeError } from '$lib/api'
|
import { create, PayloadToLargeError } from '$lib/api'
|
||||||
import { Crypto, Hex } from '$lib/crypto'
|
import { Keys } from '$lib/crypto'
|
||||||
import { status } from '$lib/stores/status'
|
import { status } from '$lib/stores/status'
|
||||||
import { notify } from '$lib/toast'
|
import { notify } from '$lib/toast'
|
||||||
import AdvancedParameters from '$lib/ui/AdvancedParameters.svelte'
|
import AdvancedParameters from '$lib/ui/AdvancedParameters.svelte'
|
||||||
@ -58,8 +58,8 @@
|
|||||||
try {
|
try {
|
||||||
loading = $t('common.encrypting')
|
loading = $t('common.encrypting')
|
||||||
|
|
||||||
const password = Hex.encode(Crypto.getRandomBytes(32))
|
const key = await Keys.generateKey()
|
||||||
const key = await Crypto.getKeyFromString(password)
|
const password = await Keys.export(key)
|
||||||
|
|
||||||
const data: Note = {
|
const data: Note = {
|
||||||
contents: '',
|
contents: '',
|
@ -1,14 +1,7 @@
|
|||||||
<script lang="ts" context="module">
|
|
||||||
import { getLocaleFromNavigator, init, waitLocale } from 'svelte-intl-precompile'
|
|
||||||
// @ts-ignore
|
|
||||||
import { registerAll } from '$locales'
|
|
||||||
registerAll()
|
|
||||||
init({ initialLocale: getLocaleFromNavigator() ?? undefined, fallbackLocale: 'en' })
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { SvelteToast } from '@zerodevx/svelte-toast'
|
import { SvelteToast } from '@zerodevx/svelte-toast'
|
||||||
import { onMount } from 'svelte'
|
import { onMount } from 'svelte'
|
||||||
|
import { waitLocale } from 'svelte-intl-precompile'
|
||||||
|
|
||||||
import '../app.css'
|
import '../app.css'
|
||||||
|
|
5
packages/frontend/src/routes/+layout.ts
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
import { getLocaleFromNavigator, init } from 'svelte-intl-precompile'
|
||||||
|
// @ts-ignore
|
||||||
|
import { registerAll } from '$locales'
|
||||||
|
registerAll()
|
||||||
|
init({ initialLocale: getLocaleFromNavigator() ?? undefined, fallbackLocale: 'en' })
|
@ -1,10 +1,6 @@
|
|||||||
<script context="module">
|
<script lang="ts">
|
||||||
import { browser, dev } from '$app/env'
|
|
||||||
import { status } from '$lib/stores/status'
|
import { status } from '$lib/stores/status'
|
||||||
import AboutParagraph from '$lib/ui/AboutParagraph.svelte'
|
import AboutParagraph from '$lib/ui/AboutParagraph.svelte'
|
||||||
|
|
||||||
export const hydrate = dev
|
|
||||||
export const router = browser
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<svelte:head>
|
<svelte:head>
|
@ -1,26 +1,18 @@
|
|||||||
<script context="module" lang="ts">
|
|
||||||
import type { Load } from '@sveltejs/kit'
|
|
||||||
|
|
||||||
export const load: Load = async ({ params }) => {
|
|
||||||
return {
|
|
||||||
props: params,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { onMount } from 'svelte'
|
import { onMount } from 'svelte'
|
||||||
import { t } from 'svelte-intl-precompile'
|
import { t } from 'svelte-intl-precompile'
|
||||||
|
|
||||||
import { Adapters } from '$lib/adapters'
|
import { Adapters } from '$lib/adapters'
|
||||||
import { get, info } from '$lib/api'
|
import { get, info } from '$lib/api'
|
||||||
import { Crypto } from '$lib/crypto'
|
import { Keys } from '$lib/crypto'
|
||||||
import Button from '$lib/ui/Button.svelte'
|
import Button from '$lib/ui/Button.svelte'
|
||||||
import Loader from '$lib/ui/Loader.svelte'
|
import Loader from '$lib/ui/Loader.svelte'
|
||||||
import ShowNote, { type DecryptedNote } from '$lib/ui/ShowNote.svelte'
|
import ShowNote, { type DecryptedNote } from '$lib/ui/ShowNote.svelte'
|
||||||
|
import type { PageData } from './$types'
|
||||||
|
|
||||||
export let id: string
|
export let data: PageData
|
||||||
|
|
||||||
|
let id = data.id
|
||||||
let password: string
|
let password: string
|
||||||
let note: DecryptedNote | null = null
|
let note: DecryptedNote | null = null
|
||||||
let exists = false
|
let exists = false
|
||||||
@ -51,7 +43,7 @@
|
|||||||
loading = $t('common.downloading')
|
loading = $t('common.downloading')
|
||||||
const data = await get(id)
|
const data = await get(id)
|
||||||
loading = $t('common.decrypting')
|
loading = $t('common.decrypting')
|
||||||
const key = await Crypto.getKeyFromString(password)
|
const key = await Keys.import(password)
|
||||||
switch (data.meta.type) {
|
switch (data.meta.type) {
|
||||||
case 'text':
|
case 'text':
|
||||||
note = {
|
note = {
|
5
packages/frontend/src/routes/note/[id]/+page.ts
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
import type { PageLoad } from './$types'
|
||||||
|
|
||||||
|
export const load: PageLoad = async ({ params }) => {
|
||||||
|
return params
|
||||||
|
}
|
Before Width: | Height: | Size: 6.1 KiB After Width: | Height: | Size: 6.1 KiB |
@ -3,6 +3,7 @@ import precompileIntl from 'svelte-intl-precompile/sveltekit-plugin'
|
|||||||
|
|
||||||
/** @type {import('vite').UserConfig} */
|
/** @type {import('vite').UserConfig} */
|
||||||
const config = {
|
const config = {
|
||||||
|
clearScreen: false,
|
||||||
server: {
|
server: {
|
||||||
port: 3000,
|
port: 3000,
|
||||||
},
|
},
|
@ -9,12 +9,15 @@ const config: PlaywrightTestConfig = {
|
|||||||
|
|
||||||
outputDir: './test-results',
|
outputDir: './test-results',
|
||||||
testDir: './test',
|
testDir: './test',
|
||||||
|
timeout: 60_000,
|
||||||
|
testIgnore: ['file/too-big.spec.ts'],
|
||||||
|
|
||||||
webServer: {
|
webServer: {
|
||||||
command: 'pnpm run ci:server',
|
command: 'pnpm run test:server',
|
||||||
port: 1234,
|
port: 1234,
|
||||||
reuseExistingServer: true,
|
reuseExistingServer: true,
|
||||||
},
|
},
|
||||||
|
|
||||||
projects: [
|
projects: [
|
||||||
{ name: 'chrome', use: { ...devices['Desktop Chrome'] } },
|
{ name: 'chrome', use: { ...devices['Desktop Chrome'] } },
|
||||||
{ name: 'firefox', use: { ...devices['Desktop Firefox'] } },
|
{ name: 'firefox', use: { ...devices['Desktop Firefox'] } },
|
||||||
|
1642
pnpm-lock.yaml
generated
2
pnpm-workspace.yaml
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
packages:
|
||||||
|
- "packages/**"
|
8
test/file/too-big.spec.ts
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
import { test } from '@playwright/test'
|
||||||
|
import { createNote } from '../utils'
|
||||||
|
import Files from './files'
|
||||||
|
|
||||||
|
test('to big zip', async ({ page }) => {
|
||||||
|
const files = [Files.Zip]
|
||||||
|
const link = await createNote(page, { files, error: 'note is to big' })
|
||||||
|
})
|