Compare commits

...

15 Commits

Author SHA1 Message Date
dc1c03d912 Merge pull request #90 from cupcakearmy/feature/52-Add-note-id-size-option
feat: add note id size option
2023-05-30 10:31:12 +02:00
2a75acae3f docs 2023-05-30 09:43:41 +02:00
815ac4e8ba changelog 2023-05-30 09:43:31 +02:00
7c85c1e621 version bump 2023-05-30 09:43:26 +02:00
a323d48c41 feat: add note id size option 2023-05-29 16:34:59 +02:00
2bff6a37db add some metadata 2023-05-26 01:10:22 +02:00
f8223dfc62 enable sparse bundle 2023-05-26 00:21:50 +02:00
063d073c27 fix pipeline 2023-05-25 23:54:59 +02:00
ac32b97383 Merge pull request #89 from cupcakearmy/69/password
69/password
2023-05-25 23:47:08 +02:00
9c9c23d958 version bump 2023-05-25 23:29:09 +02:00
92893a5b2d github actions 2023-05-25 23:29:05 +02:00
ac68f4a540 docs 2023-05-25 19:06:07 +02:00
83b2fa5372 version bump 2023-05-25 18:15:31 +02:00
3c86f3f3be update pnpm version 2023-05-25 18:15:18 +02:00
80e64ad207 fix types 2023-05-25 18:15:05 +02:00
16 changed files with 130 additions and 38 deletions

View File

@@ -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:

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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/)

View File

@@ -17,7 +17,7 @@
} }
], ],
"settings": { "settings": {
"i18n-ally.localesPaths": ["packages/frontend/locales"], "i18n-ally.localesPaths": ["locales"],
"cSpell.words": ["cryptgeon"] "cSpell.words": ["cryptgeon"]
} }
} }

View File

@@ -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",

View File

@@ -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",

View File

@@ -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"

View File

@@ -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

View File

@@ -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
View 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"
```

View File

@@ -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"

View File

@@ -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)

View File

@@ -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>

View File

@@ -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>