v0.0.52 - Added api.md with unified verb scheme, fixed TUI status display in README, added TCP/HTTP port auto-increment on EADDRINUSE (up to 5 tries)

This commit is contained in:
Laan Tungir
2026-07-20 09:07:21 -04:00
parent db274ce487
commit 0355744103
5 changed files with 596 additions and 93 deletions

View File

@@ -92,7 +92,7 @@ When started, `n_signer` immediately enters terminal input mode:
5. **OTP pad selection** (optional): auto-scans attached USB drives for OTP pads and offers to bind one. See [`plans/otp_nostr_integration.md`](plans/otp_nostr_integration.md).
6. Pick the abstract socket name (random BIP-39 pair, or `--socket-name` / `--name` / `-n` override).
7. Initialize transport endpoints and bind the socket.
8. Switch to running status display, with the signer name, socket address, and OTP pad status shown in the banner.
8. Switch to running status display, with the signer name and socket address shown in the Connections section and status line (see [§3.2](#32-running-phase-status-display--signer)).
No startup files are read or written. The mnemonic — typed or generated — lives only in `mlock`'d memory and is zeroized on shutdown or crash.
@@ -105,46 +105,42 @@ These modes avoid putting mnemonic material in argv/environment and are designed
### 3.2 Running phase (status display + signer)
After unlock, terminal becomes a live status and control console. Example layout:
After unlock, the terminal becomes a live status and control console rendered by [`render_status()`](src/main.c). The top frame shows the program name and version; below it are the Connections, Roles, and Activity sections, followed by a single status line. Example layout (single Unix listener, one role derived):
```text
n_signer v0.x | foreground session active
n_signer v0.0.2 > Main Menu
Connections
Server: unix @nsigner (bridge-source-trusted)
Client: nsigner --socket-name nsigner client '<json>'
Qrexec: qrexec-client-vm <target_qube> qubes.NsignerRpc
Server: HTTP 127.0.0.1:11111
Client: curl -X POST http://127.0.0.1:11111/ -H 'Content-Type: application/json' -d '<json>'
Connections:
Server: unix @nsigner_hairy_dog
Client: nsigner --socket-name nsigner_hairy_dog client '<json>'
OTP pad: 333e9902db839d9d... (offset 288 / 1048576 bytes)
session: unlocked (RAM-only)
Roles:
Role Purpose Curve Selector
main nostr secp256k1 role:main
ops nostr secp256k1 nostr_index:7
backup bitcoin secp256k1 role_path:m/84'/0'/0'/0/5
Roles
-----
main purpose=nostr curve=secp256k1 selector=role:main
ops purpose=nostr curve=secp256k1 selector=nostr_index:7
backup purpose=bitcoin curve=secp256k1 selector=role_path:m/84'/0'/0'/0/5
Pending approvals
-----------------
(none)
Activity (latest first)
-----------------------
Activity (latest first):
16:03:11 allow caller=uid:1000 method=get_public_key role=main
16:02:44 prompt caller=uid:1000 method=sign_event role=ops
16:02:46 allow caller=uid:1000 method=sign_event role=ops
15:59:10 deny caller=uid:1001 method=sign_event error=unauthorized
Hotkeys
-------
a toggle auto-approve(prompt) for this session
r refresh
l lock/reunlock session
q quit
session=unlocked (12 words) signer=nsigner_hairy_dog derived=3 auto-approve=OFF
```
The signer's name (`nsigner_hairy_dog` in this example) appears in two places: the **Connections** section as the abstract socket address (`Server: unix @nsigner_hairy_dog`), and the **status line** at the bottom (`signer=nsigner_hairy_dog`). See [§7.1](#71-linux-desktop-abstract-namespace-unix-socket) for how the name is generated.
When multiple transports are active (interactive transport selection), the Connections section lists each one with its client command. HTTP and FIPS/TCP entries show `curl` / `nsigner --listen ... client` examples respectively.
Hotkeys (active while the status display is shown):
- `a` — toggle auto-approve (prompt) for this session
- `r` — refresh the display
- `l` — lock / re-unlock the session
- `q` — quit
### 3.3 Approval prompts
When a request needs confirmation, `n_signer` interrupts the status view with a prompt and waits for a local keystroke.
@@ -334,6 +330,8 @@ nsigner --preapprove caller=uid:1000,algorithm=ml-kem-768,index=0,verb=decapsula
## 5. Wire contract (JSON-RPC)
> **The full, authoritative API reference now lives in [`api.md`](api.md).** The summary below is kept for orientation; for request/response shapes, error codes, and worked examples, consult [`api.md`](api.md).
Request shape is JSON-RPC with NIP-46-style methods and optional trailing selector options.
```jsonc
@@ -522,7 +520,7 @@ Properties:
Naming rules:
- Default: random pick at startup, displayed in the TUI banner.
- Default: random pick at startup, displayed in the Connections section and status line of the running display.
- Override: `--socket-name <name>` (alias: `--name <name>` / `-n <name>`) forces a specific name (useful for scripts and tests).
- Collision: if the chosen random name is already bound by another process, `nsigner` retries with a fresh pair up to 8 times before erroring out with a hint to use an explicit name override.
@@ -678,7 +676,7 @@ Setup scripts and policy are in [`packaging/qubes/`](packaging/qubes/). See also
nsigner
```
Program starts in attached foreground mode and prompts for mnemonic. After mnemonic acceptance, the TUI banner shows the randomly assigned signer name and its abstract socket address.
Program starts in attached foreground mode and prompts for mnemonic. After mnemonic acceptance, the running status display shows the randomly assigned signer name and its abstract socket address in the Connections section and the bottom status line (see [§3.2](#32-running-phase-status-display--signer)).
To force a specific socket name (e.g. for scripted clients):
@@ -764,10 +762,7 @@ Terminal A:
```text
$ nsigner
[unlock] enter mnemonic:
[ok] session unlocked
signer name : hairy dog
socket : @nsigner_hairy_dog
[listen] unix-abstract:@nsigner_hairy_dog
System is ready and waiting for connections on @nsigner_hairy_dog.
[prompt] caller=uid:1000 method=sign_event role=main -> allow? (y/n)
```