Skip to content

Releases: dot-protocol/piedpiper

v1.5.0 — embed mode + theming + channel admin (RBAC)

Choose a tag to compare

@mevBlaze mevBlaze released this 18 May 09:22

[1.5.0] — 2026-05-17

Added — embed mode, theming, channel admin + RBAC

  • Embed mode (?embed=1 URL param or postMessage('piperchat:embed')).
    Hides sidebar, header chrome, and identity pill so the chat fits inside
    any host page's UI.
  • Host postMessage bus for runtime control:
    • piperchat:set-identity — host injects ed25519 + x25519 keys + channel
    • piperchat:set-theme — patch CSS variables at runtime (CSS-var
      whitelist rejects ;, url(), expression())
    • piperchat:set-channel — switch active channel without remount
    • piperchat:embed — enable embed mode at runtime
  • Iframe → host events:
    • piperchat:boot — bootstrap script parsed
    • piperchat:ready — DOM ready, accepting commands
    • piperchat:message-received — metadata only (from, channel, ts,
      message_id, in_reply_to); ciphertext never leaves the iframe
  • Theming via URL params: ?theme=light|dark presets plus
    ?accent=…&bg=…&surface=…&text=…&radius=…&font=….
  • Channel ownership + membership + audit (RBAC) — opt-in:
    • POST /channels/:name/claim — first-write-wins ownership
      (ed25519-signed, ±300s replay window)
    • POST /channels/:name/members — add member (owner/admin)
    • DELETE /channels/:name/members/:dot1 — remove (owner/admin; owner
      is protected)
    • PATCH /channels/:name/members/:dot1 — change role (owner only)
    • GET /channels/:name/admin — public read of owner + roster + audit
    • GET /channels/mine?dot1=… — channels this identity belongs to
  • Membership enforcement on /messages POST: unclaimed channels stay
    open; once a channel is claimed only members may post and v1.0 legacy
    unsigned envelopes are rejected outright.
  • /admin panel UI at public/admin.html — ed25519 unlock, claim,
    manage roster + roles, audit log.
  • Three new examples:
    • examples/embed-iframe/ — vanilla HTML drop-in with live theme picker
    • examples/embed-react/<PiperChat /> React component
    • examples/crm-support-panel/ — per-customer encrypted support flow

Schema

Three new tables, all idempotent on existing databases:

  • channel_owners (channel, owner_dot1, owner_name, claimed_at, description, branding_json)
  • channel_members (channel, dot1, username, role, added_by, added_at)
  • channel_audit (id, channel, event_type, actor_dot1, target_dot1, details, ts)

Backwards compatibility

Fully backwards-compatible with v1.0–v1.4 clients on unclaimed channels.
Claimed channels reject v1.0 (no provable identity) and require v1.1+
from_dot1. The protocol layer (sealed bodies, signatures) is unchanged
— this is product-layer RBAC enforced at the relay.

Tests

Smoke-tested end-to-end: claim → add → list → enforce → remove →
owner-protection → duplicate-claim 409 → bad-sig 400 → ts-skew 400 →
unclaimed-channel still open. All paths clean.


v1.4.0 — zstd-with-shared-dict wire compression (34.8% reduction, p99 0.68ms)

Choose a tag to compare

@mevBlaze mevBlaze released this 17 May 10:06

[1.4.0] — 2026-05-16

Added — zstd wire compression with shared dictionary

  • New optional comp field on v1.2 sealed-body envelopes. When set to
    "zstd-dict-v1", the body plaintext was zstd-compressed (level 3) using the
    shipped shared dictionary BEFORE AES-256-GCM encryption. Decoder reverses
    the order: verify sig → unwrap body key → AES open → zstd decompress with
    dict.
  • lib/compression.js — compress/decompress helpers using Node 22+
    built-in zlib zstd (no native or wasm deps). Loads
    lib/dict/piperchat-zstd-v1.dict once on first use, caches.
  • lib/dict/piperchat-zstd-v1.dict — 64KB shared zstd dictionary,
    trained offline on 211 representative piperchat-shaped samples (11
    real v1.2 messages + 200 DOTpost observations). Committed as binary.
  • tools/dict-trainer/{split-corpus.py,train.sh} — re-train the dict
    from a fresh corpus when ready (e.g. after collecting more traffic).
  • comp field is signed in ed25519 canonical bytes when present
    (v12CanonicalBytes extended). v1.2/v1.3 envelopes without comp
    produce byte-identical canonical bytes as before — no breaking change.
  • Server stores comp in a new messages.comp SQLite column and
    echoes it back in toPublic / SSE / GET responses.
  • isV12Envelope now accepts version ∈ {1.2, 1.3, 1.4} — they share
    the encrypted-envelope wire shape.

Performance (measured on the included test suite)

Message size class Sample count v1.4 reduction vs v1.2
Short (<30B raw) 3 -35.5% (bloat — zstd frame overhead)
Meaningful (≥100B raw) 5 34.8%
Mixed corpus (60 samples) median 1.62× ratio

Round-trip latency (compress + decompress) p99 = 0.68 ms on Apple Silicon.

Backwards compatibility

Fully backwards-compatible. No flag day. v1.0–v1.3 clients keep working unchanged.

Sender Receiver Result
v1.0–1.3 any unchanged — no compression negotiated
v1.4 v1.0–1.3 sender omits comp; receiver handles as v1.2/v1.3
v1.4 v1.4 sender sets comp = "zstd-dict-v1"; both peers compress

Sender chooses compression based on recipient's client_caps advertised in
their identity DOT, or falls back to plaintext if capability is unknown.

Threat model

  • Confidentiality: unchanged (AES-256-GCM, per-message random nonce)
  • Authenticity: unchanged + comp is signed (cannot strip / downgrade)
  • Plaintext-length leak: pre-existing in v1.2 (cipher_body size ≈ plaintext +
    28B); v1.4 actually reduces length variance. Padded-bucket framing
    scheduled for v1.5.
  • No CRIME-style adaptive attack: bodies aren't shared across trust
    boundaries; dict is static; attacker can't inject chosen plaintext.

Tests

  • test/compression.test.js — 9 unit tests (round-trip, latency, dispatch,
    cross-version isolation, dict cache)
  • tests/v1.4-roundtrip.js — 6 end-to-end tests (sign+encrypt+decrypt+
    decompress, v1.2 backwards-compat, comp tampering rejection, wire-size
    reduction, v1.4-sender-to-v1.2-receiver degraded path)
  • HTTP smoke: POST a v1.4 envelope to a live server, GET it back, verify
    version=1.4 and comp=zstd-dict-v1 round-trip through the SQLite
    storage layer.
  • Existing tests/v1.2-roundtrip.js continues to pass (19/19) — no regression.

Engine bump

engines.node now requires Node 22+ (was 20+). Required for built-in
zlib.zstdCompressSync / zstdDecompressSync with dictionary option.

Files

  • New: lib/compression.js, lib/dict/piperchat-zstd-v1.dict,
    tools/dict-trainer/{split-corpus.py,train.sh},
    test/compression.test.js, tests/v1.4-roundtrip.js
  • Modified: lib/crypto.js (v12CanonicalBytes + isV12Envelope extended),
    lib/db.js (comp column), client.js (sendEncrypted +
    sendViaMailbox + readEnvelope), server.js (envForVerify includes
    comp + insert + toPublic), docs/PROTOCOL.md (v1.4 section),
    package.json (1.3.0 → 1.4.0, engines 20 → 22)

v1.3.0 — sealed-body encryption + mailbox bridge + usernames

Choose a tag to compare

@mevBlaze mevBlaze released this 14 May 20:23

What's new since v1.0.0

v1.2 — sealed-body encryption (X25519 + AES-256-GCM) + mailbox bridge transport. Production-live at piedpiper.fun/chat/ since 2026-05-11.

v1.3 — username layer: registry + claim endpoint + UI. Canonical-JSON signing for username claim records.

Highlights

  • End-to-end body encryption — only the recipient's keypair can decrypt
  • Mailbox bridge transport for asynchronous delivery to offline peers
  • Username registry — claim a human-readable handle pinned to your pubkey
  • PROTOCOL.md spec is canonical (versions 1.2 + 1.3 included)
  • Reference server + browser client, both Apache-2.0

Verifying

```
git clone https://github.com/dot-protocol/piperchat
cd piperchat && git checkout v1.3.0
```

Apache 2.0. No restrictions.

v1.0.0 — signed messages, channels, production ops

Choose a tag to compare

@mevBlaze mevBlaze released this 03 May 17:44

first hardened release. signed messages via ed25519. sqlite WAL persistence. per-channel rooms. dockerfile, github actions ci, pm2 ecosystem. one repo, no servers between you and the people you're chatting with.