mirror of
https://github.com/cupcakearmy/cryptgeon.git
synced 2025-09-06 17:30:39 +00:00
Compare commits
15 Commits
a5809c216c
...
v2.3.0
Author | SHA1 | Date | |
---|---|---|---|
dc1c03d912 | |||
2a75acae3f | |||
815ac4e8ba | |||
7c85c1e621 | |||
a323d48c41 | |||
2bff6a37db | |||
f8223dfc62 | |||
063d073c27 | |||
ac32b97383 | |||
9c9c23d958 | |||
92893a5b2d | |||
ac68f4a540 | |||
83b2fa5372 | |||
3c86f3f3be | |||
80e64ad207 |
9
.github/workflows/release.yml
vendored
9
.github/workflows/release.yml
vendored
@@ -12,15 +12,22 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v3
|
||||||
|
|
||||||
|
- uses: pnpm/action-setup@v2
|
||||||
- uses: actions/setup-node@v3
|
- uses: actions/setup-node@v3
|
||||||
with:
|
with:
|
||||||
|
cache: 'pnpm'
|
||||||
node-version-file: '.nvmrc'
|
node-version-file: '.nvmrc'
|
||||||
- uses: pnpm/action-setup@v2
|
registry-url: 'https://registry.npmjs.org'
|
||||||
|
|
||||||
- run: |
|
- run: |
|
||||||
pnpm install --frozen-lockfile
|
pnpm install --frozen-lockfile
|
||||||
pnpm run build
|
pnpm run build
|
||||||
|
|
||||||
|
- run: npm publish
|
||||||
|
working-directory: ./packages/cli
|
||||||
|
env:
|
||||||
|
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
|
||||||
|
|
||||||
docker:
|
docker:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
|
3
.github/workflows/test.yaml
vendored
3
.github/workflows/test.yaml
vendored
@@ -13,10 +13,11 @@ jobs:
|
|||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v3
|
||||||
|
|
||||||
# Node
|
# Node
|
||||||
|
- uses: pnpm/action-setup@v2
|
||||||
- uses: actions/setup-node@v3
|
- uses: actions/setup-node@v3
|
||||||
with:
|
with:
|
||||||
|
cache: 'pnpm'
|
||||||
node-version-file: '.nvmrc'
|
node-version-file: '.nvmrc'
|
||||||
- uses: pnpm/action-setup@v2
|
|
||||||
|
|
||||||
# Docker
|
# Docker
|
||||||
- uses: docker/setup-qemu-action@v2
|
- uses: docker/setup-qemu-action@v2
|
||||||
|
11
CHANGELOG.md
11
CHANGELOG.md
@@ -5,18 +5,17 @@ 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.3.0] - 2023-05-XX
|
## [2.3.0] - 2023-05-30
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
|
||||||
- New CLI 🎉
|
- New CLI 🎉.
|
||||||
- Russian language
|
- Russian language.
|
||||||
|
- Option for reducing note id size (`ID_LENGTH`).
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
|
|
||||||
- Moved to monorepo
|
- Moved to monorepo.
|
||||||
|
|
||||||
## [2.2.0] - 2023-01-14
|
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
|
|
||||||
|
@@ -12,6 +12,7 @@ FROM rust:1.69-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 ./packages/backend/Cargo.* ./
|
COPY ./packages/backend/Cargo.* ./
|
||||||
|
ENV CARGO_REGISTRIES_CRATES_IO_PROTOCOL=sparse
|
||||||
RUN cargo fetch
|
RUN cargo fetch
|
||||||
COPY ./packages/backend ./
|
COPY ./packages/backend ./
|
||||||
RUN cargo build --release
|
RUN cargo build --release
|
||||||
|
30
README.md
30
README.md
@@ -18,7 +18,8 @@ EN | [简体中文](README_zh-CN.md)
|
|||||||
|
|
||||||
## About?
|
## About?
|
||||||
|
|
||||||
_cryptgeon_ is a secure, open source sharing note or file service inspired by [_PrivNote_](https://privnote.com)
|
_cryptgeon_ is a secure, open source sharing note or file service inspired by [_PrivNote_](https://privnote.com).
|
||||||
|
It includes a server, a web page and a CLI client.
|
||||||
|
|
||||||
> 🌍 If you want to translate the project feel free to reach out to me.
|
> 🌍 If you want to translate the project feel free to reach out to me.
|
||||||
>
|
>
|
||||||
@@ -26,10 +27,21 @@ _cryptgeon_ is a secure, open source sharing note or file service inspired by [_
|
|||||||
|
|
||||||
## Live Service / Demo
|
## Live Service / Demo
|
||||||
|
|
||||||
|
### Web
|
||||||
|
|
||||||
Check out the live service / demo and see for yourself [cryptgeon.org](https://cryptgeon.org)
|
Check out the live service / demo and see for yourself [cryptgeon.org](https://cryptgeon.org)
|
||||||
|
|
||||||
|
### CLI
|
||||||
|
|
||||||
|
```
|
||||||
|
npx cryptgeon send text "This is a secret note"
|
||||||
|
```
|
||||||
|
|
||||||
|
For more documentation about the CLI see the [readme](./packages/cli/README.md).
|
||||||
|
|
||||||
## Features
|
## Features
|
||||||
|
|
||||||
|
- send text or files
|
||||||
- server cannot decrypt contents due to client side encryption
|
- server cannot decrypt contents due to client side encryption
|
||||||
- view or time constraints
|
- view or time constraints
|
||||||
- in memory, no persistence
|
- in memory, no persistence
|
||||||
@@ -57,6 +69,7 @@ of the notes even if it tried to.
|
|||||||
| `MAX_VIEWS` | `100` | Maximal number of views. |
|
| `MAX_VIEWS` | `100` | Maximal number of views. |
|
||||||
| `MAX_EXPIRATION` | `360` | Maximal expiration in minutes. |
|
| `MAX_EXPIRATION` | `360` | Maximal expiration in minutes. |
|
||||||
| `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. |
|
||||||
|
| `ID_LENGTH` | `32` | Set the size of the note `id` in bytes. By default this is `32` bytes. This is useful for reducing link size. _This setting does not affect encryption strength_. |
|
||||||
| `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` |
|
| `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` |
|
||||||
| `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 |
|
||||||
@@ -121,14 +134,13 @@ There is a [guide](https://mariushosting.com/how-to-install-cryptgeon-on-your-sy
|
|||||||
**Requirements**
|
**Requirements**
|
||||||
|
|
||||||
- `pnpm`: `>=6`
|
- `pnpm`: `>=6`
|
||||||
- `node`: `>=16`
|
- `node`: `>=18`
|
||||||
- `rust`: edition `2021`
|
- `rust`: edition `2021`
|
||||||
|
|
||||||
**Install**
|
**Install**
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
pnpm install
|
pnpm install
|
||||||
pnpm --prefix frontend install
|
|
||||||
|
|
||||||
# Also you need cargo watch if you don't already have it installed.
|
# Also you need cargo watch if you don't already have it installed.
|
||||||
# https://lib.rs/crates/cargo-watch
|
# https://lib.rs/crates/cargo-watch
|
||||||
@@ -148,19 +160,19 @@ Running `pnpm run dev` in the root folder will start the following things:
|
|||||||
- redis docker container
|
- redis docker container
|
||||||
- rust backend
|
- rust backend
|
||||||
- client
|
- client
|
||||||
|
- cli
|
||||||
|
|
||||||
You can see the app under [localhost:1234](http://localhost:1234).
|
You can see the app under [localhost:1234](http://localhost:1234).
|
||||||
|
|
||||||
## Tests
|
> 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.
|
Tests are end to end tests written with Playwright.
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
pnpm run test:prepare
|
pnpm run test:prepare
|
||||||
docker compose up redis -d
|
|
||||||
pnpm run test:server
|
|
||||||
|
|
||||||
# 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.
|
||||||
pnpm run test:local
|
pnpm run test:local
|
||||||
```
|
```
|
||||||
@@ -169,7 +181,9 @@ pnpm run test:local
|
|||||||
|
|
||||||
Please refer to the security section [here](./SECURITY.md).
|
Please refer to the security section [here](./SECURITY.md).
|
||||||
|
|
||||||
###### Attributions
|
---
|
||||||
|
|
||||||
|
_Attributions_
|
||||||
|
|
||||||
- Test data:
|
- Test data:
|
||||||
- Text for tests [Nietzsche Ipsum](https://nietzsche-ipsum.com/)
|
- Text for tests [Nietzsche Ipsum](https://nietzsche-ipsum.com/)
|
||||||
|
@@ -17,7 +17,7 @@
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"settings": {
|
"settings": {
|
||||||
"i18n-ally.localesPaths": ["packages/frontend/locales"],
|
"i18n-ally.localesPaths": ["locales"],
|
||||||
"cSpell.words": ["cryptgeon"]
|
"cSpell.words": ["cryptgeon"]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"packageManager": "pnpm@8.4.0",
|
"packageManager": "pnpm@8.5.1",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev:docker": "docker-compose -f docker-compose.dev.yaml up redis",
|
"dev:docker": "docker-compose -f docker-compose.dev.yaml up redis",
|
||||||
"dev:packages": "pnpm --parallel run dev",
|
"dev:packages": "pnpm --parallel run dev",
|
||||||
|
2
packages/backend/Cargo.lock
generated
2
packages/backend/Cargo.lock
generated
@@ -439,7 +439,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cryptgeon"
|
name = "cryptgeon"
|
||||||
version = "2.3.0-beta.4"
|
version = "2.3.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"actix-files",
|
"actix-files",
|
||||||
"actix-web",
|
"actix-web",
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "cryptgeon"
|
name = "cryptgeon"
|
||||||
version = "2.3.0-beta.4"
|
version = "2.3.0"
|
||||||
authors = ["cupcakearmy <hi@nicco.io>"]
|
authors = ["cupcakearmy <hi@nicco.io>"]
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|
||||||
@@ -8,11 +8,6 @@ edition = "2021"
|
|||||||
name = "cryptgeon"
|
name = "cryptgeon"
|
||||||
path = "src/main.rs"
|
path = "src/main.rs"
|
||||||
|
|
||||||
[registries.crates-io]
|
|
||||||
protocol = "sparse"
|
|
||||||
|
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
actix-web = "4"
|
actix-web = "4"
|
||||||
actix-files = "0.6"
|
actix-files = "0.6"
|
||||||
|
@@ -30,6 +30,10 @@ lazy_static! {
|
|||||||
.unwrap_or("true".to_string())
|
.unwrap_or("true".to_string())
|
||||||
.parse()
|
.parse()
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
pub static ref ID_LENGTH: u32 = std::env::var("ID_LENGTH")
|
||||||
|
.unwrap_or("32".to_string())
|
||||||
|
.parse()
|
||||||
|
.unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
// THEME
|
// THEME
|
||||||
|
@@ -2,6 +2,8 @@ use bs62;
|
|||||||
use ring::rand::SecureRandom;
|
use ring::rand::SecureRandom;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
use crate::config;
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Clone)]
|
#[derive(Serialize, Deserialize, Clone)]
|
||||||
pub struct Note {
|
pub struct Note {
|
||||||
pub meta: String,
|
pub meta: String,
|
||||||
@@ -22,8 +24,13 @@ pub struct NotePublic {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn generate_id() -> String {
|
pub fn generate_id() -> String {
|
||||||
let mut id: [u8; 32] = [0; 32];
|
let mut result = "".to_owned();
|
||||||
|
let mut id: [u8; 1] = [0; 1];
|
||||||
let sr = ring::rand::SystemRandom::new();
|
let sr = ring::rand::SystemRandom::new();
|
||||||
let _ = sr.fill(&mut id);
|
|
||||||
return bs62::encode_data(&id);
|
for _ in 0..*config::ID_LENGTH {
|
||||||
|
let _ = sr.fill(&mut id);
|
||||||
|
result.push_str(&bs62::encode_data(&id));
|
||||||
|
}
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
54
packages/cli/README.md
Normal file
54
packages/cli/README.md
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
# Cryptgeon CLI
|
||||||
|
|
||||||
|
The CLI is a functionally identical way to interact with cryptgeon notes.
|
||||||
|
It supports text, files, expiration, password, etc.
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npx cryptgeon
|
||||||
|
|
||||||
|
# Or install globally
|
||||||
|
npm -g install cryptgeon
|
||||||
|
cryptgeon
|
||||||
|
```
|
||||||
|
|
||||||
|
## Examples
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Create simple note
|
||||||
|
cryptgeon send text "Foo bar"
|
||||||
|
|
||||||
|
# Send two files
|
||||||
|
cryptgeon send file my.pdf picture.png
|
||||||
|
|
||||||
|
# 3 views
|
||||||
|
cryptgeon send text "My message" --views 3
|
||||||
|
|
||||||
|
# 10 minutes
|
||||||
|
cryptgeon send text "My message" --minutes 10
|
||||||
|
|
||||||
|
# Custom password
|
||||||
|
cryptgeon send text "My message" --password "1337"
|
||||||
|
|
||||||
|
# Password from stdin
|
||||||
|
echo "1337" | cryptgeon send text "My message"
|
||||||
|
|
||||||
|
# Open a link
|
||||||
|
cryptgeon open https://cryptgeon.org/note/16gOIkxWjCxYNuXM8tCqMUzl...
|
||||||
|
```
|
||||||
|
|
||||||
|
## Options
|
||||||
|
|
||||||
|
### Custom server
|
||||||
|
|
||||||
|
The default server is `cryptgeon.org`, however you can use any cryptgeon server by passing the `-s` or `--server` option, or by setting the `CRYPTGEON_SERVER` environment variable.
|
||||||
|
|
||||||
|
### Password
|
||||||
|
|
||||||
|
Optionally, just like in the web ui, you can choose to use a manual password. You can do that by passing the `-p` or `--password` options, or by piping it into stdin.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
echo "my pw" | cryptgeon send text "my text"
|
||||||
|
cat pass.txt | cryptgeon send text "my text"
|
||||||
|
```
|
@@ -1,6 +1,12 @@
|
|||||||
{
|
{
|
||||||
"version": "2.3.0-beta.4",
|
"version": "2.3.0",
|
||||||
"name": "cryptgeon",
|
"name": "cryptgeon",
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/cupcakearmy/cryptgeon.git",
|
||||||
|
"directory": "packages/cli"
|
||||||
|
},
|
||||||
|
"homepage": "https://github.com/cupcakearmy/cryptgeon",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=18"
|
"node": ">=18"
|
||||||
|
@@ -42,6 +42,7 @@ program.name('cryptgeon').version(version).configureHelp({ showGlobalOptions: tr
|
|||||||
|
|
||||||
program
|
program
|
||||||
.command('info')
|
.command('info')
|
||||||
|
.description('show information about the server')
|
||||||
.addOption(server)
|
.addOption(server)
|
||||||
.action(async (options) => {
|
.action(async (options) => {
|
||||||
setBase(options.server)
|
setBase(options.server)
|
||||||
@@ -56,7 +57,7 @@ program
|
|||||||
console.table(formatted)
|
console.table(formatted)
|
||||||
})
|
})
|
||||||
|
|
||||||
const send = program.command('send')
|
const send = program.command('send').description('send a note')
|
||||||
send
|
send
|
||||||
.command('file')
|
.command('file')
|
||||||
.addArgument(files)
|
.addArgument(files)
|
||||||
@@ -86,6 +87,7 @@ send
|
|||||||
|
|
||||||
program
|
program
|
||||||
.command('open')
|
.command('open')
|
||||||
|
.description('open a link with text or files inside')
|
||||||
.addArgument(url)
|
.addArgument(url)
|
||||||
.addOption(password)
|
.addOption(password)
|
||||||
.addOption(all)
|
.addOption(all)
|
||||||
|
@@ -8,10 +8,11 @@
|
|||||||
|
|
||||||
export let note: Note
|
export let note: Note
|
||||||
export let timeExpiration = false
|
export let timeExpiration = false
|
||||||
|
export let customPassword: string | null = null
|
||||||
|
|
||||||
let customPassword = false
|
let hasCustomPassword = false
|
||||||
|
|
||||||
$: if (!customPassword) note.password = undefined
|
$: if (!hasCustomPassword) customPassword = null
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="flex col">
|
<div class="flex col">
|
||||||
@@ -49,15 +50,15 @@
|
|||||||
<div class="flex">
|
<div class="flex">
|
||||||
<Switch
|
<Switch
|
||||||
data-testid="custom-password"
|
data-testid="custom-password"
|
||||||
bind:value={customPassword}
|
bind:value={hasCustomPassword}
|
||||||
label={$t('home.advanced.custom_password')}
|
label={$t('home.advanced.custom_password')}
|
||||||
/>
|
/>
|
||||||
<TextInput
|
<TextInput
|
||||||
data-testid="password"
|
data-testid="password"
|
||||||
type="password"
|
type="password"
|
||||||
bind:value={note.password}
|
bind:value={customPassword}
|
||||||
label={$t('common.password')}
|
label={$t('common.password')}
|
||||||
disabled={!customPassword}
|
disabled={!hasCustomPassword}
|
||||||
random
|
random
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
@@ -27,6 +27,7 @@
|
|||||||
let advanced = false
|
let advanced = false
|
||||||
let isFile = false
|
let isFile = false
|
||||||
let timeExpiration = false
|
let timeExpiration = false
|
||||||
|
let customPassword: string | null = null
|
||||||
let description = ''
|
let description = ''
|
||||||
let loading: string | null = null
|
let loading: string | null = null
|
||||||
|
|
||||||
@@ -57,7 +58,7 @@
|
|||||||
try {
|
try {
|
||||||
loading = $t('common.encrypting')
|
loading = $t('common.encrypting')
|
||||||
|
|
||||||
const derived = note.password && (await AES.derive(note.password))
|
const derived = customPassword && (await AES.derive(customPassword))
|
||||||
const key = derived ? derived[0] : await AES.generateKey()
|
const key = derived ? derived[0] : await AES.generateKey()
|
||||||
|
|
||||||
const data: Note = {
|
const data: Note = {
|
||||||
@@ -79,7 +80,7 @@
|
|||||||
const response = await create(data)
|
const response = await create(data)
|
||||||
result = {
|
result = {
|
||||||
id: response.id,
|
id: response.id,
|
||||||
password: note.password ? undefined : Hex.encode(key),
|
password: customPassword ? undefined : Hex.encode(key),
|
||||||
}
|
}
|
||||||
notify.success($t('home.messages.note_created'))
|
notify.success($t('home.messages.note_created'))
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
@@ -150,7 +151,7 @@
|
|||||||
{#if advanced}
|
{#if advanced}
|
||||||
<div transition:blur={{ duration: 250 }}>
|
<div transition:blur={{ duration: 250 }}>
|
||||||
<hr />
|
<hr />
|
||||||
<AdvancedParameters bind:note bind:timeExpiration />
|
<AdvancedParameters bind:note bind:timeExpiration bind:customPassword />
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
</fieldset>
|
</fieldset>
|
||||||
|
Reference in New Issue
Block a user