Files
reze-test/README.md
T
reze dfe3e94aa4 reze: Make the CI deploy step manual-only
Dokploy deploys are triggered from the UI, so the pipeline no longer runs on
push to trunk. The file stays as a template: it is a no-op unless DEPLOY_URL is
available, and the trigger can be switched back to push-on-trunk.
2026-10-21 09:07:15 +00:00

187 lines
5.8 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# reze-test
A small, dependency-free password generator. It has two modes:
- **Memorable** — diceware-style passphrases shaped like `[num][word]-[num][word]-…`, e.g. `42abacus-91abdomen`.
- **Random** — fully random characters from a configurable character set.
Everything is generated server-side with Node's CSPRNG (`crypto.randomInt`). There is no
account, no login, no database, and nothing you generate is stored or logged.
## Features
- Two randomization levels: memorable passphrases and fully random passwords.
- EFF word lists (7776-word and 1296-word) selectable per request.
- Configurable digits per word, digit separator, group separator and capitalization.
- Configurable length, character classes, custom symbol set, ambiguous-character exclusion
and "at least one of each selected set".
- Generate up to 10 passwords at once, each with an entropy estimate and a strength bar.
- One-click copy with a clipboard fallback.
- Light/dark theme with a system-theme fallback, persisted in `localStorage`.
- Options persisted in `localStorage`; generated passwords are never persisted.
- No npm dependencies at all — Node.js built-ins only.
## Requirements
- Node.js 22 or newer (ESM, `"type": "module"`).
## Run locally
```sh
node server.js
```
The server listens on `0.0.0.0:3000` by default. Override the port with `PORT`:
```sh
PORT=8080 node server.js
```
Open <http://localhost:3000>.
Or via the POSIX sh helper, which defaults `PORT` to 3000:
```sh
sh scripts/run.sh
PORT=8080 sh scripts/run.sh
```
## Tests
```sh
node --test
```
## API
All API responses are JSON. Every response carries the security headers
`X-Content-Type-Options: nosniff`, `Referrer-Policy: no-referrer`,
`X-Frame-Options: DENY` and a strict `Content-Security-Policy`.
### `GET /healthz`
Liveness probe used by the Docker `HEALTHCHECK`.
```sh
curl -s localhost:3000/healthz
```
```json
{"status":"ok"}
```
### `GET /api/meta`
Describes the available word lists.
```sh
curl -s localhost:3000/api/meta
```
```json
{"lists":[{"id":"eff-large","name":"EFF Large Word List","size":7776},{"id":"eff-short","name":"EFF Short Word List (2.0)","size":1296}]}
```
### `POST /api/generate`
Body is a JSON object. `mode` selects the algorithm; `count` (1–10, default 1) is the
number of passwords to return. Unknown modes, malformed JSON and out-of-range options
are rejected with `400` and a JSON `{"error": "…"}` body. Request bodies are limited to
64 KB.
Memorable options: `words` (2–10), `digits` (0–4), `digitSeparator` (`''` or `'-'`),
`separator` (`'-'`, `'_'`, `'.'`, `' '` or `''`), `capitalization`
(`'none'`, `'title'`, `'upper'`), `list` (`'eff-large'`, `'eff-short'`).
```sh
curl -s -X POST localhost:3000/api/generate \
-H 'Content-Type: application/json' \
-d '{"mode":"memorable","words":2,"digits":2,"separator":"-","digitSeparator":"","capitalization":"title","list":"eff-large","count":2}'
```
```json
{"mode":"memorable","count":2,"passwords":[{"value":"07Sample-29Breach","mode":"memorable","entropy":39.1},{"value":"69Reassign-85Probation","mode":"memorable","entropy":39.1}],"entropy":39.1}
```
Random options: `length` (8–64), `useLower`, `useUpper`, `useDigits`, `useSymbols`,
`customSymbols` (replaces the default symbol set when non-empty), `excludeAmbiguous`
(removes `0 O 1 l I |`) and `requireEach`.
```sh
curl -s -X POST localhost:3000/api/generate \
-H 'Content-Type: application/json' \
-d '{"mode":"random","length":24,"useLower":true,"useUpper":true,"useDigits":true,"useSymbols":true,"requireEach":true,"count":1}'
```
```json
{"mode":"random","count":1,"passwords":[{"value":"3V#P@bQ2C4c3;=igw}E(EpnG","mode":"random","entropy":154.6}],"entropy":154.6}
```
### Entropy
- Random mode: `length * log2(poolSize)`, where `poolSize` is the size of the union of all
enabled character classes.
- Memorable mode: `words * log2(listSize) + words * digits * log2(10)`. Separators and the
capitalization scheme add no entropy.
### Other paths
Unknown `/api/*` paths return a JSON `404`. Unknown page paths return
`public/404.html` with HTTP `404`. Only `GET` and `HEAD` are accepted for static files.
## Word lists
| id | list | size |
| --- | --- | --- |
| `eff-large` | EFF Large Word List | 7776 |
| `eff-short` | EFF Short Word List (2.0) | 1296 |
Both files live in `public/words/` and are loaded once at startup.
- Source: [Electronic Frontier Foundation](https://www.eff.org/dice) — the
[EFF Diceware wordlists](https://www.eff.org/dice-roll-the-dice).
- Licence: Creative Commons Attribution 3.0 Unported (CC BY 3.0),
<https://www.eff.org/copyright>.
The lists contain a few hyphenated entries (`drop-down`, `felt-tip`, `t-shirt`, `yo-yo`),
which are used verbatim.
## Environment variables
| variable | default | description |
| --- | --- | --- |
| `PORT` | `3000` | TCP port the HTTP server binds to on `0.0.0.0`. |
| `NODE_ENV` | — | Set to `production` in the image. |
## Docker
```sh
docker build -t reze-test .
docker run --rm -p 3000:3000 reze-test
```
Or with compose:
```sh
docker compose up --build -d
```
The image is a single stage based on `node:22-alpine`, runs as the non-root `node` user
and ships a `HEALTHCHECK` that polls `http://127.0.0.1:3000/healthz` with `wget`.
## Deployment (Dokploy)
- Repository: `druid520/reze-test` on Gitea (git.kg.boson.party).
- Branch: `trunk`.
- Build type: Dockerfile (or "Nixpacks" — the app needs nothing but Node).
- Environment variable: `PORT=3000`.
- Exposed port: `3000`.
- Deploys are triggered from the Dokploy UI (or a Gitea webhook configured there).
CI does not deploy automatically: `.woodpecker.yml` is a manual-only template. If you
want a push-to-deploy hook, set a `DEPLOY_URL` repository variable (the Dokploy deploy
webhook URL) and switch the pipeline trigger back to `event: push` on `trunk`.
## License
MIT for the code. The bundled word lists are CC BY 3.0, © Electronic Frontier Foundation.