Compare commits

..
58 Commits
Author SHA1 Message Date
thePR0M3TH3ANandClaude Opus 4.8 0ae69a2774 Board: show only real VoxVera flyers, not foreign kind-30078 events
kind 30078 is a shared "application data" kind, so other apps (e.g.
artstr.studio) publish under it too — and relays may ignore our #t
filter, or an unrelated note may carry a "voxvera" hashtag. The board
only checked kind + t-tag, never the payload, so foreign events could
appear.

parseFlyers now also requires VoxVera's own markers: a `voxvera:` d-tag
and a `type: "voxvera_flyer"` content payload (both real flyers and
tombstones have these), filtering foreign events out client-side
regardless of relay behavior.

Test: a foreign kind-30078 event carrying a voxvera t-tag is excluded
while a real flyer shows. Full suite 384 passing.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-06-11 22:37:57 -04:00
thePR0M3TH3ANandClaude Opus 4.8 6fe9069f82 Add Open Graph preview image (1200x630 card) site-wide
Shared voxvera.org links now render a real image card, not just a text
summary. Adds site/og-card.jpg (1200x630, ~90KB, derived from the
"say something… voxvera.org" custom art) and wires og:image +
twitter:image + image dimensions/alt on the home, board, and safety
pages, bumping twitter:card to summary_large_image.

Per-flyer previews remain out of scope (fragment URLs are invisible to
servers; this stays a purely static site). Test asserts all three pages
declare the og:image and that the asset is served as JPEG. Full suite
378 passing.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-06-11 22:27:03 -04:00
thePR0M3TH3ANandClaude Opus 4.8 18fa382632 Add NIP-46 nostrconnect (QR) login path; move board safety link to footer
NIP-46 now supports both connect directions on the editor and the board:
- bunker:// (existing): paste a link the signer app generated.
- nostrconnect:// (new): the client generates the link, renders it as a
  QR (+ a copyable link for one-device use), listens on a rendezvous
  relay (relay.nsec.app), and the signer app scans it and connects back —
  proven by echoing the client's random secret. The discovered signer
  pubkey then drives the durable connection (shared adopt path).

Both paths stay session-only with an ephemeral local key; the QR uses
the same hand-rolled NIP-44 client (NIP-04 decrypt fallback). qrcode-
generator is now loaded on the board too. 3 new localized strings
(scan / waiting / copy-link) across all 14 languages in NOSTR_UI and
BOARD_UI; i18n parity passes.

Also per feedback: the board's "Safety & privacy" link moves out of the
topbar (where it ran together with "Back to VoxVera") into a centered
footer link matching the home page, and both pages now link /safety.html
(works on the static host and Vercel alike).

Tests: editor and board each connect via a fake signer that "scans" the
nostrconnect QR (reads the on-screen URI, echoes the secret) — all 6
engines. Full suite 372 passing.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-06-11 21:49:37 -04:00
thePR0M3TH3ANandClaude Opus 4.8 b38dea1294 Add NIP-46 remote signer to the board login gate
The board's connect gate now offers "Remote signer (NIP-46)" alongside
NIP-07 / nsec / create-key. Pasting a bunker:// link establishes the
viewer's pubkey (for the web-of-trust filter and display) and keeps the
connection alive so getBoardSigner can sign reports and deletions
remotely this session — its whole point being that the secret never
leaves the signer app. After a reload the board reconnects read-only from
the remembered pubkey (session-only, like the editor).

The minimal NIP-46 client (parse bunker URI, NIP-44 codec with NIP-04
decrypt fallback, raw-WebSocket request/response) is ported into board.js,
which is an independent IIFE. Reuses the editor's translations for the 3
new BOARD_UI strings across all 14 languages (i18n parity passes).

Test: connect the board via a fake bunker signer doing real NIP-44
crypto, confirm it reveals as that identity, and that a report is signed
through the remote signer (kind-1984 with the signer's pubkey). All 6
engines. Full suite 360 passing.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-06-11 15:04:12 -04:00
thePR0M3TH3ANandClaude Opus 4.8 29ed45533d Add localized Safety & privacy page + static link-preview meta
New standalone /safety page (safety.html / safety.js), localized across
all 14 languages, in plain language: what VoxVera protects, what it does
NOT (relays see your IP; the anonymous key is stored unencrypted; a short
PIN won't stop a targeted attacker; published events are public and
permanent; nsec-paste risk; reports are public; the host/relays still see
requests), and operational tips (Tor/VPN, disposable keys, signer apps).
Linked from the editor and the board. Aimed at the activist audience the
aesthetic invites — being honest about limits matters more than features.

Also adds static site-wide Open Graph / Twitter-card meta to the home,
board, and safety pages so a shared voxvera.org link renders a real
title/description instead of nothing. Per-flyer previews remain a
deliberate non-goal: the naddr lives in the URL fragment (invisible to
servers) and per-flyer meta would require server-side rendering, which is
out of scope for a purely static site.

i18n guard extended to SAFETY_UI (keys + equal bullet-list lengths per
language). New cross-engine test covers the page's sections, localization,
RTL, and the editor/board links. Full suite 354 passing.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-06-11 14:53:48 -04:00
thePR0M3TH3ANandClaude Opus 4.8 53374ec87b Add NIP-56 reporting to the bulletin board
Others' flyers now offer a "Report" action (in the ⋯ menu, alongside
Block) that publishes a signed kind-1984 report: a category picker
(spam / illegal / impersonation / other → NIP-56 report types) plus an
optional free-text reason, tagged with the flyer (e) and author (p) so
other clients and moderators can aggregate it. Reporting also hides the
flyer locally, pairing with the existing per-device blocklist. Requires a
usable signer (device key or NIP-07); pasted-nsec viewers get a clear
"connect to report" message, same as delete.

Adds 11 localized strings across all 14 languages (i18n parity passes).
Test: report publishes a kind-1984 event with the right p/e tags + type +
reason and hides the row, across all 6 engines. Full suite 342 passing.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-06-11 14:05:12 -04:00
thePR0M3TH3ANandClaude Opus 4.8 b344f92be7 Import/export a flyer design as a portable JSON file
Replaces the raw "Export event JSON" button with Import design / Export
design in the editor. A design file is content + relays only —
deliberately identity-free (no npub, naddr, event id, or signature, all
of which are derived at publish), so it can be handed to anyone and
published under their own key.

Format: { type: "voxvera_flyer_design", version: 1, flyer: <payload>,
relays: [] }. Export serializes the current form as-is (draft-friendly).
Import reads the picked file (capped at 256 KB), accepts the wrapper
format or a bare voxvera_flyer payload, then shows a confirm modal before
overwriting the editor; on confirm it fills the form and restores relays.
Imported content stays untrusted: the renderer escapes every field and
strict validation still runs at publish.

Adds 8 localized strings across all 14 languages (i18n parity passes).
Tests: export round-trip (identity-free assertions), import-then-confirm,
cancel-leaves-unchanged, and invalid-file rejection, across all 6
engines. Full suite 336 passing.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-06-11 13:42:43 -04:00
thePR0M3TH3ANandClaude Opus 4.8 a4cb8dffcb Add NIP-46 remote signer (bunker) as an editor identity
The editor can now sign flyers via a NIP-46 remote signer: paste a
bunker:// link and the user's secret stays in their signer app
(nsec.app, Amber, …) while the browser holds only an ephemeral local
key. The vendored nostr-tools bundle has no nip46 module, so the client
is hand-rolled over a raw WebSocket — kind-24133 JSON-RPC encrypted with
NIP-44 (with a NIP-04 decrypt fallback), running connect →
get_public_key → sign_event. Connections are session-only; the bunker
token is never written to disk, so a reload returns to anonymous.

Switching to/from any other identity mode disconnects the signer, and a
successful connection mirrors the user pubkey to the board's connected
key. Adds 9 localized strings across all 14 languages (i18n parity test
passes).

Tested with a fake relay/signer doing real NIP-44 crypto: full connect →
get_public_key → sign_event → publish round-trip, across all 6 engines.
Full suite 312 passing.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-06-11 13:17:17 -04:00
thePR0M3TH3ANandClaude Opus 4.8 bf90f1608b Degree-2 web-of-trust + editor↔board identity sync
Board trust filter now also includes follows-of-follows (degree 2): on
connect it fetches the viewer's NIP-02 follows, then the kind-3 lists of
those follows (capped at 150 authors), and trusts the union. Brand-new
keys still fall back to the curator seed; no-data still falls back to
show-all.

A deliberate editor identity choice (NIP-07 / imported / generated /
unlocked nsec / anonymous) now writes a shared local pubkey that the
board reads, so the same person sees a consistent identity across pages.

Tests: degree-2 inclusion (A direct, B friend-of-friend shown; stranger
C hidden) and editor→board key sync, across all 6 engines. Full suite
306 passing.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-06-11 10:36:30 -04:00
thePR0M3TH3ANandClaude Opus 4.8 c97624a5e0 Board "My flyers" filter + author display names; editor wrong-PIN lockout
Three quick-ish wins:

- "My flyers" board filter: a checkbox that shows only the connected user's own
  flyers (overrides the trust filter, since your own may not be in your follow
  graph). New mine_only string × 14.
- Author display names: the board fetches authors' kind-0 metadata and shows
  the display name (falling back to the npub) instead of a bare key. Names are
  untrusted — escaped at render and length-capped. (NIP-05 verification is still
  future.)
- Wrong-PIN lockout: after 3 bad PINs the editor refuses to unlock a remembered
  nsec for a 30s cooldown, persisted across reloads so it isn't reset by a
  refresh. A deterrent against casual on-device guessing (a leaked blob is still
  offline-brute-forceable). New too_many_attempts string × 14.

Adds e2e for each; the i18n guard enforces the new strings in all 14 languages.
294 e2e across all six engines; roadmap updated.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-06-11 10:20:16 -04:00
thePR0M3TH3ANandClaude Opus 4.8 78ee5bf0cf Add i18n key-parity guard + publish "N/M relays accepted"; fix missing translation
Two quick, high-value wins:

- i18n guard (e2e/i18n.spec.js): a pure-Node test that fails if any NOSTR_UI /
  BOARD_UI / locales dictionary is missing or has an extra key in some language.
  It immediately caught field_too_long, which was English-only — so non-English
  users saw the English "that field is too long" message. Added the missing
  translation to all 13 other languages.

- Publish transparency: the confirmation modal now shows "Relays accepted: N / M"
  (relays_accepted string × 14) and flags a zero-acceptance publish in red, so a
  weak publish is visible immediately instead of discovered later.

276 e2e across all six engines; roadmap updated.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-06-11 10:04:18 -04:00
thePR0M3TH3ANandClaude Opus 4.8 d160542f7d Default flyer: swap title/headline so the side tabs carry the project name
The tear-off tabs are labeled with the flyer's title, so swap the default
landing content's title and headline in every language: the title is now
"OPERATION VOX VERA" (the project name, shown on all ten tabs and as the top
line) and the headline is the dramatic "TOP SECRET" below it. Applied across all
14 languages in locales.js (e.g. de title "OPERATION VOX VERA" / headline
"STRENG GEHEIM").

Updated the e2e assertions (default title is now the project name; the German-
distinctive string is now the headline) and the spec payload example. 258 e2e
across all six engines.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-06-11 09:30:28 -04:00
thePR0M3TH3ANandClaude Opus 4.8 90e1bc8873 Mobile: flyer fits width, board collapses to cards, fix always-shown identity box
Three mobile/responsive fixes (diagnosed at phone widths):

- Flyer no longer side-scrolls/clips on phones. In viewer mode .flyer-preview is
  a flexbox, so the sheet (a flex item) was shrunk to the viewport, making the
  fit math compute scale = 1 and the full-width content clip. Add flex: 0 0 auto
  so the sheet keeps its true print width and the transform scales it to fully
  fit the screen.

- Bulletin board collapses to a card per flyer on ≤640px: title + the ⋯ menu
  stay visible; the secondary columns (link, posted-by, language, date, event
  id) move behind a per-row "Details" disclosure (labeled via data-label). New
  details_label string × 14 languages.

- Fix a real (not mobile-only) bug: the editor's nsec-import box and
  "locked identity" row showed on every load because .identity-import's
  display:flex overrode the hidden attribute. Add .identity-import[hidden]
  { display:none } (same class of bug we hit on the board identity chip).

Adds e2e: flyer fits width with no horizontal overflow, identity controls hidden
until chosen, and the board's narrow-screen card + Details toggle. The desktop
"sortable columns" test pins a desktop viewport (the header is hidden in card
mode). 258 e2e across all six engines; docs updated.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-06-11 09:20:33 -04:00
thePR0M3TH3ANandClaude Opus 4.8 053ea875b8 Tear-off tabs: title label, clickable "open & reprint" link, VoxVera.org event ID
Each of the ten tear-off tabs now reads, top to bottom:

- the flyer's TITLE, auto-sized (fitTabTitles) to be as large as fits the ~1in
  tab — big for short titles, shrinking instead of overflowing for long ones —
  so every tab is clearly labeled;
- a smaller, clickable "Open & reprint this flyer" link (the <a href>, so it
  stays live in a printed PDF) in place of the old "Click to open this poster."
  / "Share and reprint." (clicking, not "scan," is what a PDF link does);
- the tear-off QR; and
- a "Reopen at VoxVera.org — Event ID:" line (was just "Event ID:") so people
  know the id is for re-finding/reprinting the flyer at the site.

New tab_link / tab_event_id strings in all 14 languages (VoxVera.org stays the
Latin brand; the rest localizes). e2e covers the title, the link text + poster
href, and the event-id label. 240 e2e across all six engines.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-06-11 08:29:13 -04:00
thePR0M3TH3ANandClaude Opus 4.8 085ff81c1a Board: tuck per-row actions behind a ⋯ menu
The inline Edit / Re-broadcast / Delete (and Block) buttons wrapped messily in
the actions column. Replace them with a single ⋯ button per row that opens a
small popout menu with the relevant actions. Closes on outside click, Escape,
or selecting an item; the actions and their data-act wiring are unchanged.

Adds the menu markup/toggle in board.js, an "Actions" aria-label string × 14
languages, and menu/kebab styles. e2e updated to open the menu before acting.
234 e2e across all six engines.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-06-10 20:16:12 -04:00
thePR0M3TH3ANandClaude Opus 4.8 73c28f31ec Bulletin board: per-row manage (edit / re-broadcast / delete) + local Block
Add inline management to the board for the connected viewer:

- On your own flyers: Edit (links to /?edit=1#<naddr>, which the main client
  now honors by loading the flyer straight into the editor), Re-broadcast
  (re-sends the already-signed event to all relays — no signing), and Delete
  (replaceable tombstone + NIP-09, signed via the device key or NIP-07; a
  pasted-nsec connection is pointed to the editor where the key is available).
- On flyers from others: Block — a per-device blocklist of author pubkeys
  (voxvera_blocked_pubkeys) that always hides them, with a "Clear blocked"
  control. This is roadmap #1's local blocklist direction.

The board hides tombstoned flyers (newest-version-wins so a delete can't be
undone by an older copy). New non-sortable actions column; a board delete-
confirm modal; 12 new strings × 14 languages. Adds e2e for block (hide/persist/
clear), own-vs-other actions, and board delete (tombstone + NIP-09 published),
plus a ?edit=1 deep link. 234 e2e across all six engines; docs updated.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-06-10 20:06:07 -04:00
thePR0M3TH3ANandClaude Opus 4.8 9b03ada43a Flyers: edit, re-publish (keep-alive), and delete (tombstone + NIP-09)
Authors can now manage a published flyer from the editor when it's loaded from
an event (author-only — the active signing key must match the flyer's author):

- Edit: change fields and publish again; the same d-tag replaces in place.
- Re-publish (keep-alive): re-sign + re-broadcast the current content so relays
  that prune app-data don't age the flyer out. Partially addresses roadmap #4.
- Delete: belt-and-suspenders across relay behaviors —
  1) a replaceable TOMBSTONE (same kind+d, payload deleted:true + a ["deleted"]
     tag) that overwrites the flyer's content, so the board/viewer hide it even
     on relays that ignore deletions, and
  2) a NIP-09 deletion request (kind 5) for the addressable a-tag + event id.
  Confirmed via a modal; framed as best-effort, not a guarantee.

Tombstone recognition: the board's parseFlyers keeps the newest event per
(pubkey, d) and skips it when that newest version is a tombstone (so a delete
can't be reversed by an older copy arriving later); the viewer renders a
localized "This flyer was removed." state.

Adds the loaded-flyer actions UI + a delete-confirm modal, 11 new strings ×
14 languages, a Python schema test for the tombstone payload, and e2e for the
delete flow, board hiding, and the viewer removed state. 216 e2e across all six
engines; docs (spec/roadmap/README) updated.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-06-10 19:39:23 -04:00
thePR0M3TH3ANandClaude Opus 4.8 23badb03ae Add an SVG favicon (no more /favicon.ico 404)
Link a small inline SVG (site/favicon.svg, a red tile with a white "V") from
both index.html and board.html via a root-absolute href, so it resolves from
"/" and from "/board/" under Vercel cleanUrls. With an icon link present,
browsers stop auto-requesting (and 404ing on) /favicon.ico. No binary asset and
no external dependency, consistent with the self-contained client.

e2e asserts both pages declare the favicon and that /favicon.svg is served as
valid SVG. Closes the last code-finishable item in the roadmap's smaller list.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-06-10 19:19:06 -04:00
thePR0M3TH3ANandClaude Opus 4.8 2f423ceed5 Editor: build the poster naddr from the actual signing key (fix wrong-author URLs)
A flyer published via NIP-07 could get a poster naddr encoding the anonymous
device key instead of the signer: signActiveEvent signed through window.nostr
(the real key) while activeIdentity() — used to build the naddr — fell back to
the anon key whenever nip07Pubkey hadn't loaded yet (e.g. just after a reload
restored nip07 mode). The resulting poster URL pointed at the wrong author and
could never be loaded back, even though the flyer appeared on the board (which
finds events by tag, not address).

signAndPublish now resolves the concrete signing pubkey first (fetching the
NIP-07 key if needed), builds the naddr from that exact key, and refuses to
publish if the signed event's pubkey does not match the naddr — so the signer
and the poster address can no longer diverge.

Note: this prevents new broken flyers; an already-published flyer with a
mismatched naddr must be re-published to get a correct poster URL.

Test: a NIP-07 publish issued while getPublicKey is still pending now yields a
naddr whose pubkey matches the signer (fails on the old code). 192 e2e across
all six engines.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-06-10 15:53:03 -04:00
thePR0M3TH3ANandClaude Opus 4.8 0530dbc905 Bulletin board: add an Event ID column with a per-row copy button
Each flyer row now shows its event ID (shortened, full value in the title
attribute) with a Copy button that copies the full 64-char id to the clipboard
(flips to "Copied", falls back to selecting the text if the clipboard is
blocked). The column is sortable like the others. Copy is handled by a single
delegated listener on the tbody, since rows re-render on sort.

Localized the new column header (col_event_id) across all 14 languages; Copy/
Copied already existed in the board strings. Updated the column e2e test (now 6
columns) and added a test for the id cell + copy target. Docs updated.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-06-10 15:42:20 -04:00
thePR0M3TH3ANandClaude Opus 4.8 82126d52d6 Viewer: render any flyer the board lists (lenient view + board-style fetch)
A flyer could appear on the bulletin board yet fail to open in the viewer.
Two causes, both fixed so "if the board shows it, the viewer opens it":

- Over-strict view validation. The viewer ran the *authoring* validatePayload
  on fetched events (in payloadFromEvent and normalizePayload) and threw on
  length caps, a raw-HTML regex that false-positives on plain text like
  "value < x >", version, and URL scheme — refusing to render. The renderer
  already HTML-escapes every field, so the view path is now lenient: it renders
  what was published and only neutralizes unsafe URL schemes (javascript:/data:
  become no-link instead of throwing). Strict validation still gates authoring
  via buildPayloadFromForm, so we never publish junk. The mandatory t=flyer tag
  is dropped (t=voxvera + a voxvera_flyer payload is enough), matching the board.

- Fragile fetch. fetchReplaceable relied on the relay honoring an addressable
  "#d" tag filter; some relays don't, yet still return the event for a broader
  query (which is how the board finds it). It now queries by author+kind and
  matches the d-tag in-page, with a longer timeout.

Tests: a fetched flyer with HTML-ish text + a 6k body + a javascript: URL now
renders with the URL neutralized; and a flyer served by a relay that refuses
"#d" filters still resolves. 180 e2e across all six engines.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-06-10 15:29:17 -04:00
thePR0M3TH3ANandClaude Opus 4.8 be91ea7250 Roadmap: mark the trust model (#1–#2) shipped
Add a "Shipped so far" summary (board login gate, web-of-trust filter, editor
publishing identity with PIN-encrypted nsec) and refresh the review footer:
the trust model is now implemented, so #3 (centralized client distribution) is
the highest-leverage untouched item.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-06-10 10:22:27 -04:00
thePR0M3TH3ANandClaude Opus 4.8 861407cbf6 Editor: publish under your own identity (NIP-07 / nsec) with PIN-encrypted nsec
Let authors publish a flyer under a stable, identifiable key when they want
one, while keeping anonymous-by-default. The editor now signs under one of
three identities, routed through activeIdentity()/signActiveEvent():

- Anonymous (default, unchanged): the per-device key, signed locally.
- NIP-07 extension: signs via window.nostr.signEvent; the secret never
  enters the page.
- Imported nsec: decoded to a key used to sign. By default the secret lives
  only in memory for the session. "Remember on this device" stores it
  encrypted with a PIN (PBKDF2 SHA-256, 600k iterations, random salt ->
  AES-GCM-256); the plaintext secret is never written to storage. On reload a
  remembered key is locked until the PIN is entered; a session-only key falls
  back to anonymous.

The signer pill, author npub, naddr, and poster URL all follow the active
identity. New identity controls are localized across all 14 languages.

Security note (also in docs): a short numeric PIN is brute-forceable offline
if the encrypted blob leaks, so it guards casual snooping, not a targeted
attacker — the NIP-07 path is stronger, and NIP-46 is a documented follow-up.
The minimum PIN is 4 digits but longer is allowed and encouraged.

Also updates README, the client spec (new "Publishing identity" section),
the roadmap (#1/#2 marked in progress with phases shipped), and the e2e
README. Covered by the cross-engine Playwright suite (default-anonymous,
NIP-07 connect + publish, session-only nsec without persistence, invalid
nsec, PIN encrypt -> lock on reload -> wrong/right PIN -> unlock, and forget).

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-06-10 10:16:53 -04:00
thePR0M3TH3ANandClaude Opus 4.8 1297a73332 Bulletin board: login gate, web-of-trust filter, and key connect methods
Gate the board behind a connected Nostr identity and filter what it shows
to the viewer's web of trust, so it is no longer an unmoderated firehose.

- Login gate: the board shows a Connect prompt instead of the table until a
  Nostr identity is connected; the connected npub is surfaced with a
  Disconnect control and remembered (pubkey only) for silent reconnect.
- Connect methods: NIP-07 extension, pasting an nsec (decoded in-page to a
  pubkey, then discarded — the board reads, never signs), or creating a new
  key (reveals the nsec to save, reuses the device key if present).
- Web-of-trust filter (NIP-02): defaults to flyers from authors in the
  viewer's follow graph, with a "Show all" opt-out. A fresh key with no
  follows is seeded from a pinned curator account so new viewers still get a
  curated board; if no trust data loads at all, it shows everything.
- Localized across all 14 languages (gate, filter, and connect strings),
  RTL included.

Covered by the cross-engine Playwright suite (gate shown/hidden, connect via
each method, pubkey-only persistence, web-of-trust filtering + show-all, and
the curator-seeded fallback).

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-06-10 10:16:24 -04:00
thePR0M3TH3ANandClaude Opus 4.8 b92cb018c5 Roadmap: plan identity + web-of-trust gating for the bulletin board
Mark board moderation (#1) and authenticity (#2) as Planned and add a joint
"identity + web-of-trust on the board" direction:

- Login enables a trust-filtered view, not access control (you cannot gate
  writes to public relays; you filter what the board displays).
- Keep anonymous creation + printing available; require identity only to
  appear on the public board.
- Web-of-trust (NIP-02 follow graph) is the real spam defense, since keys are
  free; login alone is just a soft deterrent.
- Support NIP-07 plus nsec import / NIP-46 / promoted anon key so mobile (the
  scanned-QR audience) isn't locked out.
- Phased plan (identity → WoT filter → blocklist/report/NIP-05) and the two
  open decisions: gate viewing or not, and which login methods at launch.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-06-09 22:25:38 -04:00
thePR0M3TH3ANandClaude Opus 4.8 c8c715f438 Document known issues and roadmap
Add docs/roadmap.md capturing product/threat-model gaps that are not code
bugs, in priority order: (1) bulletin board has no moderation/abuse story,
(2) anonymous keys give no authenticity, (3) client distribution is
centralized on one domain, (4) relay permanence is overstated, (5) minimal
content-safety guardrails, plus smaller items. Each entry notes the problem,
current mitigation, why it matters, and possible directions.

Link it from the README and the spec's bulletin board section.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-06-09 22:21:34 -04:00
thePR0M3TH3ANandClaude Opus 4.8 e0ea31eaef Widen paper-size selector and balance bulletin-board link spacing
- Give the paper-size selects a min/max width so "US Letter (8.5 × 11 in)"
  is readable instead of truncated.
- Add equal spacing below the bulletin-board link to match the gap above it.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-06-09 22:15:03 -04:00
thePR0M3TH3ANandClaude Opus 4.8 7ab7e412ec Show a publish confirmation modal with the flyer URL
After Sign and publish succeeds, open a modal that tells the author the
flyer is published and shows its URL (pre-selected) with Copy and Close
buttons, so they know the process completed and where to view/share it.

- New modal markup in index.html + overlay/box styles (hidden in print).
- Closes on the Close button, backdrop click, or Escape; Copy writes the URL
  to the clipboard with a "Copied" confirmation.
- Localized for all 14 languages (published_title / published_message /
  close); the URL is result.posterUrl.
- Playwright: add a test that stubs the relay socket, publishes, and asserts
  the modal shows the localized text and the naddr poster URL. 84 tests pass
  across all engines.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-06-09 22:06:30 -04:00
thePR0M3TH3ANandClaude Opus 4.8 0044b4b797 Fix unstyled bulletin board on Vercel (cleanUrls/trailingSlash)
vercel.json sets cleanUrls + trailingSlash, so board.html is served at
/board/. Its relative asset paths (nostr-client.css, board.js, locales.js,
vendor/...) then resolved to /board/... and 404'd, leaving the page as raw
unstyled HTML stuck on "Loading…". Use root-absolute paths instead, and
point the back link at "/". Add an e2e guard asserting board.html assets are
root-absolute (the dev server can't reproduce Vercel's URL rewrites).

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-06-09 21:38:26 -04:00
thePR0M3TH3ANandClaude Opus 4.8 98086a0ad4 Add bulletin board page listing recent flyers from the relays
A small screen-only link below the flyer preview (outside the printable
sheet, hidden in print) opens board.html: a spreadsheet-style list of the
most recent VoxVera flyers found on the default relays.

- Columns: title, link (the poster URL shown as "link"), posting npub,
  language, and posted date; every column is sortable (default date
  descending). Replaceable events are de-duplicated per author+d identifier,
  keeping the latest.
- board.js is independent of nostr-client.js (which exports nothing): its UI
  strings live in BOARD_UI for all 14 languages, and it reuses the vendored
  nostr-tools and locales.js (language names + RTL direction).
- The board has its own language selector that reads/writes the same
  voxvera_nostr_lang localStorage key as the main client, so the choice
  carries across pages; switching it re-localizes the chrome, headers,
  language labels, and date formatting and flips RTL.
- Untrusted relay content is escaped, and link URLs are rejected unless
  http(s) so javascript:/data: never render as a link.

Docs updated (README, spec, AGENTS). Playwright: add tests for the
out-of-sheet print-hidden link, the localized sortable columns, and the
board language selector (incl. RTL + persistence). 72 tests pass across
Chromium, Firefox, WebKit, and Android/iOS mobile emulations.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-06-09 16:28:32 -04:00
thePR0M3TH3ANandClaude Opus 4.8 127f9c3134 Locale-aware defaults: browser language list + US Letter/A4 paper size
Language inference:
- Walk navigator.languages (the full ordered preference list), not just
  navigator.language, and pick the first base language we support. A user who
  prefers e.g. Dutch then German now gets German instead of the English
  fallback. De-duplicates the default-language resolution into setDefaultText.

Paper size (US Letter + A4):
- Add A4 (210x297mm) alongside US Letter (8.5x11in). Sheet dimensions move to
  CSS custom properties (--sheet-w/--sheet-h) toggled by a paper-letter/paper-a4
  class on <html>; the tear-off column and QR codes stay fixed physical sizes
  and the content column flexes.
- @page size is injected by JS (id voxvera-page-size) since @page cannot read
  CSS variables across engines; the print block keeps margin:0 and a Letter
  default for the pre-JS state.
- Default paper is chosen from the browser locale's region subtag
  (en-US -> Letter, en-GB/de-DE -> A4) — "by location" without geolocation,
  falling back to Letter when no region is present. A manual override selector
  (topbar + viewer controls) persists in localStorage and wins over the default.
- Paper size is a local print/view preference and is never written into the
  Nostr event, so a flyer reprints on either size unchanged.
- Add paper_size/paper_letter/paper_a4 labels for all 14 languages.

Docs + tests:
- Spec gains a "Print paper size" section; AGENTS.md records the
  not-in-payload invariant; README adds a feature bullet; the field-limits
  cheat sheet gains Letter/A4 columns (re-measured per paper size).
- Playwright: add tests for navigator.languages inference, region-based paper
  default (A4 and Letter), and override persistence. 54 tests pass across
  Chromium, Firefox, WebKit, and Android/iOS mobile emulations.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-06-09 15:56:25 -04:00
thePR0M3TH3ANandClaude Opus 4.8 c5b2c20fc9 Add cross-browser e2e tests, field-limit cheat sheet, and docs
Verification:
- Add Playwright harness (e2e/) covering Chromium, Firefox, and WebKit plus
  Android/iOS mobile emulations. Smoke tests assert: default flyer renders
  with no JS/console errors, @media print hides app chrome and keeps the
  flyer, anonymous npub generation (WebCrypto), legacy /nostr/ redirect
  preserves query+hash, and event-lookup URLs show the loading state instead
  of the default flyer. All six projects pass.
- package.json/playwright.config.js wire up the projects and a managed static
  server; .gitignore excludes node_modules and Playwright output.

Docs:
- docs/flyer-field-limits.md: per-script character cheat sheet for each flyer
  field (single-line caps + multi-line guidance), measured by rendering each
  script at print size.
- README: add a Features section matching the shipping client and a
  cross-browser verification section; link the cheat sheet.
- AGENTS.md: document the e2e suite and the one-time WebKit Linux dep.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-06-09 15:29:49 -04:00
thePR0M3TH3ANandClaude Opus 4.8 562b7d1429 Show loading state on event-lookup URLs instead of default flyer
A viewer arriving via an event-lookup URL (naddr/nevent/note/hex in the
query or #fragment) previously saw the default placeholder flyer flash
before the real event resolved. Now it renders a localized "Loading
content..." state, and a "Could not load this flyer." state on fetch
failure. Default flyer content now appears only on the bare main URL.

- Add loading_content and load_failed labels for all 14 languages
- Add renderStatusPreview() rendering a minimal flyer sheet with a single
  centered, direction-aware message (no tear-offs, no QR)
- Render loading state synchronously before fetch in the URL-event path,
  failed state in the catch handler
- Add .flyer-status-message CSS

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-06-09 13:46:43 -04:00
thePR0M3TH3ANandClaude Opus 4.8 77bfef1bbe Serve client at site root; redirect legacy /nostr/
The /nostr/ path was a leftover from when the site also hosted a Tor
client. The app is Nostr-only now, so move the client to the site root
and shorten poster URLs to https://voxvera.org/#naddr1... (drops both
/nostr/ and the ?addr= query key, for a cleaner/smaller tear-off QR).

- Move site/nostr/{nostr-client.js,css,locales.js,vendor} to site/.
- site/index.html is now the client; site/nostr/index.html is a redirect
  stub that forwards /nostr/ to / while preserving the query string and
  #naddr fragment, so older poster URLs and printed QR codes still
  resolve.
- Carry the naddr in the URL fragment (#) instead of ?addr=; the viewer
  reads query, fragment, or the full URL, so old links keep working.
- Update README, AGENTS.md, and the spec to the new paths.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-06-09 10:49:36 -04:00
thePR0M3TH3ANandClaude Opus 4.8 828ac3a624 Tolerate whitespace in pasted event ID lookups
The Load Event field requires 64 contiguous hex chars, but the event ID
printed on a tear-off tab wraps across two lines, so copying it back in
pastes as two 32-char halves separated by a newline/space and failed to
match. Strip inner whitespace before matching the raw hex id, which also
tolerates a pasted "Event ID:" label prefix. naddr/note/nevent inputs are
unaffected.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-06-09 10:37:07 -04:00
thePR0M3TH3ANandClaude Opus 4.8 aedb381dfb Improve flyer tear-offs, shorten poster URL, adaptive tracking
- Tear-off tabs: single hyperlinked statement (no printed URL), with
  "Share and reprint." on its own line; localize "Click to open this
  poster." across all 14 languages.
- Show the full event ID, bottom-anchored on each tab, split into two
  32-char lines at max readable monospace size.
- Shorten the poster URL by encoding the naddr with a single relay hint
  instead of the full relay list (~233 -> ~171 chars) for an easier-to-
  scan QR; still a standard naddr, older URLs resolve unchanged.
- Add per-script letter-spacing policy (ls-full/ls-cjk/ls-none) to fit
  more text per line where safe, and turn tracking off for Arabic,
  Persian, and Hindi (fixes broken cursive joins / combining marks).
- Move the "field too long" warning inline under the offending field
  instead of a single bottom status line.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
2026-06-09 10:13:55 -04:00
thePR0M3TH3AN 9baf5fb195 fixed mobile 2026-06-06 14:38:19 -04:00
thePR0M3TH3AN fd272888ec Move VoxVera credit below footer message 2026-06-06 14:31:14 -04:00
thePR0M3TH3AN d273843bb1 Improve flyer editing and add demos 2026-06-06 14:26:40 -04:00
thePR0M3TH3AN 20d5e64326 Localize Nostr editor status UI 2026-06-06 09:28:10 -04:00
thePR0M3TH3AN c08f8509db Truncate visible tear-off URLs 2026-06-06 09:19:23 -04:00
thePR0M3TH3AN c53f87dd95 Update default flyer copy for Nostr 2026-06-05 16:01:32 -04:00
thePR0M3TH3AN 83b4133780 Add Vercel static deployment config 2026-06-05 13:59:27 -04:00
thePR0M3TH3AN 1bda451604 Flag flyer language in Nostr events 2026-06-05 13:33:18 -04:00
thePR0M3TH3AN 5afda54a21 Keep content URL separate from poster URL 2026-06-05 10:18:03 -04:00
thePR0M3TH3AN 9aa90773e6 Remove legacy Tor app from main 2026-06-05 10:13:41 -04:00
thePR0M3TH3AN ee13d3fd03 Localize Nostr flyer side tabs 2026-06-05 10:01:57 -04:00
thePR0M3TH3AN 8619261c78 Localize Nostr language controls 2026-06-05 08:51:18 -04:00
thePR0M3TH3AN 3738204ede Keep viewer controls in layout 2026-06-05 08:29:40 -04:00
thePR0M3TH3AN fc50962bf4 Center Nostr viewer controls 2026-06-05 08:22:46 -04:00
thePR0M3TH3AN 0f94d640ac added language selector 2026-06-04 22:30:50 -04:00
thePR0M3TH3AN 46fa306c31 Localize VoxVera Nostr client 2026-06-04 22:06:22 -04:00
thePR0M3TH3AN d415eb26a3 Add VoxVera Nostr static client 2026-06-04 20:15:50 -04:00
thePR0M3TH3AN 285d730369 chore: release v0.3.12 2026-03-19 22:52:47 -04:00
thePR0M3TH3AN f5403448a7 fix: stabilize docker runtime smoke checks 2026-03-19 22:49:05 -04:00
thePR0M3TH3AN 6822b8e496 fix: add docker runtime smoke job to ci 2026-03-19 22:36:36 -04:00
thePR0M3TH3AN 83e9e3d511 feat: harden docker runtime validation 2026-03-19 22:30:28 -04:00
thePR0M3TH3AN 004cce2a4f chore: release v0.3.11 2026-03-19 22:05:16 -04:00
3046 changed files with 21333 additions and 486019 deletions

No files matched your search

-8
View File
@@ -1,8 +0,0 @@
{
"name": "VoxVera",
"build": {
"dockerfile": "../Dockerfile",
"context": ".."
},
"workspaceFolder": "/workspace/VoxVera"
}
-3
View File
@@ -1,3 +0,0 @@
[flake8]
max-line-length = 120
ignore = E501,E741,E401,E402
-173
View File
@@ -1,173 +0,0 @@
name: Build Standalone Binaries
on:
push:
tags:
- 'v*'
workflow_dispatch:
jobs:
build:
name: Build for ${{ matrix.os }}
runs-on: ${{ matrix.os }}
timeout-minutes: 60
strategy:
fail-fast: false
matrix:
os: [ubuntu-22.04, windows-latest, macos-latest]
include:
- os: ubuntu-22.04
artifact_name: voxvera-linux-x86_64
- os: windows-latest
artifact_name: voxvera-windows.exe
- os: macos-latest
artifact_name: voxvera-macos-x86_64
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.12'
- name: Install dependencies
run: |
pip install --upgrade setuptools pkg_resources || pip install --upgrade setuptools
pip install -r requirements.txt
pip install .
pip install pyinstaller pyinstaller-hooks-contrib
- name: Download Tor Binaries
shell: bash
run: |
chmod +x scripts/download_tor.sh
./scripts/download_tor.sh
- name: Build with PyInstaller
shell: bash
run: |
if [ "$RUNNER_OS" == "Windows" ]; then SEP=";"; else SEP=":"; fi
pyinstaller --onefile \
--collect-all pkg_resources \
--collect-all setuptools \
--hidden-import pkg_resources \
--hidden-import setuptools \
--hidden-import jaraco.text \
--hidden-import jaraco.functools \
--hidden-import jaraco.context \
--hidden-import more_itertools \
--hidden-import packaging \
--hidden-import platformdirs \
--collect-all onionshare_cli \
--collect-all flask_socketio \
--collect-all engineio \
--collect-all socketio \
--collect-all eventlet \
--collect-all gevent \
--add-data "voxvera/locales${SEP}voxvera/locales" \
--add-data "voxvera/src${SEP}voxvera/src" \
--add-data "voxvera/templates${SEP}voxvera/templates" \
--add-data "voxvera/resources/tor${SEP}voxvera/resources/tor" \
--add-data "support-matrix.json${SEP}." \
--add-data "requirements.txt${SEP}." \
--name "${{ matrix.artifact_name }}" \
voxvera/cli.py
- name: Validate built binary contract surface (Linux/macOS)
if: matrix.os != 'windows-latest'
shell: bash
run: |
./dist/${{ matrix.artifact_name }} platform-status --json
./dist/${{ matrix.artifact_name }} doctor --json
./dist/${{ matrix.artifact_name }} autostart status --json
- name: Validate built binary contract surface (Windows)
if: matrix.os == 'windows-latest'
shell: pwsh
run: |
& ".\dist\${{ matrix.artifact_name }}" platform-status --json
& ".\dist\${{ matrix.artifact_name }}" doctor --json
& ".\dist\${{ matrix.artifact_name }}" autostart status --json
- name: Build .deb (Linux)
if: matrix.os == 'ubuntu-22.04'
run: |
mkdir -p voxvera/resources/bin
cp dist/${{ matrix.artifact_name }} voxvera/resources/bin/voxvera-linux-x86_64
chmod +x packaging/build_deb.sh
./packaging/build_deb.sh dist/${{ matrix.artifact_name }}
- name: Build AppImage (Linux)
if: matrix.os == 'ubuntu-22.04'
run: |
mkdir -p voxvera/resources/bin
cp dist/${{ matrix.artifact_name }} voxvera/resources/bin/voxvera-linux-x86_64
chmod +x packaging/build_appimage.sh
./packaging/build_appimage.sh dist/${{ matrix.artifact_name }}
- name: Validate Linux release artifacts
if: matrix.os == 'ubuntu-22.04'
shell: bash
run: |
chmod +x scripts/validate-release-artifacts.sh
./scripts/validate-release-artifacts.sh
- name: Build Flatpak (Linux)
if: matrix.os == 'ubuntu-22.04'
run: |
mkdir -p voxvera/resources/bin
cp dist/${{ matrix.artifact_name }} voxvera/resources/bin/voxvera-linux-x86_64
sudo apt-get update
sudo apt-get install -y flatpak flatpak-builder
chmod +x packaging/build_flatpak.sh
./packaging/build_flatpak.sh dist/${{ matrix.artifact_name }} || echo "Flatpak build failed"
- name: Build .dmg (macOS)
if: matrix.os == 'macos-latest'
run: |
mkdir -p voxvera/resources/bin
cp dist/${{ matrix.artifact_name }} voxvera/resources/bin/voxvera-macos-x86_64
chmod +x packaging/build_dmg.sh
./packaging/build_dmg.sh dist/${{ matrix.artifact_name }}
- name: Upload artifacts
uses: actions/upload-artifact@v4
with:
name: binaries-${{ matrix.os }}
path: |
dist/${{ matrix.artifact_name }}
voxvera/resources/bin/*.deb
voxvera/resources/bin/*.dmg
voxvera/resources/bin/*.AppImage
voxvera/resources/bin/*.flatpak
publish:
name: Create GitHub Release
needs: build
runs-on: ubuntu-latest
if: startsWith(github.ref, 'refs/tags/')
permissions:
contents: write
steps:
- name: Download all artifacts
uses: actions/download-artifact@v4
with:
path: artifacts
- name: Flatten artifacts for release
run: |
mkdir -p release_assets
find artifacts -type f -exec cp {} release_assets/ \;
ls -R release_assets/
- name: Release
uses: softprops/action-gh-release@v2
with:
files: |
release_assets/*
fail_on_unmatched_files: false
overwrite: true
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+12 -49
View File
@@ -2,63 +2,26 @@ name: CI
on:
push:
branches: [ main ]
branches: [main]
pull_request:
jobs:
lint-test:
static-client:
runs-on: ubuntu-latest
timeout-minutes: 15
timeout-minutes: 10
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: "22"
- uses: actions/setup-python@v5
with:
python-version: '3.12'
- name: Install dependencies
run: |
sudo apt-get update
sudo apt-get install -y tor
python -m pip install --upgrade pip
pip install flake8
pip install -e ".[test]"
pip install git+https://github.com/onionshare/onionshare.git#subdirectory=cli
- name: Lint
run: flake8 voxvera tests --exclude=voxvera/vendor --ignore=E501,W503,W293,E402,E306,E704,E261,F841,E302,F401,E401,F541
- name: Test
run: pytest tests/ -v
- name: Platform smoke
run: bash scripts/platform-smoke.sh linux-cli
platform-contract:
runs-on: ${{ matrix.os }}
timeout-minutes: 15
strategy:
fail-fast: false
matrix:
include:
- os: macos-latest
smoke_target: macos-cli
- os: windows-latest
smoke_target: windows-cli
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: '3.12'
- name: Install dependencies
shell: bash
python-version: "3.12"
- name: Install Python test dependencies
run: |
python -m pip install --upgrade pip
pip install -e ".[test]"
- name: Verify smoke target listing
shell: bash
run: bash scripts/platform-smoke.sh list
- name: Validate platform-status JSON
shell: bash
run: python -m voxvera.cli platform-status --json
- name: Validate doctor JSON
shell: bash
run: python -m voxvera.cli doctor --json
- name: Validate autostart JSON
shell: bash
run: python -m voxvera.cli autostart status --json
- name: Check frontend JavaScript
run: node --check site/nostr/nostr-client.js
- name: Run tests
run: pytest -q
-31
View File
@@ -1,31 +0,0 @@
name: E2E
on:
push:
pull_request:
jobs:
e2e:
runs-on: ubuntu-latest
timeout-minutes: 20
steps:
- uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.12'
- name: Install dependencies
run: |
sudo apt-get update
sudo apt-get install -y tor
python -m pip install --upgrade pip
pip install -e ".[e2e]"
- name: Run end-to-end tests
run: ci/test-e2e.sh
continue-on-error: true
- name: Upload logs
if: always()
uses: actions/upload-artifact@v4
with:
name: ci-logs
path: ci-logs/
+23 -51
View File
@@ -1,59 +1,31 @@
# Temporary files
*.tmp
tmp*/
# Python
__pycache__/
*.py[cod]
.pytest_cache/
*.egg-info/
.venv/
venv/
.venv
!voxvera/
!voxvera/resources/**
!voxvera/src/**
# OS and editor files
# Node/browser tooling
node_modules/
# Playwright e2e output
test-results/
playwright-report/
playwright/.cache/
# Build and local output
build/
dist/
ci-logs/
# OS/editor noise
.DS_Store
Thumbs.db
*~
*.swp
__pycache__/
*.pyc
# Build and distribution artifacts
dist/
build/
*.egg-info/
# Electron app artifacts
gui/electron/node_modules/
gui/electron/dist/
gui/electron/build/
gui/electron/out/
# Generated host directories
host/*
!host/voxvera/
# CI logs
ci-logs/
# Onionshare logs and session files
# Local browser/debug artifacts
*.log
*.onionshare-session
gui/electron/package-lock.json
voxvera/src/config.json
voxvera/src/index.html
voxvera/src/nostr.html
voxvera/src/qrcode-content.png
voxvera/src/qrcode-tear-offs.png
# PyInstaller
*.spec
dist_bin/
voxvera/resources/bin/*
!voxvera/resources/bin/.gitkeep
site/download/*.zip
!site/download/voxvera-source.zip
site/download/*.exe
site/download/*.deb
site/download/*.dmg
site/download/*.AppImage
site/download/*.flatpak
site/download/voxvera-linux
site/download/voxvera-linux-x86_64
*.pdf
.vercel
+39 -31
View File
@@ -1,42 +1,50 @@
# AI Agent Instructions for VoxVera
# AI Agent Instructions For VoxVera
This guide is for AI agents (like Gemini, Claude, or GPT) contributing to the VoxVera project. Follow these protocols to maintain the architectural integrity and multi-language support.
`main` is the Nostr static-client branch. The old Tor/OnionShare CLI application is preserved on `legacy-tor`.
## Core Mandates
## Current Architecture
1. **Security-First**: VoxVera is a Tor-based tool. Never suggest features that leak IP addresses or use non-Tor external resources (CDNs, etc.).
2. **Local-First**: All assets (fonts, dependencies, binaries) must be self-contained within the `voxvera/` package to support the Universal Mirroring model.
3. **Tokenized UI**: Never hardcode user-facing strings. Always add them to `voxvera/locales/en.json` and use the `t('cli.token')` helper.
4. **Markdown Redaction**: Use `~~text~~` in locale JSONs for strike-through effects. Both the build system and the JS engine handle the conversion to `<span class="redacted">` automatically.
5. **Visual Width Testing**: When modifying UI or adding languages, verify that long or complex strings (e.g., Hindi ligatures or CJK characters) do not exceed the visual unit limits defined in the CLI.
- Active frontend: `site/` (`index.html`, `nostr-client.js`, `nostr-client.css`, `locales.js`)
- Bulletin board: `site/board.html` + `site/board.js` (standalone page listing recent flyers from the relays; escapes untrusted relay content and rejects non-http(s) link URLs)
- Static deployment root: `site`
- Browser dependencies: vendored under `site/vendor/`
- Legacy path: `site/nostr/index.html` is a redirect stub forwarding old `/nostr/` poster URLs and QR codes to the root
- Python helper package: `voxvera/nostr/`
- Design plan: `docs/nostr-static-client-spec.md`
## Localization Protocol
## Guardrails
When adding a new language or updating an existing one:
- **CLI/Flyers**: Update `voxvera/locales/{lang}.json`. Include `meta`, `cli`, `web`, and `landing` categories.
- **Landing Page**:
- Directly update the `const locales` object in `site/index.html`.
- **Crucial**: Run `voxvera build-site` to generate the latest portable bundle and refresh the pre-rendered HTML.
- **Documentation**:
- Master templates live in `docs/templates/`.
- Localized overrides live in `voxvera/locales/{lang}/docs/`.
- **Crucial**: After any change to locales or templates, you MUST run `voxvera build-docs` to synchronize the output in `docs/{en,es,de}/`.
- Do not reintroduce the legacy Tor CLI, OnionShare runtime, installer, Electron manager, bundled Tor binaries, generated old flyer site, or packaging workflows on `main`.
- Keep the Nostr client static and host-agnostic.
- Do not load frontend dependencies from CDNs.
- Treat Nostr event content as untrusted. Escape rendered content and reject unsafe schema input.
- Preserve print behavior: app controls must not print or shift the flyer sheet in print output.
- Preserve the old flyer visual language unless the user explicitly asks for a redesign.
- Paper size (US Letter / A4) is a local print/view preference (`localStorage`), defaulted from the browser locale region. Never write it into the Nostr event — a flyer must reprint on either size without changing the source event.
## Universal Mirroring
## Localization
VoxVera propagates through its own flyers.
- Every `voxvera build` and `voxvera build-site` generates `voxvera-portable.zip`.
- If you modify the core source code, ensure the `bundle_portable` function in `voxvera/cli.py` still correctly captures all necessary directories (especially `vendor/`, `locales/`, and `resources/`).
- Use `site/locales.js` for flyer content defaults.
- Use `NOSTR_UI` in `site/nostr-client.js` for editor/viewer controls and Nostr-specific labels.
- Add translations for every supported language when adding user-facing strings.
- Check right-to-left languages when touching layout.
## Verification Checklist
## Verification
Before finishing a task, ensure you have:
1. Run unit tests: `pytest tests/test_cli.py`.
2. Verified the localization: `voxvera --lang {lang} check`.
3. Rebuilt the documentation: `voxvera build-docs`.
4. Synchronized the public site: `voxvera build-site`.
5. Verified the portable bundle exists: `ls -l voxvera/host/*/download/voxvera-portable.zip` and `ls -l site/download/voxvera-portable.zip`.
Run:
---
```bash
node --check site/nostr-client.js
pytest -q
```
Follow these rules to ensure VoxVera remains a robust, viral, and decentralized tool for truth.
For visual or print changes, also run a local static server and inspect the site root (`/`) in a browser.
Cross-browser end-to-end tests live in `e2e/` (Playwright; Chromium, Firefox, WebKit, plus mobile emulations). Run them after changes that touch rendering, print, key generation, URL/redirect handling, or the loading state:
```bash
npm install && npx playwright install
npm run test:e2e
```
WebKit/Safari on Linux needs `sudo npx playwright install-deps` once. See `e2e/README.md`. Test tooling is a dev dependency only — it must not pull runtime frontend dependencies from CDNs or otherwise weaken the static, host-agnostic client.
+30 -38
View File
@@ -1,48 +1,40 @@
# Contributing to VoxVera
# Contributing To VoxVera
Thank you for your interest in contributing to VoxVera! This project aims to be a global, censorship-resistant tool, and your help—especially with translations—is vital.
VoxVera `main` is a static Nostr client. Keep contributions focused on the browser editor/viewer, Nostr event validation, printable flyer rendering, and static deployment.
## Adding a New Language
## Frontend
VoxVera uses a centralized token system for the CLI and Web components, and a template-based system for Documentation. To add a new language (e.g., French/`fr`), follow this checklist:
- Edit the active app under `site/nostr/`.
- Keep dependencies vendored under `site/nostr/vendor/`; do not rely on CDNs.
- Preserve viewer mode as a flyer-first experience.
- Keep editor, load, print, language, and other controls hidden from print output.
- Verify print layout after changes that affect the flyer surface.
### 1. The Token File
Create a new JSON file in `voxvera/locales/{lang_code}.json`.
- Use `en.json` as your master template.
- **`meta`**: Include the native language name and a flag emoji.
- **`cli`**: Translate all strings used in the terminal interface.
- **`web`**: Translate strings used on the generated landing pages and flyers.
- **`landing`**: Translate the specific content for the official VoxVera website.
- **Formatting**: You can use Markdown-style strike-throughs (`~~redacted text~~`) in any of these strings; they will be automatically converted to the stylized "redacted" effect on the flyers.
## Localization
### 2. The Landing Page
The main landing page is generated from the shared template and locale files.
- Add your language in `voxvera/locales/{lang_code}.json`.
- Do **not** edit `site/index.html` directly; it is generated output.
- Run `voxvera build-site` to refresh the public assets and inject your new locale into the generated HTML.
The static client currently uses `site/nostr/locales.js` plus the `NOSTR_UI` table in `site/nostr/nostr-client.js`.
### 3. Documentation
VoxVera uses the **Doc-Sync Engine** to keep manuals in sync.
- Create localized Markdown files in `voxvera/locales/{lang_code}/docs/`.
- Use the templates in `docs/templates/` as your guide.
- You can use `cli.token_name` to reference terminal commands automatically.
When adding user-facing text:
### 4. Build and Verify
Run the following commands to verify your changes:
- `voxvera --lang {lang_code} check` (Verify CLI translation)
- `voxvera build-docs` (Generate localized manuals)
- `voxvera build-site` (Synchronize the public website and generate the latest portable bundle)
- Open the generated `site/index.html` in a browser and test the language switcher.
- Add translations for every supported language.
- Check right-to-left languages in the browser where layout may be affected.
- Keep side-tab strings short enough for tear-off strips.
## Code Contributions
- **Dependencies**: if you add a new Python library to `requirements.txt`, you MUST run `voxvera vendorize` to include it in the portable distribution.
- **Layout Integrity**: VoxVera uses visual width validation. If you add new UI elements, ensure they respect the physical boundaries of an 8.5"x11" flyer.
- **Tests**: Ensure all tests pass: `pytest tests/`. Run the integrity suite specifically when modifying locales: `pytest tests/test_integrity.py`.
- **Recommended local check**: Run `bash scripts/check.sh` before opening a PR. It mirrors the main lint/test/build checks in one command.
- **Generated artifacts**: Treat `voxvera/resources/bin/` as local build output, not source files. Release binaries belong in GitHub Releases, not hand-edited repo state.
- **Style**: Follow the existing coding style (PEP 8 for Python).
- **Documentation**: If adding a new feature, update the master templates in `docs/templates/` and run `voxvera build-docs`.
## Nostr Schema
---
Python validation helpers live in `voxvera/nostr/`. Keep the schema conservative:
Together, we can ensure that truth remains accessible to everyone, everywhere.
- Reject raw HTML in user-supplied flyer fields.
- Reject unsupported URL schemes.
- Keep attachments out of V1 events unless the spec is deliberately expanded.
## Verification
Run:
```bash
node --check site/nostr/nostr-client.js
pytest -q
```
For UI work, also run a local static server and inspect `/nostr/` in a browser.
-24
View File
@@ -1,24 +0,0 @@
FROM python:3.11-slim
# Experimental container path: Linux systemd remains the supported
# persistent-host deployment target.
# Install system dependencies (only runtime)
RUN apt-get update && apt-get install -y \
tor onionshare-cli \
&& rm -rf /var/lib/apt/lists/*
# Copy VoxVera source
COPY . /opt/voxvera
WORKDIR /opt/voxvera
# Install VoxVera and its Python dependencies
RUN pip install .
# Prepare flyers volume
RUN mkdir /flyers
ENV VOXVERA_DIR=/flyers
VOLUME /flyers
# Seed a default config when the volume is empty, then retry startup periodically.
CMD ["sh", "-lc", "mkdir -p /flyers && if [ ! -f /flyers/config.json ]; then cp /opt/voxvera/voxvera/src/config.json /flyers/config.json; fi && voxvera quickstart --non-interactive && while true; do sleep 300; voxvera start-all || true; done"]
-5
View File
@@ -1,5 +0,0 @@
include voxvera/templates/**
include voxvera/src/**
include voxvera/resources/**
include voxvera/locales/**
include voxvera/resources/bin/**
+60 -62
View File
@@ -1,92 +1,90 @@
# VoxVera
**Anonymous Information Distribution Engine**
VoxVera is a static, Nostr-powered flyer client.
Generate printable flyers with QR codes linking to Tor (.onion) hidden services. VoxVera is built for activists, journalists, and anyone who needs to spread a message securely and anonymously.
The active app lives at the site root ([`site/`](site/)). It lets anyone author flyer content, publish it as a public Nostr event, and re-render or reprint the flyer later from a Nostr address or event ID — no application server. The frontend is intentionally self-contained: Nostr relays store the content, and any static host can serve the client.
---
The previous Tor/OnionShare CLI version is preserved on the `legacy-tor` branch.
## Installation
## Features
VoxVera is designed for maximum portability and censorship resistance.
- **Author and publish.** Fill in the flyer fields and publish them as a Nostr `30078` parameterized replaceable event. Republishing with the same flyer name replaces the previous version.
- **Anonymous by default, your identity if you want it.** The editor signs flyers under one of four identities: an **anonymous** per-device key (default, no setup), a **NIP-07 browser extension** (your secret never touches the page), an **imported `nsec`**, or a **NIP-46 remote signer** (paste a `bunker://` link or scan a `nostrconnect://` QR with your signer app — your secret stays in the app, the browser holds only an ephemeral key; session-only). An imported key signs in-memory for the session; tick "Remember on this device" to keep it, encrypted with a PIN (PBKDF2 → AES-GCM) — the plaintext secret is never stored. A short PIN is a convenience lock, not protection against a targeted attacker (see the [spec](docs/nostr-static-client-spec.md#publishing-identity)); the extension and remote-signer paths are stronger.
- **Publish confirmation.** After signing and publishing, a modal shows the new flyer's URL to copy, so authors know they're done and where to find it (localized, like everything else).
- **Edit, re-publish, and delete your flyers.** Because flyers are replaceable events, the author can edit one in place (same key + Flyer Name keeps the same URL), re-publish it as a keep-alive so relays don't age it out, or delete it. Delete publishes a replaceable **tombstone** (so VoxVera hides it even where relays ignore deletions) **and** a NIP-09 deletion request — best-effort, author-only.
- **Import / export a flyer design.** Save the current flyer as a portable `.json` file and load it back later — or hand it to someone else. The design file holds the content and relay list but **nothing identity-bound** (no npub, address, or signature; those are generated at publish), so a recipient can import it and publish under their own key. Importing asks for confirmation before replacing what's in the editor.
- **Open from a link or ID.** Load a flyer from an `naddr`, `nevent1`, `note1`, raw 64-char event ID, or `nostr:` URL. The lookup field tolerates copy/paste whitespace and newlines, so an event ID copied off a printed tear-off (where it wraps across two lines) still resolves.
- **Short, scannable poster URLs.** Each poster URL is a standard NIP-19 `naddr` carrying a single relay hint, placed in the URL `#fragment` (no `?addr=` query). Shorter URLs make the tear-off QR code easier to scan. Older relay-list `naddr`s and `?addr=` URLs still resolve.
- **Tear-off tabs.** The printable flyer has ten tear-off tabs. Each tab is labeled with the flyer's **title** (auto-sized to be as large as fits), a clickable **"Open & reprint this flyer"** link (live in the printed PDF), a QR code, and a **"Reopen at VoxVera.org — Event ID:"** line with the full event ID so anyone can re-find and reprint the flyer by typing it in. Localized in every language.
- **Loading state on shared links.** Opening a poster/event link shows a localized "Loading content…" placeholder (and a "Could not load this flyer." state on failure) instead of the default flyer; the default sample content appears only on the bare site URL.
- **14 languages with RTL support.** Flyer content and UI are localized; right-to-left scripts render correctly. Letter-spacing is applied per script so cursive (Arabic/Persian) and combining (Devanagari) scripts are not broken — see [the spec](docs/nostr-static-client-spec.md#letter-spacing-by-script).
- **US Letter and A4.** Print size defaults to the right paper for the visitor's country (from the browser locale's region — `en-US` → Letter, `en-GB` → A4, no geolocation), with a manual override. Paper size is a local print preference and is never written into the event. See the [spec](docs/nostr-static-client-spec.md#print-paper-size).
- **Fits-the-page editing.** Fields that would overflow the printable sheet are rejected as you type, with an inline error under the affected field. See the [field length cheat sheet](docs/flyer-field-limits.md) for how much text fits each field per language and paper size.
- **QR codes.** The tear-off QR points at the poster URL (re-open and reprint); the main flyer QR points at the creator's content URL.
- **Bulletin board (members-only, trust-filtered).** A small screen-only link below the flyer preview (outside the printed sheet, never printed) opens a spreadsheet-style page of the most recent flyers found on the relays — title, link, posting npub, language, date, and event ID (with a copy button) — sortable by any column. Viewing the board requires connecting a Nostr identity — via a NIP-07 browser extension, by pasting a private key (`nsec`, decoded in-page and never stored), or by creating a new key (revealed so you can save it). The board then shows only flyers from authors in your **web of trust** (your NIP-02 follow graph), with a "Show all" opt-out. A brand-new key with no follows is seeded from a curated trust anchor so the board is never an unmoderated firehose. On your own flyers the board offers inline **Edit / Re-broadcast / Delete**; on others' it offers **Report** (a public, signed NIP-56 report with a category and optional reason, which also hides the flyer for you) and a local **Block** (a per-device hide list). Connecting is not required to author or print flyers, which stay fully anonymous. See the [roadmap](docs/roadmap.md) for the phased trust model.
- **Mobile-friendly.** The flyer preview shrinks to fully fit the screen width (no side-scrolling), the editor and viewer are single-column with large tap targets, and the bulletin board collapses to a card per flyer with a per-row **Details** toggle on narrow screens.
- **Honest safety page.** A localized **[Safety & privacy](https://voxvera.org/safety)** page (linked from the editor and board) explains in plain language what VoxVera protects and — just as importantly — what it does *not*: relays see your IP when you publish or browse, the anonymous key is stored unencrypted in your browser, a short PIN won't stop a targeted attacker, and published events are public and effectively permanent. Plus operational tips (Tor/VPN, disposable keys, signer apps). No overpromising to the people most likely to rely on it.
- **Self-contained.** No build step and no CDNs — Nostr and QR libraries are vendored under `site/vendor/`.
Linux with systemd is the supported persistent-host deployment target.
Windows, macOS, Docker, Flatpak, AppImage, Homebrew, and Chocolatey remain experimental until their background Tor hosting and auto-recovery paths are validated end-to-end.
## What Is In `main`
See [docs/platform-support-matrix.md](docs/platform-support-matrix.md) for the canonical platform status table and [docs/roadmap-platform-parity.md](docs/roadmap-platform-parity.md) for the parity plan.
For the supported Linux hosting path, use [docs/linux-hosting-validation.md](docs/linux-hosting-validation.md) as the operational validation runbook.
- `site/index.html`, `site/nostr-client.js`, `site/nostr-client.css`, `site/locales.js`: static editor/viewer client
- `site/board.html`, `site/board.js`: bulletin-board page listing recent flyers from the relays
- `site/vendor/`: vendored browser dependencies for Nostr and QR generation
- `site/nostr/index.html`: redirect stub so legacy `/nostr/` poster URLs and QR codes still resolve
- `site/CNAME`: custom-domain target
- `voxvera/nostr/`: small Python schema/validation helpers
- `docs/nostr-static-client-spec.md`: design notes and development plan
- `docs/flyer-field-limits.md`: per-language field length cheat sheet
- `docs/roadmap.md`: known issues and future development directions
### 1. Standalone Binaries (Recommended)
Download the executable for your OS:
- 🐧 [**Linux**](https://github.com/PR0M3TH3AN/VoxVera/releases/latest/download/voxvera-linux)
- 🪟 [**Windows (Experimental)**](https://github.com/PR0M3TH3AN/VoxVera/releases/latest/download/voxvera-windows.exe)
- 🍏 [**macOS (Experimental)**](https://github.com/PR0M3TH3AN/VoxVera/releases/latest/download/voxvera-macos)
## Local Development
### 2. Universal Mirroring (The "Viral" Method)
If you found a physical VoxVera flyer, scan it and click **"Download"**. You will receive a `voxvera-portable.zip` containing the full tool, all dependencies, and all 14 languages—ready to run offline.
Run the static site from the repo root:
### 3. One-Line Installer (Linux/macOS)
```bash
curl -fsSL https://raw.githubusercontent.com/PR0M3TH3AN/VoxVera/main/install.sh | bash
```
On Linux, this now installs the recurring `systemd --user` recovery timer used to retry hidden-service startup after boot or offline periods. On macOS, the installer path is still experimental.
### 4. Developer / Python Install
```bash
pip install .
voxvera vendorize # Optional: pull dependencies locally for offline use
python3 -m http.server 8768 --directory site
```
### 5. Local Validation
Run the full local validation sweep with:
```bash
bash scripts/check.sh
Then open:
```text
http://127.0.0.1:8768/
```
This runs linting, Python tests, Electron smoke tests, dependency checks, and the docs/site rebuild steps used during development.
---
No build command is required for the frontend.
## Key Features
## Vercel
* **Universal Mirroring**: Every flyer acts as a mirror for the tool itself. The "Download" button provides a portable version of VoxVera, creating a decentralized distribution network.
* **Standalone Binaries**: Zero-install executables for high-security environments.
* **Global Multi-Script Support**: Native support for 14 languages including **Arabic (RTL)**, **Hebrew (RTL)**, **Hindi (Devanagari)**, **Japanese/Chinese (CJK)**, and **Russian (Cyrillic)**.
* **Tor-Safe Architecture**: 100% static HTML flyers. Works perfectly in Tor "Safest" mode with **JavaScript completely disabled**.
* **Integrated Server Manager**: `voxvera manage` provides an interactive UI to handle multiple flyers, monitor Tor bootstrapping, and manage persistent .onion URLs.
* **Secure Migration**: Bulk export and import of flyers and their unique Tor identity keys via `~/voxvera-exports/`.
Point Vercel at this repository on `main`.
---
- Framework preset: Other
- Root directory: repo root
- Build command: leave empty
- Output directory: `site`
## Documentation
The client is served from the domain root (`site/index.html`). `site/nostr/index.html` is a redirect stub that forwards the legacy `/nostr/` path to the root while preserving the query/fragment, so older poster URLs and printed QR codes still resolve.
VoxVera is available in multiple languages. Select your preferred language for the detailed usage guide:
## Verification
| Language | Documentation | Contributing | Agent Guide |
| :--- | :--- | :--- | :--- |
| 🇺🇸 **English** | [usage.md](docs/en/usage.md) | [CONTRIBUTING.md](docs/en/CONTRIBUTING.md) | [AGENTS.md](docs/en/AGENTS.md) |
| 🇪🇸 **Español** | [usage.md](docs/es/usage.md) | [CONTRIBUTING.md](docs/es/CONTRIBUTING.md) | [AGENTS.md](docs/es/AGENTS.md) |
| 🇩🇪 **Deutsch** | [usage.md](docs/de/usage.md) | [CONTRIBUTING.md](docs/de/CONTRIBUTING.md) | [AGENTS.md](docs/de/AGENTS.md) |
| 🇫🇷 **Français** | [usage.md](docs/fr/usage.md) | [CONTRIBUTING.md](docs/fr/CONTRIBUTING.md) | [AGENTS.md](docs/fr/AGENTS.md) |
| 🇷🇺 **Русский** | [usage.md](docs/ru/usage.md) | [CONTRIBUTING.md](docs/ru/CONTRIBUTING.md) | [AGENTS.md](docs/ru/AGENTS.md) |
| 🇮🇱 **עברית** | [usage.md](docs/he/usage.md) | [CONTRIBUTING.md](docs/he/CONTRIBUTING.md) | [AGENTS.md](docs/he/AGENTS.md) |
| 🇸🇦 **العربية** | [usage.md](docs/ar/usage.md) | [CONTRIBUTING.md](docs/ar/CONTRIBUTING.md) | [AGENTS.md](docs/ar/AGENTS.md) |
| 🇯🇵 **日本語** | [usage.md](docs/ja/usage.md) | [CONTRIBUTING.md](docs/ja/CONTRIBUTING.md) | [AGENTS.md](docs/ja/AGENTS.md) |
| 🇮🇳 **हिन्दी** | [usage.md](docs/hi/usage.md) | [CONTRIBUTING.md](docs/hi/CONTRIBUTING.md) | [AGENTS.md](docs/hi/AGENTS.md) |
| 🇰🇪 **Kiswahili** | [usage.md](docs/sw/usage.md) | [CONTRIBUTING.md](docs/sw/CONTRIBUTING.md) | [AGENTS.md](docs/sw/AGENTS.md) |
```bash
node --check site/nostr-client.js # client syntax
pytest -q # Nostr source schema
```
---
### Cross-browser end-to-end tests
## Roadmap (v0.2.0)
[Playwright](https://playwright.dev) smoke tests run the client on Chromium, Firefox, and WebKit (Safari's engine), plus Android/iOS mobile emulations — covering rendering, the `@media print` path, WebCrypto key generation, the `/nostr/` redirect, and the loading state.
We are actively working on:
- **PGP Signing**: Cryptographic proof of tool integrity.
- **Nostr Integration**: Automated social amplification.
- **Template Gallery**: Visual styles for protests, alerts, and art.
- **Self-Healing Network**: Automated decentralized updates.
```bash
npm install
npx playwright install # download the browser engines
npm run test:e2e
```
See [ROADMAP-v0.2.0.md](docs/roadmap-v0.2.0.md) for details.
See [`e2e/README.md`](e2e/README.md) for per-engine coverage and the one-time Linux step for WebKit (`sudo npx playwright install-deps`).
---
The Python tests only cover the Nostr source schema. The frontend is static; the Playwright suite covers engine behavior, but real Safari/iOS print and clipboard behavior is still worth a manual pass before a release.
## License
-104
View File
@@ -1,104 +0,0 @@
# VoxVera Release Process
**⚠️ ATTENTION AI AGENTS (CRITICAL WORKFLOW):**
Do **NOT** automatically package, tag, or push a new release after completing a set of changes. Releases should **ONLY** be triggered when the user explicitly requests one (e.g., "Package a release now" or "Let's release this").
Instead of releasing immediately, you must append a summary of your completed work to the `UPCOMING_RELEASE.md` file. This allows development to span multiple context sessions and ensures that new releases contain a substantial amount of value. When a release is finally requested, use the contents of `UPCOMING_RELEASE.md` to format the GitHub Release notes, and then clear the document for the next cycle.
This document outlines the mandatory steps to perform before every release to ensure code quality, cross-language integrity, and professional distribution assets.
## 1. Pre-Flight Checks (Quality Assurance)
Before any release, the codebase must pass all internal quality checks **without taking any shortcuts**. All tests must be rigorous, use real data where appropriate, and passing them should be a true mark of quality.
### Run Tests
Ensure all core CLI, E2E, and Integrity tests pass:
```bash
pytest tests/
```
*Note: The `test_integrity.py` check is critical as it verifies that all 14+ language locales have synchronized keys and all binary bundles are 100% self-contained.*
### Run Linting
Ensure the code adheres to style guidelines (no trailing whitespace, proper spacing, etc.):
```bash
# Using flake8 (excluding vendored dependencies)
flake8 voxvera/ --exclude=voxvera/vendor/
```
## 2. Update & Generate Localized Assets
Before releasing, you must ensure that **all documentation accurately reflects the new features and functions** introduced in the release.
All documentation and site templates must be synchronized with the translation system. This ensures that any changes to documentation are reflected across all 14+ supported languages.
### Synchronize Documentation
If you have modified any documentation templates in `docs/templates/` (which you should, to cover new features), you **must** use the translation system to regenerate the localized documentation before release:
```bash
# Regenerate docs/ folders for all languages from templates and locales
python3 -m voxvera.cli build-docs
```
### Synchronize Site Assets
The main `site/` directory (including QRs, HTML, and portable Zips) must also be refreshed to include the latest binary names and locale strings:
```bash
# Refresh site/ directory
python3 -m voxvera.cli build-site
```
## 3. Build Distribution Binaries
Linux CLI delivery is the supported deployment target today. Other package formats should be treated as experimental release artifacts until their Tor/OnionShare background-hosting behavior is validated end-to-end.
Capture platform evidence before promoting any support tier: run `bash scripts/platform-smoke.sh linux-cli` locally for the supported Linux path, and keep CI/workflow evidence aligned with the same command.
As other runtime targets mature, use `bash scripts/platform-smoke.sh macos-cli`, `bash scripts/platform-smoke.sh windows-cli`, or `bash scripts/platform-smoke.sh docker-cli` on their native environments before changing their support labels.
### Standard Binary
Generates an architecture-specific binary (e.g., `voxvera-linux-x86_64`) in `voxvera/resources/bin/`.
```bash
./scripts/build_binaries.sh
```
This directory is local build output only. Do not treat old files in `voxvera/resources/bin/` as canonical release history; the GitHub Release artifacts are the publish surface.
### AppImage (Linux)
Wraps the standard binary into a self-contained AppImage.
```bash
./packaging/build_appimage.sh
```
Experimental package surface.
### Flatpak (Linux)
Generates a standalone `.flatpak` bundle. Requires `flatpak-builder`.
```bash
./packaging/build_flatpak.sh
```
Experimental package surface.
### Debian Package (Linux)
Generates a `.deb` package for Debian/Ubuntu systems.
```bash
./packaging/build_deb.sh
```
Experimental package surface unless its runtime dependencies and recovery behavior are explicitly validated for the release.
### DMG (macOS)
Generates a `.dmg` installer for macOS (must be run on macOS).
```bash
./packaging/build_dmg.sh
```
Experimental package surface.
## 4. Release Execution
1. **Version Bump:** Update `__version__` in `voxvera/__init__.py` and `version` in `pyproject.toml`.
2. **Commit & Tag:**
```bash
git add .
git commit -m "chore: release vX.Y.Z"
git tag -a vX.Y.Z -m "VoxVera vX.Y.Z"
git push origin main --tags
```
## 5. Automated Releases (GitHub Actions)
The repository is configured with a **Build Standalone Binaries** workflow that automatically runs when a new tag (`v*`) is pushed. This workflow:
- Builds native executables for **Linux**, **Windows (.exe)**, and **macOS**.
- Automatically attaches these binaries to the corresponding GitHub Release.
This ensures that Windows users receive a professional `voxvera-windows.exe` rather than having to rely on `.bat` or `.sh` scripts.
-1
View File
@@ -1 +0,0 @@
# Upcoming Release Notes
-218
View File
@@ -1,218 +0,0 @@
#!/usr/bin/env bash
set -euo pipefail
# Robustness: ensure we are in the project root
cd "$(dirname "$0")/.."
LOG_DIR="$(pwd)/ci-logs"
mkdir -p "$LOG_DIR"
# Use a subshell for tee to avoid issues with some shell environments
exec > >(tee "$LOG_DIR/run.log") 2>&1
echo "Starting E2E verification at $(date)"
# Install VoxVera
if [ -n "${VOXVERA_BIN:-}" ] && [ -f "$VOXVERA_BIN" ]; then
voxvera_cmd="$VOXVERA_BIN"
echo "Using provided VoxVera binary: $voxvera_cmd" >&2
elif command -v voxvera >/dev/null 2>&1; then
voxvera_cmd="$(command -v voxvera)"
echo "Using existing VoxVera on PATH: $voxvera_cmd" >&2
else
echo "Installing VoxVera in editable mode..."
python3 -m pip install --break-system-packages --no-build-isolation -e ".[e2e]"
voxvera_cmd="$(command -v voxvera || echo "$HOME/.local/bin/voxvera")"
fi
echo "VoxVera command: $voxvera_cmd"
echo "Checking platform contract before workflow..."
bash scripts/platform-smoke.sh linux-cli
# Generate demo flyer
echo "Initializing demo flyer..."
"$voxvera_cmd" --lang en init --template voxvera <<EOI
DemoUser
voxvera
EOI
config_path="$HOME/host/voxvera/config.json"
if [ ! -f "$config_path" ]; then
echo "CRITICAL: Expected config file not found after init: $config_path" >&2
exit 1
fi
echo "Building demo flyer..."
"$voxvera_cmd" --lang en --config "$config_path" build
# Verify build output exists in host/
folder_name="voxvera"
host_dir="$HOME/host/$folder_name"
if [ ! -d "$host_dir" ]; then
echo "CRITICAL: Host directory $host_dir not found!" >&2
ls -R "$HOME/host/" || true
exit 1
fi
ls -R "$host_dir" >>"$LOG_DIR/tree.txt"
# Verify essential files
for f in index.html config.json; do
if [ ! -f "$host_dir/$f" ]; then
echo "CRITICAL: Missing $f in $host_dir" >&2
exit 1
fi
done
echo "Build output verified in $host_dir"
# Run pytest unit tests
echo "Running pytest unit tests..."
python3 -m pytest tests/ -v 2>&1 | tee "$LOG_DIR/pytest.log"
# Optional network tests
if [ "${VOXVERA_E2E_OFFLINE:-}" != "1" ]; then
echo "Starting network-dependent tests..."
# GitHub Actions Ubuntu runners have Tor pre-installed and running as a service.
# We stop it to ensure we can run our own instance with known configuration on default ports.
echo "Stopping system Tor service if running..."
sudo systemctl stop tor || true
# Kill any lingering tor processes
sudo pkill -x tor || true
echo "Starting a fresh Tor instance on default ports (9050/9051)..."
mkdir -p "$LOG_DIR/tor_data"
tor --SocksPort 9050 --ControlPort 9051 --CookieAuthentication 0 --DataDirectory "$LOG_DIR/tor_data" >"$LOG_DIR/tor.log" 2>&1 &
TOR_PID=$!
# Wait for Tor to bootstrap
echo "Waiting for Tor to bootstrap (up to 120s)..."
BOOTSTRAPPED=0
for i in {1..120}; do
if grep -q "Bootstrapped 100%" "$LOG_DIR/tor.log"; then
echo "Tor bootstrapped successfully."
BOOTSTRAPPED=1
break
fi
[ $((i % 10)) -eq 0 ] && echo "... still bootstrapping Tor ($i s) ..."
sleep 1
done
if [ $BOOTSTRAPPED -eq 0 ]; then
echo "CRITICAL: Tor failed to bootstrap after 120s" >&2
tail -n 20 "$LOG_DIR/tor.log"
kill ${TOR_PID:-} || true
exit 1
fi
echo "Checking platform contract with live Tor..."
VOXVERA_REQUIRE_TOR=1 bash scripts/platform-smoke.sh linux-cli
# Start OnionShare
echo "Starting OnionShare..."
# Explicitly set environment variables that OnionShare-cli respects
export TOR_SOCKS_PORT=9050
export TOR_CONTROL_PORT=9051
onionshare-cli --website --public \
--persistent "$host_dir/.onionshare-session" \
-v \
"$host_dir" >"$LOG_DIR/onionshare.log" 2>&1 &
OS_PID=$!
# Check if OnionShare process is still alive after a few seconds
sleep 5
if ! kill -0 $OS_PID 2>/dev/null; then
echo "CRITICAL: OnionShare-cli failed to start" >&2
cat "$LOG_DIR/onionshare.log"
kill ${TOR_PID:-} || true
exit 1
fi
# Wait for URL with timeout and feedback
echo "Waiting for OnionShare to generate URL (up to 120s)..."
URL=""
for i in {1..120}; do
# Use -a to process as text even if there are binary chars (ANSI codes)
if grep -aEo 'http[s]?://[a-z2-7]{56}\.onion' "$LOG_DIR/onionshare.log" | head -n1 >"$LOG_DIR/url.txt"; then
URL=$(cat "$LOG_DIR/url.txt" | tr -d '\r\n ')
if [ -n "$URL" ]; then
echo "Successfully generated Onion URL: $URL"
break
fi
fi
[ $((i % 10)) -eq 0 ] && echo "... still waiting ($i s) ..."
sleep 1
done
if [ -z "$URL" ]; then
echo "CRITICAL: Onion URL not found after 120s" >&2
echo "--- Last 20 lines of OnionShare log ---"
tail -n 20 "$LOG_DIR/onionshare.log"
kill $OS_PID || true
kill ${TOR_PID:-} || true
exit 1
fi
# Robustness: Manually update the config.json with the URL so verification passes
# and the site is actually using the live onion address.
echo "Updating $host_dir/config.json with live URL: $URL"
python3 <<EOF
import json
import os
path = "$host_dir/config.json"
with open(path, 'r') as f:
data = json.load(f)
data['url'] = "$URL"
with open(path + '.new', 'w') as f:
json.dump(data, f, indent=2)
os.replace(path + '.new', path)
EOF
echo "Verifying content of $host_dir/config.json:"
cat "$host_dir/config.json"
# Verify URL in config
if ! grep -Fq "$URL" "$host_dir/config.json"; then
echo "CRITICAL: URL $URL not found in $host_dir/config.json" >&2
cat "$host_dir/config.json"
kill $OS_PID || true
kill ${TOR_PID:-} || true
exit 1
fi
# Re-build to update QR codes with live onion URL
echo "Re-building site with live URL..."
"$voxvera_cmd" --lang en build --config "$host_dir/config.json"
# Fetch page via Tor (retry a few times as circuits can be flaky)
echo "Verifying reachability via Tor (on port 9050)..."
FETCHED=0
for attempt in {1..5}; do
echo "Attempt $attempt..."
if curl --socks5-hostname 127.0.0.1:9050 -fsSL "$URL" | grep -q '<title>'; then
echo "Success: Site is reachable via Tor."
FETCHED=1
break
fi
sleep 10
done
if [ $FETCHED -eq 0 ]; then
echo "WARNING: Site could not be reached via Tor after 5 attempts, but OnionShare is running."
# In CI, we might skip hard failure if Tor network is exceptionally slow/blocked
fi
# Clean up
echo "Cleaning up..."
kill $OS_PID || true
kill ${TOR_PID:-} || true
wait $OS_PID 2>/dev/null || true
else
echo "Skipping network-dependent tests (VOXVERA_E2E_OFFLINE=1)" >&2
fi
echo "E2E verification complete at $(date)"
exit 0
+18
View File
@@ -0,0 +1,18 @@
# Data Center Construction Protest Demo Flyer
Use these values in the VoxVera editor for a civic protest or public-comment demo.
| Field | Value |
| --- | --- |
| Relays | `wss://relay.damus.io`, `wss://nos.lol`, `wss://relay.primal.net` |
| Flyer Name | `data-center-protest` |
| Language | `en` |
| Page title | `Data Center Protest Flyer` |
| Title | `PUBLIC HEARING` |
| Subtitle | `NO BLANK CHECK FOR BIG TECH` |
| Headline | `STOP THE DATA CENTER LAND GRAB` |
| Content | `A proposed data center project could strain local power, water, roads, and public budgets while leaving residents with noise, traffic, and long-term infrastructure costs. Attend the public hearing, ask for full environmental review, and demand binding limits before any approval.` |
| URL message | `Scan for meeting time, talking points, and public-comment instructions.` |
| Content URL | `https://example.com/data-center-hearing` |
| Footer message | `BRING NEIGHBORS - SPEAK DURING PUBLIC COMMENT` |
+18
View File
@@ -0,0 +1,18 @@
# Presbyterian Gospel Tract Demo Flyer
Use these values in the VoxVera editor for a Reformed Presbyterian gospel tract demo.
| Field | Value |
| --- | --- |
| Relays | `wss://relay.damus.io`, `wss://nos.lol`, `wss://relay.primal.net` |
| Flyer Name | `presbyterian-gospel-tract` |
| Language | `en` |
| Page title | `Presbyterian Gospel Tract` |
| Title | `CHRIST SAVES SINNERS` |
| Subtitle | `REPENT AND BELIEVE THE GOSPEL` |
| Headline | `THE GOOD NEWS OF JESUS CHRIST` |
| Content | `God is holy, and all men have sinned against Him. Yet God sent His eternal Son, Jesus Christ, to take on true humanity, obey perfectly, die for sinners, and rise again. Salvation is by grace alone, through faith alone, in Christ alone. Turn from sin and trust the Lord Jesus Christ.` |
| URL message | `Scan to read Scripture, a short catechism, and a local church invitation.` |
| Content URL | `https://example.com/gospel` |
| Footer message | `FOR BY GRACE ARE YE SAVED THROUGH FAITH - EPHESIANS 2:8` |
+18
View File
@@ -0,0 +1,18 @@
# Yard Sale Demo Flyer
Use these values in the VoxVera editor as a practical neighborhood-sale demo.
| Field | Value |
| --- | --- |
| Relays | `wss://relay.damus.io`, `wss://nos.lol`, `wss://relay.primal.net` |
| Flyer Name | `yard-sale-saturday` |
| Language | `en` |
| Page title | `Saturday Yard Sale` |
| Title | `YARD SALE` |
| Subtitle | `SATURDAY 8 AM TO 2 PM` |
| Headline | `TOOLS, BOOKS, TOYS, AND HOME GOODS` |
| Content | `Stop by this Saturday for a family yard sale with useful household items, kids clothes, books, tools, small furniture, toys, and kitchen goods. Prices are marked to move. Cash is preferred, and early visitors are welcome after 8 AM.` |
| URL message | `Scan for address, photos, and any weather updates.` |
| Content URL | `https://example.com/yard-sale` |
| Footer message | `SATURDAY ONLY - PLEASE PARK ALONG THE STREET` |
-42
View File
@@ -1,42 +0,0 @@
# AI Agent Instructions for VoxVera
This guide is for AI agents (like Gemini, Claude, or GPT) contributing to the VoxVera project. Follow these protocols to maintain the architectural integrity and multi-language support.
## Core Mandates
1. **Security-First**: VoxVera is a Tor-based tool. Never suggest features that leak IP addresses or use non-Tor external resources (CDNs, etc.).
2. **Local-First**: All assets (fonts, dependencies, binaries) must be self-contained within the `voxvera/` package to support the Universal Mirroring model.
3. **Tokenized UI**: Never hardcode user-facing strings. Always add them to `voxvera/locales/en.json` and use the `t('cli.token')` helper.
4. **Markdown Redaction**: Use `~~text~~` in locale JSONs for strike-through effects. Both the build system and the JS engine handle the conversion to `<span class="redacted">` automatically.
5. **Visual Width Testing**: When modifying UI or adding languages, verify that long or complex strings (e.g., Hindi ligatures or CJK characters) do not exceed the visual unit limits defined in the CLI.
## Localization Protocol
When adding a new language or updating an existing one:
- **CLI/Flyers**: Update `voxvera/locales/{lang}.json`. Include `meta`, `cli`, `web`, and `landing` categories.
- **Landing Page**:
- Directly update the `const locales` object in `site/index.html`.
- **Crucial**: Run `voxvera build-site` to generate the latest portable bundle and refresh the pre-rendered HTML.
- **Documentation**:
- Master templates live in `docs/templates/`.
- Localized overrides live in `voxvera/locales/{lang}/docs/`.
- **Crucial**: After any change to locales or templates, you MUST run `voxvera build-docs` to synchronize the output in `docs/{en,es,de}/`.
## Universal Mirroring
VoxVera propagates through its own flyers.
- Every `voxvera build` and `voxvera build-site` generates `voxvera-portable.zip`.
- If you modify the core source code, ensure the `bundle_portable` function in `voxvera/cli.py` still correctly captures all necessary directories (especially `vendor/`, `locales/`, and `resources/`).
## Verification Checklist
Before finishing a task, ensure you have:
1. Run unit tests: `pytest tests/test_cli.py`.
2. Verified the localization: `voxvera --lang {lang} check`.
3. Rebuilt the documentation: `voxvera build-docs`.
4. Synchronized the public site: `voxvera build-site`.
5. Verified the portable bundle exists: `ls -l voxvera/host/*/download/voxvera-portable.zip` and `ls -l site/download/voxvera-portable.zip`.
---
Follow these rules to ensure VoxVera remains a robust, viral, and decentralized tool for truth.
-47
View File
@@ -1,47 +0,0 @@
# Contributing to VoxVera
Thank you for your interest in contributing to VoxVera! This project aims to be a global, censorship-resistant tool, and your help—especially with translations—is vital.
## Adding a New Language
VoxVera uses a centralized token system for the CLI and Web components, and a template-based system for Documentation. To add a new language (e.g., French/`fr`), follow this checklist:
### 1. The Token File
Create a new JSON file in `voxvera/locales/{lang_code}.json`.
- Use `en.json` as your master template.
- **`meta`**: Include the native language name and a flag emoji.
- **`cli`**: Translate all strings used in the terminal interface.
- **`web`**: Translate strings used on the generated landing pages and flyers.
- **`landing`**: Translate the specific content for the official VoxVera website.
- **Formatting**: You can use Markdown-style strike-throughs (`~~redacted text~~`) in any of these strings; they will be automatically converted to the stylized "redacted" effect on the flyers.
### 2. The Landing Page
The main landing page is generated from the shared template and locale files.
- Add your language in `voxvera/locales/{lang_code}.json`.
- Do **not** edit `site/index.html` directly; it is generated output.
- Run `voxvera build-site` to refresh the public assets and inject your new locale into the generated HTML.
### 3. Documentation
VoxVera uses the **Doc-Sync Engine** to keep manuals in sync.
- Create localized Markdown files in `voxvera/locales/{lang_code}/docs/`.
- Use the templates in `docs/templates/` as your guide.
- You can use `cli.token_name` to reference terminal commands automatically.
### 4. Build and Verify
Run the following commands to verify your changes:
- `voxvera --lang {lang_code} check` (Verify CLI translation)
- `voxvera build-docs` (Generate localized manuals)
- `voxvera build-site` (Synchronize the public website and generate the latest portable bundle)
- Open the generated `site/index.html` in a browser and test the language switcher.
## Code Contributions
- **Dependencies**: if you add a new Python library to `requirements.txt`, you MUST run `voxvera vendorize` to include it in the portable distribution.
- **Layout Integrity**: VoxVera uses visual width validation. If you add new UI elements, ensure they respect the physical boundaries of an 8.5"x11" flyer.
- **Tests**: Ensure all tests pass: `pytest tests/`. Run the integrity suite specifically when modifying locales: `pytest tests/test_integrity.py`.
- **Generated artifacts**: Treat `voxvera/resources/bin/` as local build output, not source files. Release binaries belong in GitHub Releases, not hand-edited repo state.
- **Style**: Follow the existing coding style (PEP 8 for Python).
- **Documentation**: If adding a new feature, update the master templates in `docs/templates/` and run `voxvera build-docs`.
---
Together, we can ensure that truth remains accessible to everyone, everywhere.
-19
View File
@@ -1,19 +0,0 @@
# Docker Usage
Experimental: the container path is not yet a production-grade hidden-service deployment target. Linux with `systemd --user` remains the supported persistent-host environment.
A prebuilt image containing Tor, OnionShare and the `voxvera` CLI is published to
`ghcr.io/voxvera/voxvera`.
```bash
# pull the image
docker pull ghcr.io/voxvera/voxvera:latest
# run the experimental container with flyers stored in ./flyers
mkdir -p flyers
docker run -it --rm -v "$(pwd)/flyers:/flyers" ghcr.io/voxvera/voxvera
```
The container stores runtime state under `/flyers`, seeds a default `config.json` if needed, and retries `voxvera start-all` periodically after the initial `quickstart`.
Use this path for testing only until the container runtime and background recovery behavior are validated end-to-end.
-14
View File
@@ -1,14 +0,0 @@
# Flyer Templates
Pre-built flyer templates live in the `templates/` directory. Use the CLI to copy one with:
```bash
voxvera init --template <name>
```
This will create a new folder under `dist/` named `<name>-<YYYYMMDD>` containing the template files.
Available templates:
- **blank** – minimal placeholder files, also used when extracting fields from a PDF.
- **voxvera** – example flyer showcasing the VoxVera project.
-75
View File
@@ -1,75 +0,0 @@
# Troubleshooting
This page collects common issues encountered when hosting or accessing flyers.
## Tor connectivity
- Ensure Tor is allowed through your firewall. On systems using `ufw` you may need to run `sudo ufw allow tor`.
- Some networks block Tor entirely. If you cannot reach onion services, try connecting over a different network or use a Tor bridge.
## Supported deployment target
- The supported persistent-host setup is Linux with `systemd --user`.
- Windows, macOS, Docker, Flatpak, AppImage, Homebrew, and Chocolatey are currently experimental and may not recover hosting automatically after reboot or network interruptions.
## Tor port detection
`voxvera serve` auto-detects Tor by probing common ports (9050/9150 for SOCKS, 9051/9151 for control). If detection fails -- for example when Tor runs on non-standard ports -- you can override with environment variables:
```bash
TOR_SOCKS_PORT=19050 TOR_CONTROL_PORT=19051 voxvera serve
```
If no running Tor is found, the defaults (9050/9051) are used and OnionShare will attempt to connect on those ports.
## Firewall rules
- If `voxvera serve` fails to start OnionShare, verify that outbound connections on ports 9001 and 80 are permitted.
- Corporate or university firewalls can block the hidden service ports required by Tor.
## SELinux
- On SELinux-enabled distributions you may see `permission denied` errors when OnionShare writes to the `host` directory.
- Run `sudo chcon -Rt svirt_sandbox_file_t host` or disable SELinux enforcement for the folder.
## OnionShare crashes
If `voxvera serve` prints "OnionShare exited unexpectedly", check the log file
`host/<folder_name>/onionshare.log` for details. Common causes:
- Tor is not running (`sudo systemctl start tor`)
- A port conflict with another service
- Missing `onionshare-cli` (run `voxvera check`)
## Onion URL changed unexpectedly
The onion URL is tied to the Ed25519 keypair stored in
`host/<folder_name>/.onionshare-session`. If this file is deleted, a new
keypair (and URL) will be generated on the next `voxvera serve`. The
`voxvera import` command preserves this file automatically, but manual
deletion of the `host/` directory will destroy it.
## Hosting does not return after reboot or network loss
On Linux, install or verify the recovery timer:
```bash
voxvera autostart
systemctl --user status voxvera-start.timer
systemctl --user status voxvera-start.service
```
The supported recovery path is the recurring `systemd --user` timer, which reruns `voxvera start-all` every few minutes.
## QR codes not generated
If `voxvera build` reports "No URLs configured yet", this is expected before the first `voxvera serve`. QR codes for tear-off links are generated automatically once the .onion address is known. QR codes for the content link are generated if you provided a URL during `voxvera init`.
## Electron GUI
If `npm start` fails with `spawn voxvera ENOENT`, the `voxvera` command is not in your `PATH`. Install it with `pipx install git+https://github.com/PR0M3TH3AN/VoxVera.git` or run `./install.sh` from the repository.
## Missing dependencies
Run `voxvera check` to verify your setup. The command checks for required
Python packages (`qrcode`, `Pillow`, `jsmin`, `htmlmin`, `pypdf`) and
external tools (`onionshare-cli`), then prints a summary of anything
missing. To install everything:
```bash
# Recommended: use the install script (handles Tor + OnionShare too)
curl -fsSL https://raw.githubusercontent.com/PR0M3TH3AN/VoxVera/main/install.sh | bash
# Or reinstall just the Python package
pipx install --force 'voxvera@git+https://github.com/PR0M3TH3AN/VoxVera.git@main'
```
-130
View File
@@ -1,130 +0,0 @@
# الاستخدام التفصيلي
يغطي هذا الدليل سير عمل واجهة سطر الأوامر (CLI) الشائعة. راجع `docs/docker.md` للحصول على تعليمات Docker و `docs/templates.md` لقوالب المنشورات المتاحة.
## المتطلبات الأساسية
تم تصميم VoxVera ليكون سهل النقل للغاية ويتطلب الحد الأدنى من تبعيات النظام.
### 1. الملفات الثنائية المستقلة (موصى به)
يمكنك تنزيل ملفات ثنائية مستقلة بدون تبعيات لنظام التشغيل الخاص بك:
- **Linux:** `voxvera-linux`
- **Windows:** `voxvera-windows.exe`
- **macOS:** `voxvera-macos`
تتضمن هذه الملفات الثنائية كل ما يلزم لتشغيل VoxVera (باستثناء `onionshare-cli`).
### 2. المثبت بنقرة واحدة
بدلاً من ذلك، قم بالتثبيت عبر البرمجية النصية المؤتمتة الخاصة بنا:
```bash
curl -fsSL https://raw.githubusercontent.com/PR0M3TH3AN/VoxVera/main/install.sh | bash
```
### 3. تثبيت Python اليدوي
إذا كنت تفضل التشغيل من المصدر:
```bash
pipx install 'voxvera@git+https://github.com/PR0M3TH3AN/VoxVera.git@main'
sudo apt install tor onionshare-cli # Debian/Ubuntu
```
## خطوة بخطوة
1. **التهيئة:** قم بتشغيل `voxvera init` واتبع المطالبات. سيُطلب منك اختيار لغتك أولاً.
2. **البناء:** قم بإنشاء أصول المنشور. ينشئ كل بناء تلقائياً ملف `voxvera-portable.zip` في مجلد المنشور، مما يسمح للآخرين بتنزيل الأداة الكاملة مباشرة من منشورك.
```bash
voxvera build
```
3. **الخدمة:** انشر المنشور عبر Tor:
```bash
voxvera serve
```
يكتشف هذا تلقائياً نسخة Tor الخاصة بك، ويبدأ OnionShare، ويكتب عنوان .onion الناتج في روابط المنشور القابلة للنزع.
## دعم اللغة
VoxVera مترجم بالكامل. يمكنك تغيير تفضيل اللغة الخاص بك بشكل دائم باستخدام المبدل التفاعلي أو اختصار مباشر:
- **المبدل التفاعلي:** `voxvera lang`
- **اختصار مباشر:** `voxvera --lang ar` (يضبط التفضيل على العربية)
### اللغات المدعومة:
- **الإنجليزية:** `en`
- **الإسبانية:** `es` (اسم مستعار: `--idioma`)
- **الألمانية:** `de` (اسم مستعار: `--sprache`)
- **العربية:** `ar`
يمكنك أيضاً فرض لغة معينة لأمر واحد دون تغيير تفضيلك الدائم:
- **الإنجليزية:** `voxvera --lang en check`
- **العربية:** `voxvera --lang ar check`
تكتشف المنشورات الناتجة تلقائياً لغة متصفح الزائر وتبدل نص واجهة المستخدم وفقاً لذلك.
## إدارة الخوادم
إدارة منشورات متعددة وهويات Tor الخاصة بها من قائمة تفاعلية واحدة:
```bash
voxvera manage
```
الميزات:
- **--- إنشاء موقع/منشور جديد ---**: ابدأ تسلسل الإعداد الكامل.
- **--- تشغيل جميع المواقع ---**: تشغيل أو إيقاف جميع المنشورات في أسطولك دفعة واحدة.
- **الحالة في الوقت الفعلي**: عرض روابط .onion النشطة ومؤشرات تقدم تمهيد Tor.
- **التحكم الفردي**: تصدير إلى Zip مواقع معينة إلى ZIP أو حذفها.
## مراجة شاملة (التوزيع الفيروسي)
لضمان بقاء VoxVera متاحاً حتى لو تم فرض رقابة على المستودعات المركزية، يعمل كل منشور كمرآة للأداة.
عندما تستضيف منشوراً، يوفر زر **"تحميل الأداة والكود"** في الصفحة المقصودة ملف `voxvera-portable.zip` يحتوي على:
- كود المصدر الكامل وجميع اللغات المدعومة.
- جميع تبعيات Python (مضمنة مسبقاً).
- ملفات Tor الثنائية لجميع الأنظمة.
يتيح ذلك لأي شخص يقوم بمسح منشورك أن يصبح موزعاً جديداً لأداة VoxVera.
## التصدير والنسخ الاحتياطي
قم بنسخ هويات Tor الفريدة الخاصة بك احتياطياً (حتى لا يتغير رابط .onion الخاص بك أبداً) أو انقل منشوراتك إلى جهاز آخر.
- **تصدير موقع واحد**: `voxvera export <folder_name>`
- **تصدير جميع المواقع**: `voxvera export-all`
**مكان التخزين:** يتم حفظ جميع الصادرات كملفات ZIP في مجلد يسمى `voxvera-exports` في دليل الصفحة الرئيسية للمستخدم (`~/voxvera-exports/`) على جميع الأنظمة.
## الاستيراد والاستعادة
استعد إعدادك بالكامل على جهاز جديد بنقل ملفات ZIP الخاصة بك إلى `~/voxvera-exports/` وتشغيل:
```bash
voxvera import-multiple
```
## النقل والتشغيل بدون إنترنت
إذا كنت بحاجة إلى تشغيل VoxVera على جهاز لا يتوفر فيه اتصال بالإنترنت، يمكنك "تضمين" التبعيات أولاً:
```bash
voxvera vendorize
```
يقوم هذا بتنزيل جميع مكتبات Python المطلوبة في `voxvera/vendor/`. ستعطي الأداة بعد ذلك الأولوية لهذه الملفات المحلية، مما يسمح لها بالعمل بدون `pip install`.
## استيراد جماعي (JSON)
لإنشاء منشورات بشكل جماعي من ملفات تكوين JSON متعددة، ضعها في مجلد `imports/` وشغل:
```bash
voxvera batch-import
```
## كيف تعمل الروابط
يحتوي كل منشور على رابطين منفصلين:
- **رابط قابل للنزع** (يتم إنشاؤه تلقائياً): عنوان .onion حيث يتم استضافة المنشور.
- **رابط المحتوى** (يتم تكوينه بواسطة المستخدم): URL خارجي يشير إلى موقع ويب أو فيديو أو تنزيل.
لا تحتاج إلى إدخال عنوان .onion يدوياً؛ يتولى VoxVera ذلك تلقائياً خلال مرحلة `serve`.
-42
View File
@@ -1,42 +0,0 @@
# AI Agent Instructions for VoxVera
This guide is for AI agents (like Gemini, Claude, or GPT) contributing to the VoxVera project. Follow these protocols to maintain the architectural integrity and multi-language support.
## Core Mandates
1. **Security-First**: VoxVera is a Tor-based tool. Never suggest features that leak IP addresses or use non-Tor external resources (CDNs, etc.).
2. **Local-First**: All assets (fonts, dependencies, binaries) must be self-contained within the `voxvera/` package to support the Universal Mirroring model.
3. **Tokenized UI**: Never hardcode user-facing strings. Always add them to `voxvera/locales/en.json` and use the `t('cli.token')` helper.
4. **Markdown Redaction**: Use `~~text~~` in locale JSONs for strike-through effects. Both the build system and the JS engine handle the conversion to `<span class="redacted">` automatically.
5. **Visual Width Testing**: When modifying UI or adding languages, verify that long or complex strings (e.g., Hindi ligatures or CJK characters) do not exceed the visual unit limits defined in the CLI.
## Localization Protocol
When adding a new language or updating an existing one:
- **CLI/Flyers**: Update `voxvera/locales/{lang}.json`. Include `meta`, `cli`, `web`, and `landing` categories.
- **Landing Page**:
- Directly update the `const locales` object in `site/index.html`.
- **Crucial**: Run `voxvera build-site` to generate the latest portable bundle and refresh the pre-rendered HTML.
- **Documentation**:
- Master templates live in `docs/templates/`.
- Localized overrides live in `voxvera/locales/{lang}/docs/`.
- **Crucial**: After any change to locales or templates, you MUST run `voxvera build-docs` to synchronize the output in `docs/{en,es,de}/`.
## Universal Mirroring
VoxVera propagates through its own flyers.
- Every `voxvera build` and `voxvera build-site` generates `voxvera-portable.zip`.
- If you modify the core source code, ensure the `bundle_portable` function in `voxvera/cli.py` still correctly captures all necessary directories (especially `vendor/`, `locales/`, and `resources/`).
## Verification Checklist
Before finishing a task, ensure you have:
1. Run unit tests: `pytest tests/test_cli.py`.
2. Verified the localization: `voxvera --lang {lang} check`.
3. Rebuilt the documentation: `voxvera build-docs`.
4. Synchronized the public site: `voxvera build-site`.
5. Verified the portable bundle exists: `ls -l voxvera/host/*/download/voxvera-portable.zip` and `ls -l site/download/voxvera-portable.zip`.
---
Follow these rules to ensure VoxVera remains a robust, viral, and decentralized tool for truth.
-47
View File
@@ -1,47 +0,0 @@
# Contributing to VoxVera
Thank you for your interest in contributing to VoxVera! This project aims to be a global, censorship-resistant tool, and your help—especially with translations—is vital.
## Adding a New Language
VoxVera uses a centralized token system for the CLI and Web components, and a template-based system for Documentation. To add a new language (e.g., French/`fr`), follow this checklist:
### 1. The Token File
Create a new JSON file in `voxvera/locales/{lang_code}.json`.
- Use `en.json` as your master template.
- **`meta`**: Include the native language name and a flag emoji.
- **`cli`**: Translate all strings used in the terminal interface.
- **`web`**: Translate strings used on the generated landing pages and flyers.
- **`landing`**: Translate the specific content for the official VoxVera website.
- **Formatting**: You can use Markdown-style strike-throughs (`~~redacted text~~`) in any of these strings; they will be automatically converted to the stylized "redacted" effect on the flyers.
### 2. The Landing Page
The main landing page is generated from the shared template and locale files.
- Add your language in `voxvera/locales/{lang_code}.json`.
- Do **not** edit `site/index.html` directly; it is generated output.
- Run `voxvera build-site` to refresh the public assets and inject your new locale into the generated HTML.
### 3. Documentation
VoxVera uses the **Doc-Sync Engine** to keep manuals in sync.
- Create localized Markdown files in `voxvera/locales/{lang_code}/docs/`.
- Use the templates in `docs/templates/` as your guide.
- You can use `cli.token_name` to reference terminal commands automatically.
### 4. Build and Verify
Run the following commands to verify your changes:
- `voxvera --lang {lang_code} check` (Verify CLI translation)
- `voxvera build-docs` (Generate localized manuals)
- `voxvera build-site` (Synchronize the public website and generate the latest portable bundle)
- Open the generated `site/index.html` in a browser and test the language switcher.
## Code Contributions
- **Dependencies**: if you add a new Python library to `requirements.txt`, you MUST run `voxvera vendorize` to include it in the portable distribution.
- **Layout Integrity**: VoxVera uses visual width validation. If you add new UI elements, ensure they respect the physical boundaries of an 8.5"x11" flyer.
- **Tests**: Ensure all tests pass: `pytest tests/`. Run the integrity suite specifically when modifying locales: `pytest tests/test_integrity.py`.
- **Generated artifacts**: Treat `voxvera/resources/bin/` as local build output, not source files. Release binaries belong in GitHub Releases, not hand-edited repo state.
- **Style**: Follow the existing coding style (PEP 8 for Python).
- **Documentation**: If adding a new feature, update the master templates in `docs/templates/` and run `voxvera build-docs`.
---
Together, we can ensure that truth remains accessible to everyone, everywhere.
-19
View File
@@ -1,19 +0,0 @@
# Docker Usage
Experimental: the container path is not yet a production-grade hidden-service deployment target. Linux with `systemd --user` remains the supported persistent-host environment.
A prebuilt image containing Tor, OnionShare and the `voxvera` CLI is published to
`ghcr.io/voxvera/voxvera`.
```bash
# pull the image
docker pull ghcr.io/voxvera/voxvera:latest
# run the experimental container with flyers stored in ./flyers
mkdir -p flyers
docker run -it --rm -v "$(pwd)/flyers:/flyers" ghcr.io/voxvera/voxvera
```
The container stores runtime state under `/flyers`, seeds a default `config.json` if needed, and retries `voxvera start-all` periodically after the initial `quickstart`.
Use this path for testing only until the container runtime and background recovery behavior are validated end-to-end.
-14
View File
@@ -1,14 +0,0 @@
# Flyer Templates
Pre-built flyer templates live in the `templates/` directory. Use the CLI to copy one with:
```bash
voxvera init --template <name>
```
This will create a new folder under `dist/` named `<name>-<YYYYMMDD>` containing the template files.
Available templates:
- **blank** – minimal placeholder files, also used when extracting fields from a PDF.
- **voxvera** – example flyer showcasing the VoxVera project.
-75
View File
@@ -1,75 +0,0 @@
# Troubleshooting
This page collects common issues encountered when hosting or accessing flyers.
## Tor connectivity
- Ensure Tor is allowed through your firewall. On systems using `ufw` you may need to run `sudo ufw allow tor`.
- Some networks block Tor entirely. If you cannot reach onion services, try connecting over a different network or use a Tor bridge.
## Supported deployment target
- The supported persistent-host setup is Linux with `systemd --user`.
- Windows, macOS, Docker, Flatpak, AppImage, Homebrew, and Chocolatey are currently experimental and may not recover hosting automatically after reboot or network interruptions.
## Tor port detection
`voxvera serve` auto-detects Tor by probing common ports (9050/9150 for SOCKS, 9051/9151 for control). If detection fails -- for example when Tor runs on non-standard ports -- you can override with environment variables:
```bash
TOR_SOCKS_PORT=19050 TOR_CONTROL_PORT=19051 voxvera serve
```
If no running Tor is found, the defaults (9050/9051) are used and OnionShare will attempt to connect on those ports.
## Firewall rules
- If `voxvera serve` fails to start OnionShare, verify that outbound connections on ports 9001 and 80 are permitted.
- Corporate or university firewalls can block the hidden service ports required by Tor.
## SELinux
- On SELinux-enabled distributions you may see `permission denied` errors when OnionShare writes to the `host` directory.
- Run `sudo chcon -Rt svirt_sandbox_file_t host` or disable SELinux enforcement for the folder.
## OnionShare crashes
If `voxvera serve` prints "OnionShare exited unexpectedly", check the log file
`host/<folder_name>/onionshare.log` for details. Common causes:
- Tor is not running (`sudo systemctl start tor`)
- A port conflict with another service
- Missing `onionshare-cli` (run `voxvera check`)
## Onion URL changed unexpectedly
The onion URL is tied to the Ed25519 keypair stored in
`host/<folder_name>/.onionshare-session`. If this file is deleted, a new
keypair (and URL) will be generated on the next `voxvera serve`. The
`voxvera import` command preserves this file automatically, but manual
deletion of the `host/` directory will destroy it.
## Hosting does not return after reboot or network loss
On Linux, install or verify the recovery timer:
```bash
voxvera autostart
systemctl --user status voxvera-start.timer
systemctl --user status voxvera-start.service
```
The supported recovery path is the recurring `systemd --user` timer, which reruns `voxvera start-all` every few minutes.
## QR codes not generated
If `voxvera build` reports "No URLs configured yet", this is expected before the first `voxvera serve`. QR codes for tear-off links are generated automatically once the .onion address is known. QR codes for the content link are generated if you provided a URL during `voxvera init`.
## Electron GUI
If `npm start` fails with `spawn voxvera ENOENT`, the `voxvera` command is not in your `PATH`. Install it with `pipx install git+https://github.com/PR0M3TH3AN/VoxVera.git` or run `./install.sh` from the repository.
## Missing dependencies
Run `voxvera check` to verify your setup. The command checks for required
Python packages (`qrcode`, `Pillow`, `jsmin`, `htmlmin`, `pypdf`) and
external tools (`onionshare-cli`), then prints a summary of anything
missing. To install everything:
```bash
# Recommended: use the install script (handles Tor + OnionShare too)
curl -fsSL https://raw.githubusercontent.com/PR0M3TH3AN/VoxVera/main/install.sh | bash
# Or reinstall just the Python package
pipx install --force 'voxvera@git+https://github.com/PR0M3TH3AN/VoxVera.git@main'
```
-136
View File
@@ -1,136 +0,0 @@
# Detaillierte Verwendung
Diese Anleitung deckt gängige CLI-Workflows ab. Informationen zu Docker finden Sie unter `docs/docker.md` und verfügbare Flyer-Vorlagen unter `docs/templates.md`.
## Voraussetzungen
VoxVera ist auf hohe Portabilität ausgelegt und erfordert minimale Systemabhängigkeiten.
### 1. Eigenständige Binärdateien (Empfohlen)
Sie können eigenständige Binärdateien ohne Abhängigkeiten für Ihr Betriebssystem herunterladen:
- **Linux:** `voxvera-linux`
- **Windows:** `voxvera-windows.exe`
- **macOS:** `voxvera-macos`
Diese Binärdateien enthalten alles, was zum Ausführen von VoxVera erforderlich ist (außer `onionshare-cli`).
### 2. Ein-Zeilen-Installer
Alternativ können Sie die Installation über unser automatisiertes Skript vornehmen:
```bash
curl -fsSL https://raw.githubusercontent.com/PR0M3TH3AN/VoxVera/main/install.sh | bash
```
### 3. Manuelle Python-Installation
Wenn Sie lieber aus dem Quellcode ausführen möchten:
```bash
pipx install 'voxvera@git+https://github.com/PR0M3TH3AN/VoxVera.git@main'
sudo apt install tor onionshare-cli # Debian/Ubuntu
```
## Schritt für Schritt
1. **Initialisieren:** Führen Sie `voxvera init` aus und folgen Sie den Anweisungen. Sie werden zuerst aufgefordert, Ihre Sprache auszuwählen.
2. **Bauen:** Erstellen Sie die Flyer-Assets. Jeder Build erstellt automatisch eine `voxvera-portable.zip` im Flyer-Ordner, sodass andere das komplette Tool direkt von Ihrem Flyer herunterladen können.
```bash
voxvera build
```
3. **Bereitstellen:** Veröffentlichen Sie den Flyer über Tor:
```bash
voxvera serve
```
Dies erkennt automatisch Ihre Tor-Instanz, startet OnionShare und schreibt die generierte .onion-Adresse in die Abreiß-Links des Flyers.
## Sprachunterstützung
VoxVera ist vollständig lokalisiert. Sie können Ihre Sprachpräferenz dauerhaft über den interaktiven Selektor oder eine direkte Verknüpfung ändern:
- **Interaktiver Selektor:** `voxvera lang`
- **Direkte Verknüpfung:** `voxvera --lang de` (setzt die Präferenz auf Deutsch)
### Unterstützte Sprachen:
- **Englisch:** `en`
- **Spanisch:** `es` (Alias: `--idioma`)
- **Deutsch:** `de` (Alias: `--sprache`)
- **Russisch:** `ru`
- **Hebräisch:** `he`
- **Arabisch:** `ar`
- **Französisch:** `fr`
- **Japanisch:** `ja`
- **Hindi:** `hi`
- **Suaheli:** `sw`
Sie können auch eine bestimmte Sprache für einen einzelnen Befehl erzwingen, ohne Ihre dauerhafte Präferenz zu ändern:
- **Englisch:** `voxvera --lang en check`
- **Deutsch:** `voxvera --sprache de check`
Die generierten Flyer erkennen automatisch die Browsersprache des Besuchers und schalten den UI-Text entsprechend um.
## Server-Verwaltung
Verwalten Sie mehrere Flyer und deren Tor-Identitäten über ein einziges interaktives Menü:
```bash
voxvera manage
```
Funktionen:
- **--- Neue Website/Flyer erstellen ---**: Starten Sie die vollständige Setup-Sequenz.
- **--- Alle Websites starten ---**: Starten oder stoppen Sie alle Flyer in Ihrer Flotte auf einmal.
- **Echtzeit-Status**: Zeigen Sie aktive .onion-URLs und Tor-Bootstrapping-Fortschrittsanzeigen an.
- **Individuelle Steuerung**: Als Zip exportieren Sie bestimmte Seiten in eine ZIP-Datei oder löschen Sie sie.
## Universelle Spiegelung (Virale Verteilung)
Um sicherzustellen, dass VoxVera auch dann zugänglich bleibt, wenn zentrale Repositories zensiert werden, fungiert jeder Flyer als Spiegel für das Tool.
Wenn Sie einen Flyer hosten, bietet die Schaltfläche **"Tool & Quellcode herunterladen"** auf der Landingpage eine `voxvera-portable.zip` an, die Folgendes enthält:
- Den vollständigen Quellcode und alle unterstützten Sprachen.
- Alle Python-Abhängigkeiten (vorinstalliert).
- Plattformübergreifende Tor-Binärdateien.
Dies ermöglicht es jedem, der Ihren Flyer scannt, ein neuer Distributor des VoxVera-Tools zu werden.
## Export & Sicherung
Sichern Sie Ihre eindeutigen Tor-Identitäten (damit sich Ihre .onion-URL nie ändert) oder verschieben Sie Ihre Flyer auf einen anderen Computer.
- **Einzelne Seite exportieren:** `voxvera export <folder_name>`
- **Alle Seiten exportieren:** `voxvera export-all`
**Speicherort:** Alle Exporte werden als ZIP-Dateien in einem Ordner namens `voxvera-exports` im Home-Verzeichnis des Benutzers (`~/voxvera-exports/`) auf allen Plattformen gespeichert.
## Import & Wiederherstellung
Stellen Sie Ihr gesamtes Setup auf einem neuen Computer wieder her, indem Sie Ihre ZIP-Dateien nach `~/voxvera-exports/` verschieben und Folgendes ausführen:
```bash
voxvera import-multiple
```
## Portabilität & Offline-Nutzung
Wenn Sie VoxVera auf einem Computer ohne Internetzugang ausführen müssen, können Sie die Abhängigkeiten zuerst lokal bereitstellen:
```bash
voxvera vendorize
```
Dies lädt alle erforderlichen Python-Bibliotheken in `voxvera/vendor/` herunter. Das Tool priorisiert dann diese lokalen Dateien, sodass es ohne `pip install` ausgeführt werden kann.
## Batch-Import (JSON)
Um Flyer in großen Mengen aus mehreren JSON-Konfigurationsdateien zu generieren, legen Sie diese im Verzeichnis `imports/` ab und führen Sie Folgendes aus:
```bash
voxvera batch-import
```
## Wie URLs funktionieren
Jeder Flyer hat zwei separate URLs:
- **Abreiß-Link** (automatisch generiert): Die .onion-Adresse, unter der der Flyer gehostet wird.
- **Inhalts-Link** (vom Benutzer konfiguriert): Eine externe URL, die auf eine Website, ein Video oder einen Download verweist.
Sie müssen die .onion-Adresse nicht manuell eingeben; VoxVera erledigt dies automatisch während der `serve`-Phase.
-42
View File
@@ -1,42 +0,0 @@
# AI Agent Instructions for VoxVera
This guide is for AI agents (like Gemini, Claude, or GPT) contributing to the VoxVera project. Follow these protocols to maintain the architectural integrity and multi-language support.
## Core Mandates
1. **Security-First**: VoxVera is a Tor-based tool. Never suggest features that leak IP addresses or use non-Tor external resources (CDNs, etc.).
2. **Local-First**: All assets (fonts, dependencies, binaries) must be self-contained within the `voxvera/` package to support the Universal Mirroring model.
3. **Tokenized UI**: Never hardcode user-facing strings. Always add them to `voxvera/locales/en.json` and use the `t('cli.token')` helper.
4. **Markdown Redaction**: Use `~~text~~` in locale JSONs for strike-through effects. Both the build system and the JS engine handle the conversion to `<span class="redacted">` automatically.
5. **Visual Width Testing**: When modifying UI or adding languages, verify that long or complex strings (e.g., Hindi ligatures or CJK characters) do not exceed the visual unit limits defined in the CLI.
## Localization Protocol
When adding a new language or updating an existing one:
- **CLI/Flyers**: Update `voxvera/locales/{lang}.json`. Include `meta`, `cli`, `web`, and `landing` categories.
- **Landing Page**:
- Directly update the `const locales` object in `site/index.html`.
- **Crucial**: Run `voxvera build-site` to generate the latest portable bundle and refresh the pre-rendered HTML.
- **Documentation**:
- Master templates live in `docs/templates/`.
- Localized overrides live in `voxvera/locales/{lang}/docs/`.
- **Crucial**: After any change to locales or templates, you MUST run `voxvera build-docs` to synchronize the output in `docs/{en,es,de}/`.
## Universal Mirroring
VoxVera propagates through its own flyers.
- Every `voxvera build` and `voxvera build-site` generates `voxvera-portable.zip`.
- If you modify the core source code, ensure the `bundle_portable` function in `voxvera/cli.py` still correctly captures all necessary directories (especially `vendor/`, `locales/`, and `resources/`).
## Verification Checklist
Before finishing a task, ensure you have:
1. Run unit tests: `pytest tests/test_cli.py`.
2. Verified the localization: `voxvera --lang {lang} check`.
3. Rebuilt the documentation: `voxvera build-docs`.
4. Synchronized the public site: `voxvera build-site`.
5. Verified the portable bundle exists: `ls -l voxvera/host/*/download/voxvera-portable.zip` and `ls -l site/download/voxvera-portable.zip`.
---
Follow these rules to ensure VoxVera remains a robust, viral, and decentralized tool for truth.
-47
View File
@@ -1,47 +0,0 @@
# Contributing to VoxVera
Thank you for your interest in contributing to VoxVera! This project aims to be a global, censorship-resistant tool, and your help—especially with translations—is vital.
## Adding a New Language
VoxVera uses a centralized token system for the CLI and Web components, and a template-based system for Documentation. To add a new language (e.g., French/`fr`), follow this checklist:
### 1. The Token File
Create a new JSON file in `voxvera/locales/{lang_code}.json`.
- Use `en.json` as your master template.
- **`meta`**: Include the native language name and a flag emoji.
- **`cli`**: Translate all strings used in the terminal interface.
- **`web`**: Translate strings used on the generated landing pages and flyers.
- **`landing`**: Translate the specific content for the official VoxVera website.
- **Formatting**: You can use Markdown-style strike-throughs (`~~redacted text~~`) in any of these strings; they will be automatically converted to the stylized "redacted" effect on the flyers.
### 2. The Landing Page
The main landing page is generated from the shared template and locale files.
- Add your language in `voxvera/locales/{lang_code}.json`.
- Do **not** edit `site/index.html` directly; it is generated output.
- Run `voxvera build-site` to refresh the public assets and inject your new locale into the generated HTML.
### 3. Documentation
VoxVera uses the **Doc-Sync Engine** to keep manuals in sync.
- Create localized Markdown files in `voxvera/locales/{lang_code}/docs/`.
- Use the templates in `docs/templates/` as your guide.
- You can use `cli.token_name` to reference terminal commands automatically.
### 4. Build and Verify
Run the following commands to verify your changes:
- `voxvera --lang {lang_code} check` (Verify CLI translation)
- `voxvera build-docs` (Generate localized manuals)
- `voxvera build-site` (Synchronize the public website and generate the latest portable bundle)
- Open the generated `site/index.html` in a browser and test the language switcher.
## Code Contributions
- **Dependencies**: if you add a new Python library to `requirements.txt`, you MUST run `voxvera vendorize` to include it in the portable distribution.
- **Layout Integrity**: VoxVera uses visual width validation. If you add new UI elements, ensure they respect the physical boundaries of an 8.5"x11" flyer.
- **Tests**: Ensure all tests pass: `pytest tests/`. Run the integrity suite specifically when modifying locales: `pytest tests/test_integrity.py`.
- **Generated artifacts**: Treat `voxvera/resources/bin/` as local build output, not source files. Release binaries belong in GitHub Releases, not hand-edited repo state.
- **Style**: Follow the existing coding style (PEP 8 for Python).
- **Documentation**: If adding a new feature, update the master templates in `docs/templates/` and run `voxvera build-docs`.
---
Together, we can ensure that truth remains accessible to everyone, everywhere.
-19
View File
@@ -1,19 +0,0 @@
# Docker Usage
Experimental: the container path is not yet a production-grade hidden-service deployment target. Linux with `systemd --user` remains the supported persistent-host environment.
A prebuilt image containing Tor, OnionShare and the `voxvera` CLI is published to
`ghcr.io/voxvera/voxvera`.
```bash
# pull the image
docker pull ghcr.io/voxvera/voxvera:latest
# run the experimental container with flyers stored in ./flyers
mkdir -p flyers
docker run -it --rm -v "$(pwd)/flyers:/flyers" ghcr.io/voxvera/voxvera
```
The container stores runtime state under `/flyers`, seeds a default `config.json` if needed, and retries `voxvera start-all` periodically after the initial `quickstart`.
Use this path for testing only until the container runtime and background recovery behavior are validated end-to-end.
-14
View File
@@ -1,14 +0,0 @@
# Flyer Templates
Pre-built flyer templates live in the `templates/` directory. Use the CLI to copy one with:
```bash
voxvera init --template <name>
```
This will create a new folder under `dist/` named `<name>-<YYYYMMDD>` containing the template files.
Available templates:
- **blank** – minimal placeholder files, also used when extracting fields from a PDF.
- **voxvera** – example flyer showcasing the VoxVera project.
-75
View File
@@ -1,75 +0,0 @@
# Troubleshooting
This page collects common issues encountered when hosting or accessing flyers.
## Tor connectivity
- Ensure Tor is allowed through your firewall. On systems using `ufw` you may need to run `sudo ufw allow tor`.
- Some networks block Tor entirely. If you cannot reach onion services, try connecting over a different network or use a Tor bridge.
## Supported deployment target
- The supported persistent-host setup is Linux with `systemd --user`.
- Windows, macOS, Docker, Flatpak, AppImage, Homebrew, and Chocolatey are currently experimental and may not recover hosting automatically after reboot or network interruptions.
## Tor port detection
`voxvera serve` auto-detects Tor by probing common ports (9050/9150 for SOCKS, 9051/9151 for control). If detection fails -- for example when Tor runs on non-standard ports -- you can override with environment variables:
```bash
TOR_SOCKS_PORT=19050 TOR_CONTROL_PORT=19051 voxvera serve
```
If no running Tor is found, the defaults (9050/9051) are used and OnionShare will attempt to connect on those ports.
## Firewall rules
- If `voxvera serve` fails to start OnionShare, verify that outbound connections on ports 9001 and 80 are permitted.
- Corporate or university firewalls can block the hidden service ports required by Tor.
## SELinux
- On SELinux-enabled distributions you may see `permission denied` errors when OnionShare writes to the `host` directory.
- Run `sudo chcon -Rt svirt_sandbox_file_t host` or disable SELinux enforcement for the folder.
## OnionShare crashes
If `voxvera serve` prints "OnionShare exited unexpectedly", check the log file
`host/<folder_name>/onionshare.log` for details. Common causes:
- Tor is not running (`sudo systemctl start tor`)
- A port conflict with another service
- Missing `onionshare-cli` (run `voxvera check`)
## Onion URL changed unexpectedly
The onion URL is tied to the Ed25519 keypair stored in
`host/<folder_name>/.onionshare-session`. If this file is deleted, a new
keypair (and URL) will be generated on the next `voxvera serve`. The
`voxvera import` command preserves this file automatically, but manual
deletion of the `host/` directory will destroy it.
## Hosting does not return after reboot or network loss
On Linux, install or verify the recovery timer:
```bash
voxvera autostart
systemctl --user status voxvera-start.timer
systemctl --user status voxvera-start.service
```
The supported recovery path is the recurring `systemd --user` timer, which reruns `voxvera start-all` every few minutes.
## QR codes not generated
If `voxvera build` reports "No URLs configured yet", this is expected before the first `voxvera serve`. QR codes for tear-off links are generated automatically once the .onion address is known. QR codes for the content link are generated if you provided a URL during `voxvera init`.
## Electron GUI
If `npm start` fails with `spawn voxvera ENOENT`, the `voxvera` command is not in your `PATH`. Install it with `pipx install git+https://github.com/PR0M3TH3AN/VoxVera.git` or run `./install.sh` from the repository.
## Missing dependencies
Run `voxvera check` to verify your setup. The command checks for required
Python packages (`qrcode`, `Pillow`, `jsmin`, `htmlmin`, `pypdf`) and
external tools (`onionshare-cli`), then prints a summary of anything
missing. To install everything:
```bash
# Recommended: use the install script (handles Tor + OnionShare too)
curl -fsSL https://raw.githubusercontent.com/PR0M3TH3AN/VoxVera/main/install.sh | bash
# Or reinstall just the Python package
pipx install --force 'voxvera@git+https://github.com/PR0M3TH3AN/VoxVera.git@main'
```
-152
View File
@@ -1,152 +0,0 @@
# Detailed Usage
This guide covers common CLI workflows. See `docs/docker.md` for Docker instructions and `docs/templates.md` for available flyer templates.
## Prerequisites
VoxVera is designed to be highly portable. You can run it directly from the source code on any platform with Python installed.
Linux with `systemd --user` is the supported persistent-host environment. Windows, macOS, Docker, Flatpak, AppImage, Homebrew, and Chocolatey are currently experimental and should not yet be treated as equally reliable hidden-service deployment targets.
### 1. Automated Install (Recommended)
The easiest way to install VoxVera is using the Linux-first installer script:
**Linux / macOS:**
```bash
curl -fsSL https://raw.githubusercontent.com/PR0M3TH3AN/VoxVera/main/install.sh | bash
```
On Linux, this also installs the recurring recovery timer used to retry hidden-service startup after boot and after missed/offline periods.
**Windows (PowerShell):**
```powershell
irm https://raw.githubusercontent.com/PR0M3TH3AN/VoxVera/main/install.ps1 | iex
```
The Windows installer is experimental and does not yet guarantee production-ready background hosting behavior.
### 2. Manual Source Install
If you have downloaded the source code ZIP:
1. **Extract** the ZIP file.
2. **Open a terminal** in the extracted folder.
3. **Run the setup script**:
- **Linux/macOS:** `./setup.sh`
- **Windows:** `.\voxvera-install.sh` (or run `python -m pip install .`)
## Uninstallation
If you wish to remove VoxVera from your system, you can use the provided uninstall scripts from the source directory. This will safely remove the CLI tool and any downloaded dependencies.
- **Linux / macOS:** Run `./uninstall.sh`
- **Windows (PowerShell):** Run `.\uninstall.ps1`
*Note: Uninstallation will not delete your generated flyers or your `.onion` keys stored in the `~/voxvera-exports` or local `host/` folders.*
## Step-by-Step
1. **Initialize:** Run `voxvera init` and follow the prompts. You will be asked to select your language first.
2. **Build:** Generate the flyer assets. Every build automatically creates a `voxvera-portable.zip` in the flyer's folder, allowing others to download the full tool directly from your flyer.
```bash
voxvera build
```
3. **Serve:** Publish the flyer over Tor:
```bash
voxvera serve
```
This automatically detects your Tor instance, starts OnionShare, and writes the generated .onion address into the flyer's tear-off links.
### Persistent Hosting On Linux
For a machine that should resume hosting automatically after boot or after being offline, install the autostart recovery timer:
```bash
voxvera autostart
```
This installs a `systemd --user` timer that reruns `voxvera start-all` every few minutes. The retry loop is the supported way to recover hidden-service hosting after suspend, reboot, or temporary network loss.
## Language Support
VoxVera is fully localized. You can change your language preference permanently using either the interactive selector or a direct shortcut:
- **Interactive Selector:** `voxvera lang`
- **Direct Shortcut:** `voxvera --lang de` (sets preference to German)
### Supported Languages:
- **English:** `en`
- **Spanish:** `es` (alias: `--idioma`)
- **German:** `de` (alias: `--sprache`)
You can also force a specific language for a single command without changing your permanent preference:
- **English:** `voxvera --lang en check`
- **German:** `voxvera --sprache de check`
- **Spanish:** `voxvera --idioma es check`
The generated flyers automatically detect the visitor's browser language and switch the UI text accordingly.
## Server Management
Manage multiple flyers and their Tor identities from a single interactive menu:
```bash
voxvera manage
```
Features:
- **--- Create New Site/Flyer ---**: Start the full setup sequence.
- **--- Start All Sites ---**: Launch or shut down every flyer in your fleet at once.
- **Real-time Status**: View active `.onion` URLs and Tor bootstrapping progress indicators.
- **Individual Control**: Export to Zip specific sites to ZIP or delete them.
## Universal Mirroring (Viral Distribution)
To ensure VoxVera remains accessible even if central repositories are censored, every flyer acts as a mirror for the tool.
When you host a flyer, the **"Download Source Code"** button on the landing page provides a `voxvera-source.zip` containing:
- The full source code and all supported languages.
- Installation and setup scripts for all platforms.
- Complete documentation and templates.
This allows anyone who scans your flyer to become a new distributor of the VoxVera tool.
## Export & Backup
Back up your unique Tor identities (so your `.onion` URL never changes) or move your flyers to another machine.
- **Export a single site**: `voxvera export <folder_name>`
- **Export all sites**: `voxvera export-all`
**Storage location:** All exports are saved to `~/voxvera-exports/` on all platforms.
## Import & Recovery
Restore your entire setup on a new machine by moving your ZIP files to `~/voxvera-exports/` and running:
```bash
voxvera import-multiple
```
## Portability & Offline Use
If you need to run VoxVera on a machine without internet access, you can "vendorize" the dependencies first:
```bash
voxvera vendorize
```
This downloads all required Python libraries into `voxvera/vendor/`. The tool will then prioritize these local files, allowing it to run without `pip install`.
## Batch Import (JSON)
To bulk-generate flyers from multiple JSON configuration files, place them in the `imports/` directory and run:
```bash
voxvera batch-import
```
## How URLs Work
Each flyer has two separate URLs:
- **Tear-off link** (auto-generated): The .onion address where the flyer is hosted.
- **Content link** (user-configured): An external URL pointing to a website, video, or download.
You do not need to manually enter the .onion address; VoxVera handles this automatically during the `serve` phase.
-42
View File
@@ -1,42 +0,0 @@
# AI Agent Instructions for VoxVera
This guide is for AI agents (like Gemini, Claude, or GPT) contributing to the VoxVera project. Follow these protocols to maintain the architectural integrity and multi-language support.
## Core Mandates
1. **Security-First**: VoxVera is a Tor-based tool. Never suggest features that leak IP addresses or use non-Tor external resources (CDNs, etc.).
2. **Local-First**: All assets (fonts, dependencies, binaries) must be self-contained within the `voxvera/` package to support the Universal Mirroring model.
3. **Tokenized UI**: Never hardcode user-facing strings. Always add them to `voxvera/locales/en.json` and use the `t('cli.token')` helper.
4. **Markdown Redaction**: Use `~~text~~` in locale JSONs for strike-through effects. Both the build system and the JS engine handle the conversion to `<span class="redacted">` automatically.
5. **Visual Width Testing**: When modifying UI or adding languages, verify that long or complex strings (e.g., Hindi ligatures or CJK characters) do not exceed the visual unit limits defined in the CLI.
## Localization Protocol
When adding a new language or updating an existing one:
- **CLI/Flyers**: Update `voxvera/locales/{lang}.json`. Include `meta`, `cli`, `web`, and `landing` categories.
- **Landing Page**:
- Directly update the `const locales` object in `site/index.html`.
- **Crucial**: Run `voxvera build-site` to generate the latest portable bundle and refresh the pre-rendered HTML.
- **Documentation**:
- Master templates live in `docs/templates/`.
- Localized overrides live in `voxvera/locales/{lang}/docs/`.
- **Crucial**: After any change to locales or templates, you MUST run `voxvera build-docs` to synchronize the output in `docs/{en,es,de}/`.
## Universal Mirroring
VoxVera propagates through its own flyers.
- Every `voxvera build` and `voxvera build-site` generates `voxvera-portable.zip`.
- If you modify the core source code, ensure the `bundle_portable` function in `voxvera/cli.py` still correctly captures all necessary directories (especially `vendor/`, `locales/`, and `resources/`).
## Verification Checklist
Before finishing a task, ensure you have:
1. Run unit tests: `pytest tests/test_cli.py`.
2. Verified the localization: `voxvera --lang {lang} check`.
3. Rebuilt the documentation: `voxvera build-docs`.
4. Synchronized the public site: `voxvera build-site`.
5. Verified the portable bundle exists: `ls -l voxvera/host/*/download/voxvera-portable.zip` and `ls -l site/download/voxvera-portable.zip`.
---
Follow these rules to ensure VoxVera remains a robust, viral, and decentralized tool for truth.
-47
View File
@@ -1,47 +0,0 @@
# Contributing to VoxVera
Thank you for your interest in contributing to VoxVera! This project aims to be a global, censorship-resistant tool, and your help—especially with translations—is vital.
## Adding a New Language
VoxVera uses a centralized token system for the CLI and Web components, and a template-based system for Documentation. To add a new language (e.g., French/`fr`), follow this checklist:
### 1. The Token File
Create a new JSON file in `voxvera/locales/{lang_code}.json`.
- Use `en.json` as your master template.
- **`meta`**: Include the native language name and a flag emoji.
- **`cli`**: Translate all strings used in the terminal interface.
- **`web`**: Translate strings used on the generated landing pages and flyers.
- **`landing`**: Translate the specific content for the official VoxVera website.
- **Formatting**: You can use Markdown-style strike-throughs (`~~redacted text~~`) in any of these strings; they will be automatically converted to the stylized "redacted" effect on the flyers.
### 2. The Landing Page
The main landing page is generated from the shared template and locale files.
- Add your language in `voxvera/locales/{lang_code}.json`.
- Do **not** edit `site/index.html` directly; it is generated output.
- Run `voxvera build-site` to refresh the public assets and inject your new locale into the generated HTML.
### 3. Documentation
VoxVera uses the **Doc-Sync Engine** to keep manuals in sync.
- Create localized Markdown files in `voxvera/locales/{lang_code}/docs/`.
- Use the templates in `docs/templates/` as your guide.
- You can use `cli.token_name` to reference terminal commands automatically.
### 4. Build and Verify
Run the following commands to verify your changes:
- `voxvera --lang {lang_code} check` (Verify CLI translation)
- `voxvera build-docs` (Generate localized manuals)
- `voxvera build-site` (Synchronize the public website and generate the latest portable bundle)
- Open the generated `site/index.html` in a browser and test the language switcher.
## Code Contributions
- **Dependencies**: if you add a new Python library to `requirements.txt`, you MUST run `voxvera vendorize` to include it in the portable distribution.
- **Layout Integrity**: VoxVera uses visual width validation. If you add new UI elements, ensure they respect the physical boundaries of an 8.5"x11" flyer.
- **Tests**: Ensure all tests pass: `pytest tests/`. Run the integrity suite specifically when modifying locales: `pytest tests/test_integrity.py`.
- **Generated artifacts**: Treat `voxvera/resources/bin/` as local build output, not source files. Release binaries belong in GitHub Releases, not hand-edited repo state.
- **Style**: Follow the existing coding style (PEP 8 for Python).
- **Documentation**: If adding a new feature, update the master templates in `docs/templates/` and run `voxvera build-docs`.
---
Together, we can ensure that truth remains accessible to everyone, everywhere.
-19
View File
@@ -1,19 +0,0 @@
# Docker Usage
Experimental: the container path is not yet a production-grade hidden-service deployment target. Linux with `systemd --user` remains the supported persistent-host environment.
A prebuilt image containing Tor, OnionShare and the `voxvera` CLI is published to
`ghcr.io/voxvera/voxvera`.
```bash
# pull the image
docker pull ghcr.io/voxvera/voxvera:latest
# run the experimental container with flyers stored in ./flyers
mkdir -p flyers
docker run -it --rm -v "$(pwd)/flyers:/flyers" ghcr.io/voxvera/voxvera
```
The container stores runtime state under `/flyers`, seeds a default `config.json` if needed, and retries `voxvera start-all` periodically after the initial `quickstart`.
Use this path for testing only until the container runtime and background recovery behavior are validated end-to-end.
-14
View File
@@ -1,14 +0,0 @@
# Flyer Templates
Pre-built flyer templates live in the `templates/` directory. Use the CLI to copy one with:
```bash
voxvera init --template <name>
```
This will create a new folder under `dist/` named `<name>-<YYYYMMDD>` containing the template files.
Available templates:
- **blank** – minimal placeholder files, also used when extracting fields from a PDF.
- **voxvera** – example flyer showcasing the VoxVera project.
-75
View File
@@ -1,75 +0,0 @@
# Troubleshooting
This page collects common issues encountered when hosting or accessing flyers.
## Tor connectivity
- Ensure Tor is allowed through your firewall. On systems using `ufw` you may need to run `sudo ufw allow tor`.
- Some networks block Tor entirely. If you cannot reach onion services, try connecting over a different network or use a Tor bridge.
## Supported deployment target
- The supported persistent-host setup is Linux with `systemd --user`.
- Windows, macOS, Docker, Flatpak, AppImage, Homebrew, and Chocolatey are currently experimental and may not recover hosting automatically after reboot or network interruptions.
## Tor port detection
`voxvera serve` auto-detects Tor by probing common ports (9050/9150 for SOCKS, 9051/9151 for control). If detection fails -- for example when Tor runs on non-standard ports -- you can override with environment variables:
```bash
TOR_SOCKS_PORT=19050 TOR_CONTROL_PORT=19051 voxvera serve
```
If no running Tor is found, the defaults (9050/9051) are used and OnionShare will attempt to connect on those ports.
## Firewall rules
- If `voxvera serve` fails to start OnionShare, verify that outbound connections on ports 9001 and 80 are permitted.
- Corporate or university firewalls can block the hidden service ports required by Tor.
## SELinux
- On SELinux-enabled distributions you may see `permission denied` errors when OnionShare writes to the `host` directory.
- Run `sudo chcon -Rt svirt_sandbox_file_t host` or disable SELinux enforcement for the folder.
## OnionShare crashes
If `voxvera serve` prints "OnionShare exited unexpectedly", check the log file
`host/<folder_name>/onionshare.log` for details. Common causes:
- Tor is not running (`sudo systemctl start tor`)
- A port conflict with another service
- Missing `onionshare-cli` (run `voxvera check`)
## Onion URL changed unexpectedly
The onion URL is tied to the Ed25519 keypair stored in
`host/<folder_name>/.onionshare-session`. If this file is deleted, a new
keypair (and URL) will be generated on the next `voxvera serve`. The
`voxvera import` command preserves this file automatically, but manual
deletion of the `host/` directory will destroy it.
## Hosting does not return after reboot or network loss
On Linux, install or verify the recovery timer:
```bash
voxvera autostart
systemctl --user status voxvera-start.timer
systemctl --user status voxvera-start.service
```
The supported recovery path is the recurring `systemd --user` timer, which reruns `voxvera start-all` every few minutes.
## QR codes not generated
If `voxvera build` reports "No URLs configured yet", this is expected before the first `voxvera serve`. QR codes for tear-off links are generated automatically once the .onion address is known. QR codes for the content link are generated if you provided a URL during `voxvera init`.
## Electron GUI
If `npm start` fails with `spawn voxvera ENOENT`, the `voxvera` command is not in your `PATH`. Install it with `pipx install git+https://github.com/PR0M3TH3AN/VoxVera.git` or run `./install.sh` from the repository.
## Missing dependencies
Run `voxvera check` to verify your setup. The command checks for required
Python packages (`qrcode`, `Pillow`, `jsmin`, `htmlmin`, `pypdf`) and
external tools (`onionshare-cli`), then prints a summary of anything
missing. To install everything:
```bash
# Recommended: use the install script (handles Tor + OnionShare too)
curl -fsSL https://raw.githubusercontent.com/PR0M3TH3AN/VoxVera/main/install.sh | bash
# Or reinstall just the Python package
pipx install --force 'voxvera@git+https://github.com/PR0M3TH3AN/VoxVera.git@main'
```
-136
View File
@@ -1,136 +0,0 @@
# Uso detallado
Esta guía cubre los flujos de trabajo de CLI comunes. Consulte `docs/docker.md` para obtener instrucciones de Docker y `docs/templates.md` para conocer las plantillas de volantes disponibles.
## Prerrequisitos
VoxVera está diseñado para ser altamente portátil y requiere un mínimo de dependencias del sistema.
### 1. Binarios independientes (Recomendado)
Puede descargar binarios independientes sin dependencias para su sistema operativo:
- **Linux:** `voxvera-linux`
- **Windows:** `voxvera-windows.exe`
- **macOS:** `voxvera-macos`
Estos binarios incluyen todo lo necesario para ejecutar VoxVera (excepto `onionshare-cli`).
### 2. Instalador de una sola línea
Alternativamente, instale a través de nuestro script automatizado:
```bash
curl -fsSL https://raw.githubusercontent.com/PR0M3TH3AN/VoxVera/main/install.sh | bash
```
### 3. Instalación manual de Python
Si prefiere ejecutar desde la fuente:
```bash
pipx install 'voxvera@git+https://github.com/PR0M3TH3AN/VoxVera.git@main'
sudo apt install tor onionshare-cli # Debian/Ubuntu
```
## Paso a paso
1. **Inicializar:** Ejecute `voxvera init` y siga las instrucciones. Se le pedirá que seleccione su idioma primero.
2. **Construir:** Genere los activos del volante. Cada construcción crea automáticamente un `voxvera-portable.zip` en la carpeta del volante, lo que permite que otros descarguen la herramienta completa directamente desde su volante.
```bash
voxvera build
```
3. **Servir:** Publique el volante sobre Tor:
```bash
voxvera serve
```
Esto detecta automáticamente su instancia de Tor, inicia OnionShare y escribe la dirección .onion generada en los enlaces desprendibles del volante.
## Soporte de idiomas
VoxVera está totalmente localizado. Puede cambiar su preferencia de idioma de forma permanente utilizando el selector interactivo o un acceso directo:
- **Selector interactivo:** `voxvera lang`
- **Acceso directo:** `voxvera --lang es` (establece la preferencia en español)
### Idiomas soportados:
- **Inglés:** `en`
- **Español:** `es` (alias: `--idioma`)
- **Alemán:** `de` (alias: `--sprache`)
- **Ruso:** `ru`
- **Hebreo:** `he`
- **Árabe:** `ar`
- **Francés:** `fr`
- **Japonés:** `ja`
- **Hindi:** `hi`
- **Swahili:** `sw`
También puede forzar un idioma específico para un solo comando sin cambiar su preferencia permanente:
- **Inglés:** `voxvera --lang en check`
- **Español:** `voxvera --idioma es check`
Los volantes generados detectan automáticamente el idioma del navegador del visitante y cambian el texto de la interfaz en consecuencia.
## Gestión de servidores
Gestione múltiples volantes y sus identidades de Tor desde un único menú interactivo:
```bash
voxvera manage
```
Características:
- **--- Crear Nuevo Sitio/Volante ---**: Inicie la secuencia de configuración completa.
- **--- Iniciar Todos los Sitios ---**: Inicie o apague todos los volantes de su flota a la vez.
- **Estado en tiempo real**: Vea las URL .onion activas e indicadores de progreso de arranque de Tor.
- **Control individual**: Exportar a Zip sitios específicos a ZIP o elimínelos.
## Espejo universal (Distribución viral)
Para garantizar que VoxVera siga siendo accesible incluso si los repositorios centrales son censurados, cada volante actúa como un espejo para la herramienta.
Cuando hospeda un volante, el botón **"Descargar Herramienta y Código"** en la página de inicio proporciona un `voxvera-portable.zip` que contiene:
- El código fuente completo y todos los idiomas soportados.
- Todas las dependencias de Python (pre-vendeurizadas).
- Binarios de Tor multiplataforma.
Esto permite que cualquier persona que escanee su volante se convierta en un nuevo distribuidor de la herramienta VoxVera.
## Exportación y respaldo
Haga una copia de seguridad de sus identidades únicas de Tor (para que su URL .onion nunca cambie) o mueva sus volantes a otra máquina.
- **Exportar un solo sitio**: `voxvera export <nombre_carpeta>`
- **Exportar todos los servicios**: `voxvera export-all`
**Lugar de almacenamiento:** Todas las exportaciones se guardan como archivos ZIP en una carpeta llamada `voxvera-exports` en el directorio de inicio del usuario (`~/voxvera-exports/`) en todas las plataformas.
## Importación y recuperación
Restaure toda su configuración en una nueva máquina moviendo sus archivos ZIP a `~/voxvera-exports/` y ejecutando:
```bash
voxvera import-multiple
```
## Portabilidad y uso sin conexión
Si necesita ejecutar VoxVera en una máquina sin acceso a Internet, primero puede "vendeurizar" las dependencias:
```bash
voxvera vendorize
```
Esto descarga todas las librerías de Python requeridas en `voxvera/vendor/`. La herramienta dará prioridad a estos archivos locales, lo que le permitirá ejecutarse sin `pip install`.
## Importación por lotes (JSON)
Para generar volantes de forma masiva a partir de múltiples archivos de configuración JSON, colóquelos en el directorio `imports/` y ejecute:
```bash
voxvera batch-import
```
## Cómo funcionan las URL
Cada volante tiene dos URL separadas:
- **Enlace desprendible** (generado automáticamente): La dirección .onion donde se hospeda el volante.
- **Enlace de contenido** (configurado por el usuario): Una URL externa que apunta a un sitio web, video o descarga.
No es necesario ingresar manualmente la dirección .onion; VoxVera lo maneja automáticamente durante la fase de `serve`.
-42
View File
@@ -1,42 +0,0 @@
# AI Agent Instructions for VoxVera
This guide is for AI agents (like Gemini, Claude, or GPT) contributing to the VoxVera project. Follow these protocols to maintain the architectural integrity and multi-language support.
## Core Mandates
1. **Security-First**: VoxVera is a Tor-based tool. Never suggest features that leak IP addresses or use non-Tor external resources (CDNs, etc.).
2. **Local-First**: All assets (fonts, dependencies, binaries) must be self-contained within the `voxvera/` package to support the Universal Mirroring model.
3. **Tokenized UI**: Never hardcode user-facing strings. Always add them to `voxvera/locales/en.json` and use the `t('cli.token')` helper.
4. **Markdown Redaction**: Use `~~text~~` in locale JSONs for strike-through effects. Both the build system and the JS engine handle the conversion to `<span class="redacted">` automatically.
5. **Visual Width Testing**: When modifying UI or adding languages, verify that long or complex strings (e.g., Hindi ligatures or CJK characters) do not exceed the visual unit limits defined in the CLI.
## Localization Protocol
When adding a new language or updating an existing one:
- **CLI/Flyers**: Update `voxvera/locales/{lang}.json`. Include `meta`, `cli`, `web`, and `landing` categories.
- **Landing Page**:
- Directly update the `const locales` object in `site/index.html`.
- **Crucial**: Run `voxvera build-site` to generate the latest portable bundle and refresh the pre-rendered HTML.
- **Documentation**:
- Master templates live in `docs/templates/`.
- Localized overrides live in `voxvera/locales/{lang}/docs/`.
- **Crucial**: After any change to locales or templates, you MUST run `voxvera build-docs` to synchronize the output in `docs/{en,es,de}/`.
## Universal Mirroring
VoxVera propagates through its own flyers.
- Every `voxvera build` and `voxvera build-site` generates `voxvera-portable.zip`.
- If you modify the core source code, ensure the `bundle_portable` function in `voxvera/cli.py` still correctly captures all necessary directories (especially `vendor/`, `locales/`, and `resources/`).
## Verification Checklist
Before finishing a task, ensure you have:
1. Run unit tests: `pytest tests/test_cli.py`.
2. Verified the localization: `voxvera --lang {lang} check`.
3. Rebuilt the documentation: `voxvera build-docs`.
4. Synchronized the public site: `voxvera build-site`.
5. Verified the portable bundle exists: `ls -l voxvera/host/*/download/voxvera-portable.zip` and `ls -l site/download/voxvera-portable.zip`.
---
Follow these rules to ensure VoxVera remains a robust, viral, and decentralized tool for truth.
-47
View File
@@ -1,47 +0,0 @@
# Contributing to VoxVera
Thank you for your interest in contributing to VoxVera! This project aims to be a global, censorship-resistant tool, and your help—especially with translations—is vital.
## Adding a New Language
VoxVera uses a centralized token system for the CLI and Web components, and a template-based system for Documentation. To add a new language (e.g., French/`fr`), follow this checklist:
### 1. The Token File
Create a new JSON file in `voxvera/locales/{lang_code}.json`.
- Use `en.json` as your master template.
- **`meta`**: Include the native language name and a flag emoji.
- **`cli`**: Translate all strings used in the terminal interface.
- **`web`**: Translate strings used on the generated landing pages and flyers.
- **`landing`**: Translate the specific content for the official VoxVera website.
- **Formatting**: You can use Markdown-style strike-throughs (`~~redacted text~~`) in any of these strings; they will be automatically converted to the stylized "redacted" effect on the flyers.
### 2. The Landing Page
The main landing page is generated from the shared template and locale files.
- Add your language in `voxvera/locales/{lang_code}.json`.
- Do **not** edit `site/index.html` directly; it is generated output.
- Run `voxvera build-site` to refresh the public assets and inject your new locale into the generated HTML.
### 3. Documentation
VoxVera uses the **Doc-Sync Engine** to keep manuals in sync.
- Create localized Markdown files in `voxvera/locales/{lang_code}/docs/`.
- Use the templates in `docs/templates/` as your guide.
- You can use `cli.token_name` to reference terminal commands automatically.
### 4. Build and Verify
Run the following commands to verify your changes:
- `voxvera --lang {lang_code} check` (Verify CLI translation)
- `voxvera build-docs` (Generate localized manuals)
- `voxvera build-site` (Synchronize the public website and generate the latest portable bundle)
- Open the generated `site/index.html` in a browser and test the language switcher.
## Code Contributions
- **Dependencies**: if you add a new Python library to `requirements.txt`, you MUST run `voxvera vendorize` to include it in the portable distribution.
- **Layout Integrity**: VoxVera uses visual width validation. If you add new UI elements, ensure they respect the physical boundaries of an 8.5"x11" flyer.
- **Tests**: Ensure all tests pass: `pytest tests/`. Run the integrity suite specifically when modifying locales: `pytest tests/test_integrity.py`.
- **Generated artifacts**: Treat `voxvera/resources/bin/` as local build output, not source files. Release binaries belong in GitHub Releases, not hand-edited repo state.
- **Style**: Follow the existing coding style (PEP 8 for Python).
- **Documentation**: If adding a new feature, update the master templates in `docs/templates/` and run `voxvera build-docs`.
---
Together, we can ensure that truth remains accessible to everyone, everywhere.
-19
View File
@@ -1,19 +0,0 @@
# Docker Usage
Experimental: the container path is not yet a production-grade hidden-service deployment target. Linux with `systemd --user` remains the supported persistent-host environment.
A prebuilt image containing Tor, OnionShare and the `voxvera` CLI is published to
`ghcr.io/voxvera/voxvera`.
```bash
# pull the image
docker pull ghcr.io/voxvera/voxvera:latest
# run the experimental container with flyers stored in ./flyers
mkdir -p flyers
docker run -it --rm -v "$(pwd)/flyers:/flyers" ghcr.io/voxvera/voxvera
```
The container stores runtime state under `/flyers`, seeds a default `config.json` if needed, and retries `voxvera start-all` periodically after the initial `quickstart`.
Use this path for testing only until the container runtime and background recovery behavior are validated end-to-end.
-14
View File
@@ -1,14 +0,0 @@
# Flyer Templates
Pre-built flyer templates live in the `templates/` directory. Use the CLI to copy one with:
```bash
voxvera init --template <name>
```
This will create a new folder under `dist/` named `<name>-<YYYYMMDD>` containing the template files.
Available templates:
- **blank** – minimal placeholder files, also used when extracting fields from a PDF.
- **voxvera** – example flyer showcasing the VoxVera project.
-75
View File
@@ -1,75 +0,0 @@
# Troubleshooting
This page collects common issues encountered when hosting or accessing flyers.
## Tor connectivity
- Ensure Tor is allowed through your firewall. On systems using `ufw` you may need to run `sudo ufw allow tor`.
- Some networks block Tor entirely. If you cannot reach onion services, try connecting over a different network or use a Tor bridge.
## Supported deployment target
- The supported persistent-host setup is Linux with `systemd --user`.
- Windows, macOS, Docker, Flatpak, AppImage, Homebrew, and Chocolatey are currently experimental and may not recover hosting automatically after reboot or network interruptions.
## Tor port detection
`voxvera serve` auto-detects Tor by probing common ports (9050/9150 for SOCKS, 9051/9151 for control). If detection fails -- for example when Tor runs on non-standard ports -- you can override with environment variables:
```bash
TOR_SOCKS_PORT=19050 TOR_CONTROL_PORT=19051 voxvera serve
```
If no running Tor is found, the defaults (9050/9051) are used and OnionShare will attempt to connect on those ports.
## Firewall rules
- If `voxvera serve` fails to start OnionShare, verify that outbound connections on ports 9001 and 80 are permitted.
- Corporate or university firewalls can block the hidden service ports required by Tor.
## SELinux
- On SELinux-enabled distributions you may see `permission denied` errors when OnionShare writes to the `host` directory.
- Run `sudo chcon -Rt svirt_sandbox_file_t host` or disable SELinux enforcement for the folder.
## OnionShare crashes
If `voxvera serve` prints "OnionShare exited unexpectedly", check the log file
`host/<folder_name>/onionshare.log` for details. Common causes:
- Tor is not running (`sudo systemctl start tor`)
- A port conflict with another service
- Missing `onionshare-cli` (run `voxvera check`)
## Onion URL changed unexpectedly
The onion URL is tied to the Ed25519 keypair stored in
`host/<folder_name>/.onionshare-session`. If this file is deleted, a new
keypair (and URL) will be generated on the next `voxvera serve`. The
`voxvera import` command preserves this file automatically, but manual
deletion of the `host/` directory will destroy it.
## Hosting does not return after reboot or network loss
On Linux, install or verify the recovery timer:
```bash
voxvera autostart
systemctl --user status voxvera-start.timer
systemctl --user status voxvera-start.service
```
The supported recovery path is the recurring `systemd --user` timer, which reruns `voxvera start-all` every few minutes.
## QR codes not generated
If `voxvera build` reports "No URLs configured yet", this is expected before the first `voxvera serve`. QR codes for tear-off links are generated automatically once the .onion address is known. QR codes for the content link are generated if you provided a URL during `voxvera init`.
## Electron GUI
If `npm start` fails with `spawn voxvera ENOENT`, the `voxvera` command is not in your `PATH`. Install it with `pipx install git+https://github.com/PR0M3TH3AN/VoxVera.git` or run `./install.sh` from the repository.
## Missing dependencies
Run `voxvera check` to verify your setup. The command checks for required
Python packages (`qrcode`, `Pillow`, `jsmin`, `htmlmin`, `pypdf`) and
external tools (`onionshare-cli`), then prints a summary of anything
missing. To install everything:
```bash
# Recommended: use the install script (handles Tor + OnionShare too)
curl -fsSL https://raw.githubusercontent.com/PR0M3TH3AN/VoxVera/main/install.sh | bash
# Or reinstall just the Python package
pipx install --force 'voxvera@git+https://github.com/PR0M3TH3AN/VoxVera.git@main'
```
-130
View File
@@ -1,130 +0,0 @@
# راهنمای استفاده تفصیلی
این راهنما جریان‌های کاری معمول رابط سطر فرمان (CLI) را پوشش می‌دهد. برای دستورالعمل‌های داکر به `docs/docker.md` و برای قالب‌های اعلامیه موجود به `docs/templates.md` مراجعه کنید.
## پیش‌نیازها
ووکس‌ورا (VoxVera) به گونه‌ای طراحی شده است که بسیار قابل حمل باشد و به حداقل وابستگی‌های سیستم نیاز داشته باشد.
### ۱. فایل‌های اجرایی مستقل (توصیه شده)
می‌توانید فایل‌های اجرایی (Binary) مستقل و بدون نیاز به وابستگی را برای سیستم‌عامل خود دانلود کنید:
- **لینوکس:** `voxvera-linux`
- **ویندوز:** `voxvera-windows.exe`
- **مک:** `voxvera-macos`
این فایل‌ها شامل تمام موارد لازم برای اجرای ووکس‌ورا هستند (به جز `onionshare-cli`).
### ۲. نصب‌کننده تک‌خطی
همچنین می‌توانید از طریق اسکریپت خودکار ما نصب را انجام دهید:
```bash
curl -fsSL https://raw.githubusercontent.com/PR0M3TH3AN/VoxVera/main/install.sh | bash
```
### ۳. نصب دستی پایتون
اگر ترجیح می‌دهید از سورس کد استفاده کنید:
```bash
pipx install 'voxvera@git+https://github.com/PR0M3TH3AN/VoxVera.git@main'
sudo apt install tor onionshare-cli # دبیان/اوبونتو
```
## گام به گام
۱. **راه‌اندازی:** دستور `voxvera init` را اجرا کرده و مراحل را دنبال کنید. در ابتدا از شما خواسته می‌شود زبان خود را انتخاب کنید.
۲. **ساخت:** دارایی‌های اعلامیه را ایجاد کنید. هر بار که عملیات ساخت انجام می‌شود، یک فایل `voxvera-portable.zip` به طور خودکار در پوشه اعلامیه ساخته می‌شود که به دیگران اجازه می‌دهد ابزار کامل را مستقیماً از اعلامیه شما دانلود کنند.
```bash
voxvera build
```
۳. **میزبانی:** اعلامیه را روی شبکه تور منتشر کنید:
```bash
voxvera serve
```
این دستور به طور خودکار تور شما را شناسایی کرده، OnionShare را راه‌اندازی می‌کند و آدرس .onion تولید شده را در پیوندهای جداشونده اعلامیه می‌نویسد.
## پشتیبانی از زبان‌ها
ووکس‌ورا کاملاً بومی‌سازی شده است. می‌توانید اولویت زبان خود را به طور دائم با استفاده از انتخاب‌گر تعاملی یا میان‌بر مستقیم تغییر دهید:
- **انتخاب‌گر تعاملی:** `voxvera lang`
- **میان‌بر مستقیم:** `voxvera --lang fa` (تنظیم اولویت روی فارسی)
### زبان‌های پشتیبانی شده:
- **انگلیسی:** `en`
- **اسپانیایی:** `es` (نام مستعار: `--idioma`)
- **آلمانی:** `de` (نام مستعار: `--sprache`)
- **فارسی:** `fa`
همچنین می‌توانید بدون تغییر اولویت دائمی، یک زبان خاص را برای یک دستور واحد اجبار کنید:
- **انگلیسی:** `voxvera --lang en check`
- **فارسی:** `voxvera --lang fa check`
اعلامیه‌های تولید شده به طور خودکار زبان مرورگر بازدیدکننده را تشخیص داده و متن رابط کاربری را بر اساس آن تغییر می‌دهند.
## مدیریت سرورها
چندین اعلامیه و هویت‌های تور آن‌ها را از یک منوی تعاملی واحد مدیریت کنید:
```bash
voxvera manage
```
ویژگی‌ها:
- **--- ایجاد سایت/اعلامیه جدید ---**: شروع توالی کامل تنظیمات.
- **--- اجرای همه سایت‌ها ---**: راه‌اندازی یا توقف همزمان تمام اعلامیه‌های شما.
- **وضعیت لحظه‌ای**: مشاهده آدرس‌های .onion فعال و نشانگرهای پیشرفت تور.
- **کنترل فردی**: صدور به صورت زیپ سایت‌های خاص به فرمت ZIP یا حذف آن‌ها.
## آینه‌سازی همگانی (توزیع ویروسی)
برای اطمینان از اینکه ووکس‌ورا حتی در صورت سانسور مخازن مرکزی در دسترس باقی می‌ماند، هر اعلامیه به عنوان یک آینه برای این ابزار عمل می‌کند.
وقتی اعلامیه‌ای را میزبانی می‌کنید، دکمه **"دانلود ابزار و کد منبع"** در صفحه فرود، یک فایل `voxvera-portable.zip` شامل موارد زیر ارائه می‌دهد:
- سورس کد کامل و تمامی زبان‌های پشتیبانی شده.
- تمامی وابستگی‌های پایتون (از پیش بسته‌بندی شده).
- فایل‌های اجرایی تور برای تمامی پلتفرم‌ها.
این کار به هر کسی که اعلامیه شما را اسکن می‌کند اجازه می‌دهد تا به توزیع‌کننده جدیدی برای ابزار ووکس‌ورا تبدیل شود.
## صدور و پشتیبان‌گیری
از هویت‌های تور منحصر به فرد خود پشتیبان بگیرید (تا آدرس .onion شما هرگز تغییر نکند) یا اعلامیه‌های خود را به سیستم دیگری منتقل کنید.
- **صدور یک سایت واحد:** `voxvera export <folder_name>`
- **صدور تمامی سایت‌ها:** `voxvera export-all`
**محل ذخیره‌سازی:** تمامی موارد صادر شده به صورت فایل ZIP در پوشه‌ای به نام `voxvera-exports` در پوشه خانگی کاربر (`~/voxvera-exports/`) در تمامی پلتفرم‌ها ذخیره می‌شوند.
## وارد کردن و بازیابی
با انتقال فایل‌های ZIP خود به پوشه `~/voxvera-exports/` و اجرای دستور زیر، کل تنظیمات خود را در یک سیستم جدید بازیابی کنید:
```bash
voxvera import-multiple
```
## قابلیت حمل و استفاده آفلاین
اگر نیاز دارید ووکس‌ورا را روی سیستمی بدون دسترسی به اینترنت اجرا کنید، می‌توانید ابتدا وابستگی‌ها را به صورت محلی ذخیره کنید:
```bash
voxvera vendorize
```
این دستور تمامی کتابخانه‌های پایتون مورد نیاز را در پوشه `voxvera/vendor/` دانلود می‌کند. ابزار سپس این فایل‌های محلی را در اولویت قرار می‌دهد و اجازه می‌دهد بدون نیاز به `pip install` اجرا شود.
## وارد کردن گروهی (JSON)
برای تولید انبوه اعلامیه‌ها از چندین فایل تنظیمات JSON، آن‌ها را در پوشه `imports/` قرار داده و اجرا کنید:
```bash
voxvera batch-import
```
## آدرس‌های URL چگونه کار می‌کنند
هر اعلامیه دارای دو آدرس URL جداگانه است:
- **پیوند جداشونده** (تولید خودکار): آدرس .onion که اعلامیه در آن میزبانی می‌شود.
- **پیوند محتوا** (تنظیم توسط کاربر): یک آدرس URL خارجی که به یک وب‌سایت، ویدیو یا فایل دانلود اشاره می‌کند.
نیازی نیست آدرس .onion را به صورت دستی وارد کنید؛ ووکس‌ورا در مرحله میزبانی (`serve`) این کار را به طور خودکار انجام می‌دهد.
+74
View File
@@ -0,0 +1,74 @@
# Flyer Field Length Cheat Sheet
How much text fits in each flyer field, by script.
VoxVera does **not** impose a fixed character count. The editor measures the
rendered flyer live and rejects a keystroke the moment a field would overflow
the printable sheet (you'll see an inline "too long" error under that field).
So the real limit is enforced for you as you type — the numbers below are
practical guidance for drafting copy, sizing translations, or prompting an LLM
to write flyer text that will fit on the first try.
Capacity varies by **script** (not by individual language) and by **paper
size**, for these reasons:
1. The flyer body font is monospace (`Courier New`), so within a script every
character takes the same width regardless of upper/lowercase.
2. Per-script letter-spacing policy (`ls-full` / `ls-cjk` / `ls-none`, see
[`nostr-static-client-spec.md`](nostr-static-client-spec.md#letter-spacing-by-script)).
3. Glyph width differs by script — CJK glyphs are full-width (≈2× a Latin
character), Devanagari fallback glyphs are narrower, etc.
4. **Paper size.** A4 (210×297mm) is slightly narrower and taller than US
Letter (8.5×11in), so single-line fields hold ~2 fewer characters on A4
while the body holds a little more. Both sizes are shown below.
## Single-line fields (hard caps)
**Title**, **Subtitle**, and **Headline** are single-line: they never wrap, so
these are the limits people actually run into. Counts are characters
(codepoints), shown as **Letter / A4**.
| Languages | Title & Headline | Subtitle |
|---|---|---|
| Latin & Cyrillic & Hebrew — en, es, de, fr, pt, sw, tr, ru, he | ~28 / ~26 | ~32 / ~30 |
| Arabic & Persian — ar, fa | ~28 / ~27 | ~38 / ~36 |
| Devanagari — hi | ~36 / ~35 | ~51 / ~48 |
| CJK — ja, zh | ~17 / ~16 | ~23 / ~21 |
## Multi-line fields (generous)
**Body** (content), **Link message** (`url_message`), and **Footer**
(`footer_message`) wrap across multiple lines, so they hold far more and are
bounded only by the remaining height of the sheet.
| Languages | Body (content) — Letter / A4 |
|---|---|
| Latin & Cyrillic & Hebrew | ~1,900 / ~2,000 (a few hundred words) |
| Arabic & Persian | ~1,850 / ~1,930 |
| Devanagari — hi | ~2,450 / ~2,545 |
| CJK — ja, zh | ~1,170 / ~1,220 |
`url_message` and `footer_message` share the lower portion of the sheet and can
hold roughly 1,200–4,800 characters depending on script, but for a readable
flyer keep the link message to a sentence and the footer to a short line.
The **URL** field is a link, not body copy — keep it short both because it's
shown verbatim on the flyer and because it becomes the main QR code (shorter
URLs scan more reliably).
## Notes and caveats
- **Approximate.** These come from rendering each script in a headless browser
at true print size for both Letter (8.5×11in) and A4 (210×297mm). The
Latin/Cyrillic numbers (`Courier New`) are the most reliable; numbers for
Hebrew, Arabic, Persian, Devanagari, and CJK depend on the system fallback
font, which can differ slightly between devices and from print output.
- **The app is authoritative.** If the editor accepts your text it fits; if it
rejects it, shorten it. Treat this sheet as a target, not a contract.
- **Redaction markup counts.** Wrapping text in `~~double tildes~~` renders it
struck-through; the four `~` characters count toward the field length even
though they don't appear on the flyer.
- **Re-measuring.** If the flyer layout, font, or letter-spacing policy
changes, these numbers should be re-derived by rendering each script at print
size and binary-searching each field for the largest run of characters that
does not overflow the field target or the sheet.
-42
View File
@@ -1,42 +0,0 @@
# AI Agent Instructions for VoxVera
This guide is for AI agents (like Gemini, Claude, or GPT) contributing to the VoxVera project. Follow these protocols to maintain the architectural integrity and multi-language support.
## Core Mandates
1. **Security-First**: VoxVera is a Tor-based tool. Never suggest features that leak IP addresses or use non-Tor external resources (CDNs, etc.).
2. **Local-First**: All assets (fonts, dependencies, binaries) must be self-contained within the `voxvera/` package to support the Universal Mirroring model.
3. **Tokenized UI**: Never hardcode user-facing strings. Always add them to `voxvera/locales/en.json` and use the `t('cli.token')` helper.
4. **Markdown Redaction**: Use `~~text~~` in locale JSONs for strike-through effects. Both the build system and the JS engine handle the conversion to `<span class="redacted">` automatically.
5. **Visual Width Testing**: When modifying UI or adding languages, verify that long or complex strings (e.g., Hindi ligatures or CJK characters) do not exceed the visual unit limits defined in the CLI.
## Localization Protocol
When adding a new language or updating an existing one:
- **CLI/Flyers**: Update `voxvera/locales/{lang}.json`. Include `meta`, `cli`, `web`, and `landing` categories.
- **Landing Page**:
- Directly update the `const locales` object in `site/index.html`.
- **Crucial**: Run `voxvera build-site` to generate the latest portable bundle and refresh the pre-rendered HTML.
- **Documentation**:
- Master templates live in `docs/templates/`.
- Localized overrides live in `voxvera/locales/{lang}/docs/`.
- **Crucial**: After any change to locales or templates, you MUST run `voxvera build-docs` to synchronize the output in `docs/{en,es,de}/`.
## Universal Mirroring
VoxVera propagates through its own flyers.
- Every `voxvera build` and `voxvera build-site` generates `voxvera-portable.zip`.
- If you modify the core source code, ensure the `bundle_portable` function in `voxvera/cli.py` still correctly captures all necessary directories (especially `vendor/`, `locales/`, and `resources/`).
## Verification Checklist
Before finishing a task, ensure you have:
1. Run unit tests: `pytest tests/test_cli.py`.
2. Verified the localization: `voxvera --lang {lang} check`.
3. Rebuilt the documentation: `voxvera build-docs`.
4. Synchronized the public site: `voxvera build-site`.
5. Verified the portable bundle exists: `ls -l voxvera/host/*/download/voxvera-portable.zip` and `ls -l site/download/voxvera-portable.zip`.
---
Follow these rules to ensure VoxVera remains a robust, viral, and decentralized tool for truth.
-47
View File
@@ -1,47 +0,0 @@
# Contributing to VoxVera
Thank you for your interest in contributing to VoxVera! This project aims to be a global, censorship-resistant tool, and your help—especially with translations—is vital.
## Adding a New Language
VoxVera uses a centralized token system for the CLI and Web components, and a template-based system for Documentation. To add a new language (e.g., French/`fr`), follow this checklist:
### 1. The Token File
Create a new JSON file in `voxvera/locales/{lang_code}.json`.
- Use `en.json` as your master template.
- **`meta`**: Include the native language name and a flag emoji.
- **`cli`**: Translate all strings used in the terminal interface.
- **`web`**: Translate strings used on the generated landing pages and flyers.
- **`landing`**: Translate the specific content for the official VoxVera website.
- **Formatting**: You can use Markdown-style strike-throughs (`~~redacted text~~`) in any of these strings; they will be automatically converted to the stylized "redacted" effect on the flyers.
### 2. The Landing Page
The main landing page is generated from the shared template and locale files.
- Add your language in `voxvera/locales/{lang_code}.json`.
- Do **not** edit `site/index.html` directly; it is generated output.
- Run `voxvera build-site` to refresh the public assets and inject your new locale into the generated HTML.
### 3. Documentation
VoxVera uses the **Doc-Sync Engine** to keep manuals in sync.
- Create localized Markdown files in `voxvera/locales/{lang_code}/docs/`.
- Use the templates in `docs/templates/` as your guide.
- You can use `cli.token_name` to reference terminal commands automatically.
### 4. Build and Verify
Run the following commands to verify your changes:
- `voxvera --lang {lang_code} check` (Verify CLI translation)
- `voxvera build-docs` (Generate localized manuals)
- `voxvera build-site` (Synchronize the public website and generate the latest portable bundle)
- Open the generated `site/index.html` in a browser and test the language switcher.
## Code Contributions
- **Dependencies**: if you add a new Python library to `requirements.txt`, you MUST run `voxvera vendorize` to include it in the portable distribution.
- **Layout Integrity**: VoxVera uses visual width validation. If you add new UI elements, ensure they respect the physical boundaries of an 8.5"x11" flyer.
- **Tests**: Ensure all tests pass: `pytest tests/`. Run the integrity suite specifically when modifying locales: `pytest tests/test_integrity.py`.
- **Generated artifacts**: Treat `voxvera/resources/bin/` as local build output, not source files. Release binaries belong in GitHub Releases, not hand-edited repo state.
- **Style**: Follow the existing coding style (PEP 8 for Python).
- **Documentation**: If adding a new feature, update the master templates in `docs/templates/` and run `voxvera build-docs`.
---
Together, we can ensure that truth remains accessible to everyone, everywhere.
-19
View File
@@ -1,19 +0,0 @@
# Docker Usage
Experimental: the container path is not yet a production-grade hidden-service deployment target. Linux with `systemd --user` remains the supported persistent-host environment.
A prebuilt image containing Tor, OnionShare and the `voxvera` CLI is published to
`ghcr.io/voxvera/voxvera`.
```bash
# pull the image
docker pull ghcr.io/voxvera/voxvera:latest
# run the experimental container with flyers stored in ./flyers
mkdir -p flyers
docker run -it --rm -v "$(pwd)/flyers:/flyers" ghcr.io/voxvera/voxvera
```
The container stores runtime state under `/flyers`, seeds a default `config.json` if needed, and retries `voxvera start-all` periodically after the initial `quickstart`.
Use this path for testing only until the container runtime and background recovery behavior are validated end-to-end.
-14
View File
@@ -1,14 +0,0 @@
# Flyer Templates
Pre-built flyer templates live in the `templates/` directory. Use the CLI to copy one with:
```bash
voxvera init --template <name>
```
This will create a new folder under `dist/` named `<name>-<YYYYMMDD>` containing the template files.
Available templates:
- **blank** – minimal placeholder files, also used when extracting fields from a PDF.
- **voxvera** – example flyer showcasing the VoxVera project.
-75
View File
@@ -1,75 +0,0 @@
# Troubleshooting
This page collects common issues encountered when hosting or accessing flyers.
## Tor connectivity
- Ensure Tor is allowed through your firewall. On systems using `ufw` you may need to run `sudo ufw allow tor`.
- Some networks block Tor entirely. If you cannot reach onion services, try connecting over a different network or use a Tor bridge.
## Supported deployment target
- The supported persistent-host setup is Linux with `systemd --user`.
- Windows, macOS, Docker, Flatpak, AppImage, Homebrew, and Chocolatey are currently experimental and may not recover hosting automatically after reboot or network interruptions.
## Tor port detection
`voxvera serve` auto-detects Tor by probing common ports (9050/9150 for SOCKS, 9051/9151 for control). If detection fails -- for example when Tor runs on non-standard ports -- you can override with environment variables:
```bash
TOR_SOCKS_PORT=19050 TOR_CONTROL_PORT=19051 voxvera serve
```
If no running Tor is found, the defaults (9050/9051) are used and OnionShare will attempt to connect on those ports.
## Firewall rules
- If `voxvera serve` fails to start OnionShare, verify that outbound connections on ports 9001 and 80 are permitted.
- Corporate or university firewalls can block the hidden service ports required by Tor.
## SELinux
- On SELinux-enabled distributions you may see `permission denied` errors when OnionShare writes to the `host` directory.
- Run `sudo chcon -Rt svirt_sandbox_file_t host` or disable SELinux enforcement for the folder.
## OnionShare crashes
If `voxvera serve` prints "OnionShare exited unexpectedly", check the log file
`host/<folder_name>/onionshare.log` for details. Common causes:
- Tor is not running (`sudo systemctl start tor`)
- A port conflict with another service
- Missing `onionshare-cli` (run `voxvera check`)
## Onion URL changed unexpectedly
The onion URL is tied to the Ed25519 keypair stored in
`host/<folder_name>/.onionshare-session`. If this file is deleted, a new
keypair (and URL) will be generated on the next `voxvera serve`. The
`voxvera import` command preserves this file automatically, but manual
deletion of the `host/` directory will destroy it.
## Hosting does not return after reboot or network loss
On Linux, install or verify the recovery timer:
```bash
voxvera autostart
systemctl --user status voxvera-start.timer
systemctl --user status voxvera-start.service
```
The supported recovery path is the recurring `systemd --user` timer, which reruns `voxvera start-all` every few minutes.
## QR codes not generated
If `voxvera build` reports "No URLs configured yet", this is expected before the first `voxvera serve`. QR codes for tear-off links are generated automatically once the .onion address is known. QR codes for the content link are generated if you provided a URL during `voxvera init`.
## Electron GUI
If `npm start` fails with `spawn voxvera ENOENT`, the `voxvera` command is not in your `PATH`. Install it with `pipx install git+https://github.com/PR0M3TH3AN/VoxVera.git` or run `./install.sh` from the repository.
## Missing dependencies
Run `voxvera check` to verify your setup. The command checks for required
Python packages (`qrcode`, `Pillow`, `jsmin`, `htmlmin`, `pypdf`) and
external tools (`onionshare-cli`), then prints a summary of anything
missing. To install everything:
```bash
# Recommended: use the install script (handles Tor + OnionShare too)
curl -fsSL https://raw.githubusercontent.com/PR0M3TH3AN/VoxVera/main/install.sh | bash
# Or reinstall just the Python package
pipx install --force 'voxvera@git+https://github.com/PR0M3TH3AN/VoxVera.git@main'
```
-130
View File
@@ -1,130 +0,0 @@
# Utilisation détaillée
Ce guide couvre les flux de travail CLI courants. Consultez `docs/docker.md` pour les instructions Docker et `docs/templates.md` pour les modèles de flyers disponibles.
## Prérequis
VoxVera est conçu pour être hautement portable et nécessite un minimum de dépendances système.
### 1. Binaires autonomes (Recommandé)
Vous pouvez télécharger des binaires autonomes sans dépendance pour votre système d'exploitation :
- **Linux :** `voxvera-linux`
- **Windows :** `voxvera-windows.exe`
- **macOS :** `voxvera-macos`
Ces binaires incluent tout le nécessaire pour exécuter VoxVera (sauf `onionshare-cli`).
### 2. Installateur en une ligne
Alternativement, installez via notre script automatisé :
```bash
curl -fsSL https://raw.githubusercontent.com/PR0M3TH3AN/VoxVera/main/install.sh | bash
```
### 3. Installation Python manuelle
Si vous préférez exécuter à partir des sources :
```bash
pipx install 'voxvera@git+https://github.com/PR0M3TH3AN/VoxVera.git@main'
sudo apt install tor onionshare-cli # Debian/Ubuntu
```
## Étape par étape
1. **Initialiser :** Exécutez `voxvera init` et suivez les instructions. Il vous sera demandé de choisir votre langue en premier.
2. **Construire :** Générez les fichiers du flyer. Chaque construction crée automatiquement un `voxvera-portable.zip` dans le dossier du flyer, permettant aux autres de télécharger l'outil complet directement depuis votre flyer.
```bash
voxvera build
```
3. **Servir :** Publiez le flyer sur Tor :
```bash
voxvera serve
```
Ceci détecte automatiquement votre instance Tor, démarre OnionShare et écrit l'adresse .onion générée dans les liens détachables du flyer.
## Support linguistique
VoxVera est entièrement localisé. Vous pouvez changer votre préférence linguistique de manière permanente en utilisant soit le sélecteur interactif, soit un raccourci direct :
- **Sélecteur interactif :** `voxvera lang`
- **Raccourci direct :** `voxvera --lang fr` (définit la préférence sur le français)
### Langues supportées :
- **Anglais :** `en`
- **Espagnol :** `es` (alias : `--idioma`)
- **Allemand :** `de` (alias : `--sprache`)
- **Français :** `fr`
Vous pouvez également forcer une langue spécifique pour une seule commande sans changer votre préférence permanente :
- **Anglais :** `voxvera --lang en check`
- **Français :** `voxvera --lang fr check`
Les flyers générés détectent automatiquement la langue du navigateur du visiteur et adaptent le texte de l'interface en conséquence.
## Gestion des serveurs
Gérez plusieurs flyers et leurs identités Tor à partir d'un seul menu interactif :
```bash
voxvera manage
```
Fonctionnalités :
- **--- Créer un nouveau site/flyer ---** : Démarre la séquence de configuration complète.
- **--- Démarrer tous les sites ---** : Lance ou arrête tous les flyers de votre flotte en une seule fois.
- **Statut en temps réel** : Visualisez les URL .onion actives et les indicateurs de progression de l'amorçage Tor.
- **Contrôle individuel** : Exporter en Zip des sites spécifiques vers ZIP ou supprimez-les.
## Mise en miroir universelle (Distribution virale)
Pour garantir que VoxVera reste accessible même si les dépôts centraux sont censurés, chaque flyer agit comme un miroir pour l'outil.
Lorsque vous hébergez un flyer, le bouton **"Télécharger l'outil et le code"** sur la page d'accueil fournit un `voxvera-portable.zip` contenant :
- Le code source complet et toutes les langues supportées.
- Toutes les dépendances Python (pré-vendues).
- Les binaires Tor multiplateformes.
Cela permet à quiconque scanne votre flyer de devenir un nouveau distributeur de l'outil VoxVera.
## Exportation & Sauvegarde
Sauvegardez vos identités Tor uniques (pour que votre URL .onion ne change jamais) ou déplacez vos flyers vers une autre machine.
- **Exporter un seul site** : `voxvera export <nom_du_dossier>`
- **Exporter tous les sites** : `voxvera export-all`
**Lieu de stockage :** Toutes les exportations sont sauvegardées dans `~/voxvera-exports/` sur toutes les plateformes.
## Importation & Récupération
Restaurez toute votre configuration sur une nouvelle machine en déplaçant vos fichiers ZIP vers `~/voxvera-exports/` et en exécutant :
```bash
voxvera import-multiple
```
## Portabilité & Utilisation hors ligne
Si vous devez exécuter VoxVera sur une machine sans accès à Internet, vous pouvez d'abord "vendeuriser" les dépendances :
```bash
voxvera vendorize
```
Ceci télécharge toutes les bibliothèques Python requises dans `voxvera/vendor/`. L'outil donnera alors la priorité à ces fichiers locaux, lui permettant de s'exécuter sans `pip install`.
## Importation par lot (JSON)
Pour générer en masse des flyers à partir de plusieurs fichiers de configuration JSON, placez-les dans le répertoire `imports/` et exécutez :
```bash
voxvera batch-import
```
## Comment fonctionnent les URL
Chaque flyer possède deux URL distinctes :
- **Lien détachable** (auto-généré) : L'adresse .onion où le flyer est hébergé.
- **Lien de contenu** (configuré par l'utilisateur) : Une URL externe pointant vers un site web, une vidéo ou un téléchargement.
Vous n'avez pas besoin de saisir manuellement l'adresse .onion ; VoxVera s'en occupe automatiquement pendant la phase `serve`.
-42
View File
@@ -1,42 +0,0 @@
# AI Agent Instructions for VoxVera
This guide is for AI agents (like Gemini, Claude, or GPT) contributing to the VoxVera project. Follow these protocols to maintain the architectural integrity and multi-language support.
## Core Mandates
1. **Security-First**: VoxVera is a Tor-based tool. Never suggest features that leak IP addresses or use non-Tor external resources (CDNs, etc.).
2. **Local-First**: All assets (fonts, dependencies, binaries) must be self-contained within the `voxvera/` package to support the Universal Mirroring model.
3. **Tokenized UI**: Never hardcode user-facing strings. Always add them to `voxvera/locales/en.json` and use the `t('cli.token')` helper.
4. **Markdown Redaction**: Use `~~text~~` in locale JSONs for strike-through effects. Both the build system and the JS engine handle the conversion to `<span class="redacted">` automatically.
5. **Visual Width Testing**: When modifying UI or adding languages, verify that long or complex strings (e.g., Hindi ligatures or CJK characters) do not exceed the visual unit limits defined in the CLI.
## Localization Protocol
When adding a new language or updating an existing one:
- **CLI/Flyers**: Update `voxvera/locales/{lang}.json`. Include `meta`, `cli`, `web`, and `landing` categories.
- **Landing Page**:
- Directly update the `const locales` object in `site/index.html`.
- **Crucial**: Run `voxvera build-site` to generate the latest portable bundle and refresh the pre-rendered HTML.
- **Documentation**:
- Master templates live in `docs/templates/`.
- Localized overrides live in `voxvera/locales/{lang}/docs/`.
- **Crucial**: After any change to locales or templates, you MUST run `voxvera build-docs` to synchronize the output in `docs/{en,es,de}/`.
## Universal Mirroring
VoxVera propagates through its own flyers.
- Every `voxvera build` and `voxvera build-site` generates `voxvera-portable.zip`.
- If you modify the core source code, ensure the `bundle_portable` function in `voxvera/cli.py` still correctly captures all necessary directories (especially `vendor/`, `locales/`, and `resources/`).
## Verification Checklist
Before finishing a task, ensure you have:
1. Run unit tests: `pytest tests/test_cli.py`.
2. Verified the localization: `voxvera --lang {lang} check`.
3. Rebuilt the documentation: `voxvera build-docs`.
4. Synchronized the public site: `voxvera build-site`.
5. Verified the portable bundle exists: `ls -l voxvera/host/*/download/voxvera-portable.zip` and `ls -l site/download/voxvera-portable.zip`.
---
Follow these rules to ensure VoxVera remains a robust, viral, and decentralized tool for truth.
-47
View File
@@ -1,47 +0,0 @@
# Contributing to VoxVera
Thank you for your interest in contributing to VoxVera! This project aims to be a global, censorship-resistant tool, and your help—especially with translations—is vital.
## Adding a New Language
VoxVera uses a centralized token system for the CLI and Web components, and a template-based system for Documentation. To add a new language (e.g., French/`fr`), follow this checklist:
### 1. The Token File
Create a new JSON file in `voxvera/locales/{lang_code}.json`.
- Use `en.json` as your master template.
- **`meta`**: Include the native language name and a flag emoji.
- **`cli`**: Translate all strings used in the terminal interface.
- **`web`**: Translate strings used on the generated landing pages and flyers.
- **`landing`**: Translate the specific content for the official VoxVera website.
- **Formatting**: You can use Markdown-style strike-throughs (`~~redacted text~~`) in any of these strings; they will be automatically converted to the stylized "redacted" effect on the flyers.
### 2. The Landing Page
The main landing page is generated from the shared template and locale files.
- Add your language in `voxvera/locales/{lang_code}.json`.
- Do **not** edit `site/index.html` directly; it is generated output.
- Run `voxvera build-site` to refresh the public assets and inject your new locale into the generated HTML.
### 3. Documentation
VoxVera uses the **Doc-Sync Engine** to keep manuals in sync.
- Create localized Markdown files in `voxvera/locales/{lang_code}/docs/`.
- Use the templates in `docs/templates/` as your guide.
- You can use `cli.token_name` to reference terminal commands automatically.
### 4. Build and Verify
Run the following commands to verify your changes:
- `voxvera --lang {lang_code} check` (Verify CLI translation)
- `voxvera build-docs` (Generate localized manuals)
- `voxvera build-site` (Synchronize the public website and generate the latest portable bundle)
- Open the generated `site/index.html` in a browser and test the language switcher.
## Code Contributions
- **Dependencies**: if you add a new Python library to `requirements.txt`, you MUST run `voxvera vendorize` to include it in the portable distribution.
- **Layout Integrity**: VoxVera uses visual width validation. If you add new UI elements, ensure they respect the physical boundaries of an 8.5"x11" flyer.
- **Tests**: Ensure all tests pass: `pytest tests/`. Run the integrity suite specifically when modifying locales: `pytest tests/test_integrity.py`.
- **Generated artifacts**: Treat `voxvera/resources/bin/` as local build output, not source files. Release binaries belong in GitHub Releases, not hand-edited repo state.
- **Style**: Follow the existing coding style (PEP 8 for Python).
- **Documentation**: If adding a new feature, update the master templates in `docs/templates/` and run `voxvera build-docs`.
---
Together, we can ensure that truth remains accessible to everyone, everywhere.
-19
View File
@@ -1,19 +0,0 @@
# Docker Usage
Experimental: the container path is not yet a production-grade hidden-service deployment target. Linux with `systemd --user` remains the supported persistent-host environment.
A prebuilt image containing Tor, OnionShare and the `voxvera` CLI is published to
`ghcr.io/voxvera/voxvera`.
```bash
# pull the image
docker pull ghcr.io/voxvera/voxvera:latest
# run the experimental container with flyers stored in ./flyers
mkdir -p flyers
docker run -it --rm -v "$(pwd)/flyers:/flyers" ghcr.io/voxvera/voxvera
```
The container stores runtime state under `/flyers`, seeds a default `config.json` if needed, and retries `voxvera start-all` periodically after the initial `quickstart`.
Use this path for testing only until the container runtime and background recovery behavior are validated end-to-end.
-14
View File
@@ -1,14 +0,0 @@
# Flyer Templates
Pre-built flyer templates live in the `templates/` directory. Use the CLI to copy one with:
```bash
voxvera init --template <name>
```
This will create a new folder under `dist/` named `<name>-<YYYYMMDD>` containing the template files.
Available templates:
- **blank** – minimal placeholder files, also used when extracting fields from a PDF.
- **voxvera** – example flyer showcasing the VoxVera project.
-75
View File
@@ -1,75 +0,0 @@
# Troubleshooting
This page collects common issues encountered when hosting or accessing flyers.
## Tor connectivity
- Ensure Tor is allowed through your firewall. On systems using `ufw` you may need to run `sudo ufw allow tor`.
- Some networks block Tor entirely. If you cannot reach onion services, try connecting over a different network or use a Tor bridge.
## Supported deployment target
- The supported persistent-host setup is Linux with `systemd --user`.
- Windows, macOS, Docker, Flatpak, AppImage, Homebrew, and Chocolatey are currently experimental and may not recover hosting automatically after reboot or network interruptions.
## Tor port detection
`voxvera serve` auto-detects Tor by probing common ports (9050/9150 for SOCKS, 9051/9151 for control). If detection fails -- for example when Tor runs on non-standard ports -- you can override with environment variables:
```bash
TOR_SOCKS_PORT=19050 TOR_CONTROL_PORT=19051 voxvera serve
```
If no running Tor is found, the defaults (9050/9051) are used and OnionShare will attempt to connect on those ports.
## Firewall rules
- If `voxvera serve` fails to start OnionShare, verify that outbound connections on ports 9001 and 80 are permitted.
- Corporate or university firewalls can block the hidden service ports required by Tor.
## SELinux
- On SELinux-enabled distributions you may see `permission denied` errors when OnionShare writes to the `host` directory.
- Run `sudo chcon -Rt svirt_sandbox_file_t host` or disable SELinux enforcement for the folder.
## OnionShare crashes
If `voxvera serve` prints "OnionShare exited unexpectedly", check the log file
`host/<folder_name>/onionshare.log` for details. Common causes:
- Tor is not running (`sudo systemctl start tor`)
- A port conflict with another service
- Missing `onionshare-cli` (run `voxvera check`)
## Onion URL changed unexpectedly
The onion URL is tied to the Ed25519 keypair stored in
`host/<folder_name>/.onionshare-session`. If this file is deleted, a new
keypair (and URL) will be generated on the next `voxvera serve`. The
`voxvera import` command preserves this file automatically, but manual
deletion of the `host/` directory will destroy it.
## Hosting does not return after reboot or network loss
On Linux, install or verify the recovery timer:
```bash
voxvera autostart
systemctl --user status voxvera-start.timer
systemctl --user status voxvera-start.service
```
The supported recovery path is the recurring `systemd --user` timer, which reruns `voxvera start-all` every few minutes.
## QR codes not generated
If `voxvera build` reports "No URLs configured yet", this is expected before the first `voxvera serve`. QR codes for tear-off links are generated automatically once the .onion address is known. QR codes for the content link are generated if you provided a URL during `voxvera init`.
## Electron GUI
If `npm start` fails with `spawn voxvera ENOENT`, the `voxvera` command is not in your `PATH`. Install it with `pipx install git+https://github.com/PR0M3TH3AN/VoxVera.git` or run `./install.sh` from the repository.
## Missing dependencies
Run `voxvera check` to verify your setup. The command checks for required
Python packages (`qrcode`, `Pillow`, `jsmin`, `htmlmin`, `pypdf`) and
external tools (`onionshare-cli`), then prints a summary of anything
missing. To install everything:
```bash
# Recommended: use the install script (handles Tor + OnionShare too)
curl -fsSL https://raw.githubusercontent.com/PR0M3TH3AN/VoxVera/main/install.sh | bash
# Or reinstall just the Python package
pipx install --force 'voxvera@git+https://github.com/PR0M3TH3AN/VoxVera.git@main'
```
-152
View File
@@ -1,152 +0,0 @@
# Detailed Usage
This guide covers common CLI workflows. See `docs/docker.md` for Docker instructions and `docs/templates.md` for available flyer templates.
## Prerequisites
VoxVera is designed to be highly portable. You can run it directly from the source code on any platform with Python installed.
Linux with `systemd --user` is the supported persistent-host environment. Windows, macOS, Docker, Flatpak, AppImage, Homebrew, and Chocolatey are currently experimental and should not yet be treated as equally reliable hidden-service deployment targets.
### 1. Automated Install (Recommended)
The easiest way to install VoxVera is using the Linux-first installer script:
**Linux / macOS:**
```bash
curl -fsSL https://raw.githubusercontent.com/PR0M3TH3AN/VoxVera/main/install.sh | bash
```
On Linux, this also installs the recurring recovery timer used to retry hidden-service startup after boot and after missed/offline periods.
**Windows (PowerShell):**
```powershell
irm https://raw.githubusercontent.com/PR0M3TH3AN/VoxVera/main/install.ps1 | iex
```
The Windows installer is experimental and does not yet guarantee production-ready background hosting behavior.
### 2. Manual Source Install
If you have downloaded the source code ZIP:
1. **Extract** the ZIP file.
2. **Open a terminal** in the extracted folder.
3. **Run the setup script**:
- **Linux/macOS:** `./setup.sh`
- **Windows:** `.\voxvera-install.sh` (or run `python -m pip install .`)
## Uninstallation
If you wish to remove VoxVera from your system, you can use the provided uninstall scripts from the source directory. This will safely remove the CLI tool and any downloaded dependencies.
- **Linux / macOS:** Run `./uninstall.sh`
- **Windows (PowerShell):** Run `.\uninstall.ps1`
*Note: Uninstallation will not delete your generated flyers or your `.onion` keys stored in the `~/voxvera-exports` or local `host/` folders.*
## Step-by-Step
1. **Initialize:** Run `voxvera init` and follow the prompts. You will be asked to select your language first.
2. **Build:** Generate the flyer assets. Every build automatically creates a `voxvera-portable.zip` in the flyer's folder, allowing others to download the full tool directly from your flyer.
```bash
voxvera build
```
3. **Serve:** Publish the flyer over Tor:
```bash
voxvera serve
```
This automatically detects your Tor instance, starts OnionShare, and writes the generated .onion address into the flyer's tear-off links.
### Persistent Hosting On Linux
For a machine that should resume hosting automatically after boot or after being offline, install the autostart recovery timer:
```bash
voxvera autostart
```
This installs a `systemd --user` timer that reruns `voxvera start-all` every few minutes. The retry loop is the supported way to recover hidden-service hosting after suspend, reboot, or temporary network loss.
## Language Support
VoxVera is fully localized. You can change your language preference permanently using either the interactive selector or a direct shortcut:
- **Interactive Selector:** `voxvera lang`
- **Direct Shortcut:** `voxvera --lang de` (sets preference to German)
### Supported Languages:
- **English:** `en`
- **Spanish:** `es` (alias: `--idioma`)
- **German:** `de` (alias: `--sprache`)
You can also force a specific language for a single command without changing your permanent preference:
- **English:** `voxvera --lang en check`
- **German:** `voxvera --sprache de check`
- **Spanish:** `voxvera --idioma es check`
The generated flyers automatically detect the visitor's browser language and switch the UI text accordingly.
## Server Management
Manage multiple flyers and their Tor identities from a single interactive menu:
```bash
voxvera manage
```
Features:
- **--- צור אתר/פלייר חדש ---**: Start the full setup sequence.
- **--- הפעל את כל האתרים ---**: Launch or shut down every flyer in your fleet at once.
- **Real-time Status**: View active `.onion` URLs and Tor bootstrapping progress indicators.
- **Individual Control**: ייצא ל-Zip specific sites to ZIP or delete them.
## Universal Mirroring (Viral Distribution)
To ensure VoxVera remains accessible even if central repositories are censored, every flyer acts as a mirror for the tool.
When you host a flyer, the **"הורד כלי וקוד מקור"** button on the landing page provides a `voxvera-source.zip` containing:
- The full source code and all supported languages.
- Installation and setup scripts for all platforms.
- Complete documentation and templates.
This allows anyone who scans your flyer to become a new distributor of the VoxVera tool.
## Export & Backup
Back up your unique Tor identities (so your `.onion` URL never changes) or move your flyers to another machine.
- **Export a single site**: `voxvera export <folder_name>`
- **Export all sites**: `voxvera export-all`
**Storage location:** All exports are saved to `~/voxvera-exports/` on all platforms.
## Import & Recovery
Restore your entire setup on a new machine by moving your ZIP files to `~/voxvera-exports/` and running:
```bash
voxvera import-multiple
```
## Portability & Offline Use
If you need to run VoxVera on a machine without internet access, you can "vendorize" the dependencies first:
```bash
voxvera vendorize
```
This downloads all required Python libraries into `voxvera/vendor/`. The tool will then prioritize these local files, allowing it to run without `pip install`.
## Batch Import (JSON)
To bulk-generate flyers from multiple JSON configuration files, place them in the `imports/` directory and run:
```bash
voxvera batch-import
```
## How URLs Work
Each flyer has two separate URLs:
- **Tear-off link** (auto-generated): The .onion address where the flyer is hosted.
- **Content link** (user-configured): An external URL pointing to a website, video, or download.
You do not need to manually enter the .onion address; VoxVera handles this automatically during the `serve` phase.
-42
View File
@@ -1,42 +0,0 @@
# AI Agent Instructions for VoxVera
This guide is for AI agents (like Gemini, Claude, or GPT) contributing to the VoxVera project. Follow these protocols to maintain the architectural integrity and multi-language support.
## Core Mandates
1. **Security-First**: VoxVera is a Tor-based tool. Never suggest features that leak IP addresses or use non-Tor external resources (CDNs, etc.).
2. **Local-First**: All assets (fonts, dependencies, binaries) must be self-contained within the `voxvera/` package to support the Universal Mirroring model.
3. **Tokenized UI**: Never hardcode user-facing strings. Always add them to `voxvera/locales/en.json` and use the `t('cli.token')` helper.
4. **Markdown Redaction**: Use `~~text~~` in locale JSONs for strike-through effects. Both the build system and the JS engine handle the conversion to `<span class="redacted">` automatically.
5. **Visual Width Testing**: When modifying UI or adding languages, verify that long or complex strings (e.g., Hindi ligatures or CJK characters) do not exceed the visual unit limits defined in the CLI.
## Localization Protocol
When adding a new language or updating an existing one:
- **CLI/Flyers**: Update `voxvera/locales/{lang}.json`. Include `meta`, `cli`, `web`, and `landing` categories.
- **Landing Page**:
- Directly update the `const locales` object in `site/index.html`.
- **Crucial**: Run `voxvera build-site` to generate the latest portable bundle and refresh the pre-rendered HTML.
- **Documentation**:
- Master templates live in `docs/templates/`.
- Localized overrides live in `voxvera/locales/{lang}/docs/`.
- **Crucial**: After any change to locales or templates, you MUST run `voxvera build-docs` to synchronize the output in `docs/{en,es,de}/`.
## Universal Mirroring
VoxVera propagates through its own flyers.
- Every `voxvera build` and `voxvera build-site` generates `voxvera-portable.zip`.
- If you modify the core source code, ensure the `bundle_portable` function in `voxvera/cli.py` still correctly captures all necessary directories (especially `vendor/`, `locales/`, and `resources/`).
## Verification Checklist
Before finishing a task, ensure you have:
1. Run unit tests: `pytest tests/test_cli.py`.
2. Verified the localization: `voxvera --lang {lang} check`.
3. Rebuilt the documentation: `voxvera build-docs`.
4. Synchronized the public site: `voxvera build-site`.
5. Verified the portable bundle exists: `ls -l voxvera/host/*/download/voxvera-portable.zip` and `ls -l site/download/voxvera-portable.zip`.
---
Follow these rules to ensure VoxVera remains a robust, viral, and decentralized tool for truth.
-47
View File
@@ -1,47 +0,0 @@
# Contributing to VoxVera
Thank you for your interest in contributing to VoxVera! This project aims to be a global, censorship-resistant tool, and your help—especially with translations—is vital.
## Adding a New Language
VoxVera uses a centralized token system for the CLI and Web components, and a template-based system for Documentation. To add a new language (e.g., French/`fr`), follow this checklist:
### 1. The Token File
Create a new JSON file in `voxvera/locales/{lang_code}.json`.
- Use `en.json` as your master template.
- **`meta`**: Include the native language name and a flag emoji.
- **`cli`**: Translate all strings used in the terminal interface.
- **`web`**: Translate strings used on the generated landing pages and flyers.
- **`landing`**: Translate the specific content for the official VoxVera website.
- **Formatting**: You can use Markdown-style strike-throughs (`~~redacted text~~`) in any of these strings; they will be automatically converted to the stylized "redacted" effect on the flyers.
### 2. The Landing Page
The main landing page is generated from the shared template and locale files.
- Add your language in `voxvera/locales/{lang_code}.json`.
- Do **not** edit `site/index.html` directly; it is generated output.
- Run `voxvera build-site` to refresh the public assets and inject your new locale into the generated HTML.
### 3. Documentation
VoxVera uses the **Doc-Sync Engine** to keep manuals in sync.
- Create localized Markdown files in `voxvera/locales/{lang_code}/docs/`.
- Use the templates in `docs/templates/` as your guide.
- You can use `cli.token_name` to reference terminal commands automatically.
### 4. Build and Verify
Run the following commands to verify your changes:
- `voxvera --lang {lang_code} check` (Verify CLI translation)
- `voxvera build-docs` (Generate localized manuals)
- `voxvera build-site` (Synchronize the public website and generate the latest portable bundle)
- Open the generated `site/index.html` in a browser and test the language switcher.
## Code Contributions
- **Dependencies**: if you add a new Python library to `requirements.txt`, you MUST run `voxvera vendorize` to include it in the portable distribution.
- **Layout Integrity**: VoxVera uses visual width validation. If you add new UI elements, ensure they respect the physical boundaries of an 8.5"x11" flyer.
- **Tests**: Ensure all tests pass: `pytest tests/`. Run the integrity suite specifically when modifying locales: `pytest tests/test_integrity.py`.
- **Generated artifacts**: Treat `voxvera/resources/bin/` as local build output, not source files. Release binaries belong in GitHub Releases, not hand-edited repo state.
- **Style**: Follow the existing coding style (PEP 8 for Python).
- **Documentation**: If adding a new feature, update the master templates in `docs/templates/` and run `voxvera build-docs`.
---
Together, we can ensure that truth remains accessible to everyone, everywhere.
-19
View File
@@ -1,19 +0,0 @@
# Docker Usage
Experimental: the container path is not yet a production-grade hidden-service deployment target. Linux with `systemd --user` remains the supported persistent-host environment.
A prebuilt image containing Tor, OnionShare and the `voxvera` CLI is published to
`ghcr.io/voxvera/voxvera`.
```bash
# pull the image
docker pull ghcr.io/voxvera/voxvera:latest
# run the experimental container with flyers stored in ./flyers
mkdir -p flyers
docker run -it --rm -v "$(pwd)/flyers:/flyers" ghcr.io/voxvera/voxvera
```
The container stores runtime state under `/flyers`, seeds a default `config.json` if needed, and retries `voxvera start-all` periodically after the initial `quickstart`.
Use this path for testing only until the container runtime and background recovery behavior are validated end-to-end.
-14
View File
@@ -1,14 +0,0 @@
# Flyer Templates
Pre-built flyer templates live in the `templates/` directory. Use the CLI to copy one with:
```bash
voxvera init --template <name>
```
This will create a new folder under `dist/` named `<name>-<YYYYMMDD>` containing the template files.
Available templates:
- **blank** – minimal placeholder files, also used when extracting fields from a PDF.
- **voxvera** – example flyer showcasing the VoxVera project.
-75
View File
@@ -1,75 +0,0 @@
# Troubleshooting
This page collects common issues encountered when hosting or accessing flyers.
## Tor connectivity
- Ensure Tor is allowed through your firewall. On systems using `ufw` you may need to run `sudo ufw allow tor`.
- Some networks block Tor entirely. If you cannot reach onion services, try connecting over a different network or use a Tor bridge.
## Supported deployment target
- The supported persistent-host setup is Linux with `systemd --user`.
- Windows, macOS, Docker, Flatpak, AppImage, Homebrew, and Chocolatey are currently experimental and may not recover hosting automatically after reboot or network interruptions.
## Tor port detection
`voxvera serve` auto-detects Tor by probing common ports (9050/9150 for SOCKS, 9051/9151 for control). If detection fails -- for example when Tor runs on non-standard ports -- you can override with environment variables:
```bash
TOR_SOCKS_PORT=19050 TOR_CONTROL_PORT=19051 voxvera serve
```
If no running Tor is found, the defaults (9050/9051) are used and OnionShare will attempt to connect on those ports.
## Firewall rules
- If `voxvera serve` fails to start OnionShare, verify that outbound connections on ports 9001 and 80 are permitted.
- Corporate or university firewalls can block the hidden service ports required by Tor.
## SELinux
- On SELinux-enabled distributions you may see `permission denied` errors when OnionShare writes to the `host` directory.
- Run `sudo chcon -Rt svirt_sandbox_file_t host` or disable SELinux enforcement for the folder.
## OnionShare crashes
If `voxvera serve` prints "OnionShare exited unexpectedly", check the log file
`host/<folder_name>/onionshare.log` for details. Common causes:
- Tor is not running (`sudo systemctl start tor`)
- A port conflict with another service
- Missing `onionshare-cli` (run `voxvera check`)
## Onion URL changed unexpectedly
The onion URL is tied to the Ed25519 keypair stored in
`host/<folder_name>/.onionshare-session`. If this file is deleted, a new
keypair (and URL) will be generated on the next `voxvera serve`. The
`voxvera import` command preserves this file automatically, but manual
deletion of the `host/` directory will destroy it.
## Hosting does not return after reboot or network loss
On Linux, install or verify the recovery timer:
```bash
voxvera autostart
systemctl --user status voxvera-start.timer
systemctl --user status voxvera-start.service
```
The supported recovery path is the recurring `systemd --user` timer, which reruns `voxvera start-all` every few minutes.
## QR codes not generated
If `voxvera build` reports "No URLs configured yet", this is expected before the first `voxvera serve`. QR codes for tear-off links are generated automatically once the .onion address is known. QR codes for the content link are generated if you provided a URL during `voxvera init`.
## Electron GUI
If `npm start` fails with `spawn voxvera ENOENT`, the `voxvera` command is not in your `PATH`. Install it with `pipx install git+https://github.com/PR0M3TH3AN/VoxVera.git` or run `./install.sh` from the repository.
## Missing dependencies
Run `voxvera check` to verify your setup. The command checks for required
Python packages (`qrcode`, `Pillow`, `jsmin`, `htmlmin`, `pypdf`) and
external tools (`onionshare-cli`), then prints a summary of anything
missing. To install everything:
```bash
# Recommended: use the install script (handles Tor + OnionShare too)
curl -fsSL https://raw.githubusercontent.com/PR0M3TH3AN/VoxVera/main/install.sh | bash
# Or reinstall just the Python package
pipx install --force 'voxvera@git+https://github.com/PR0M3TH3AN/VoxVera.git@main'
```
-130
View File
@@ -1,130 +0,0 @@
# विस्तृत उपयोग
यह गाइड सामान्य CLI वर्कफ्लो को कवर करती है। डॉकर निर्देशों के लिए `docs/docker.md` और उपलब्ध फ्लायर टेम्पलेट्स के लिए `docs/templates.md` देखें।
## पूर्वापेक्षाएँ (Prerequisites)
VoxVera को अत्यधिक पोर्टेबल बनाने के लिए डिज़ाइन किया गया है और इसके लिए न्यूनतम सिस्टम निर्भरता की आवश्यकता होती है।
### 1. स्टैंडअलोन बाइनरी (अनुशंसित)
आप अपने ऑपरेटिंग सिस्टम के लिए स्टैंडअलोन, शून्य-निर्भरता बाइनरी डाउनलोड कर सकते हैं:
- **Linux:** `voxvera-linux`
- **Windows:** `voxvera-windows.exe`
- **macOS:** `voxvera-macos`
इन बाइनरी में VoxVera चलाने के लिए आवश्यक सब कुछ शामिल है (`onionshare-cli` को छोड़कर)।
### 2. वन-लाइन इंस्टॉलर
वैकल्पिक रूप से, हमारी स्वचालित स्क्रिप्ट के माध्यम से इंस्टॉल करें:
```bash
curl -fsSL https://raw.githubusercontent.com/PR0M3TH3AN/VoxVera/main/install.sh | bash
```
### 3. मैनुअल पायथन इंस्टॉलेशन
यदि आप सोर्स से चलाना पसंद करते हैं:
```bash
pipx install 'voxvera@git+https://github.com/PR0M3TH3AN/VoxVera.git@main'
sudo apt install tor onionshare-cli # Debian/Ubuntu
```
## चरण-दर-चरण (Step-by-Step)
1. **आरंभ करें (Initialize):** `voxvera init` चलाएँ और संकेतों का पालन करें। आपसे सबसे पहले अपनी भाषा चुनने के लिए कहा जाएगा।
2. **बिल्ड (Build):** फ्लायर एसेट्स जेनरेट करें। प्रत्येक बिल्ड स्वचालित रूप से फ्लायर के फ़ोल्डर में एक `voxvera-portable.zip` बनाता है, जिससे अन्य लोग सीधे आपके फ्लायर से पूरा टूल डाउनलोड कर सकते हैं।
```bash
voxvera build
```
3. **सर्व (Serve):** फ्लायर को Tor पर प्रकाशित करें:
```bash
voxvera serve
```
यह स्वचालित रूप से आपके Tor इंस्टेंस का पता लगाता है, OnionShare शुरू करता है, और जेनरेट किए गए .onion एड्रेस को फ्लायर के टियर-ऑफ लिंक में लिख देता है।
## भाषा समर्थन (Language Support)
VoxVera पूरी तरह से स्थानीयकृत (localized) है। आप इंटरैक्टिव सेलेक्टर या सीधे शॉर्टकट का उपयोग करके अपनी भाषा प्राथमिकता को स्थायी रूप से बदल सकते हैं:
- **इंटरैक्टिव सेलेक्टर:** `voxvera lang`
- **सीधा शॉर्टकट:** `voxvera --lang hi` (प्राथमिकता को हिन्दी पर सेट करता है)
### समर्थित भाषाएं:
- **अंग्रेजी:** `en`
- **स्पेनिश:** `es` (उपनाम: `--idioma`)
- **जर्मन:** `de` (उपनाम: `--sprache`)
- **हिन्दी:** `hi`
आप अपनी स्थायी प्राथमिकता को बदले बिना किसी एक कमांड के लिए एक विशिष्ट भाषा को बाध्य (force) भी कर सकते हैं:
- **अंग्रेजी:** `voxvera --lang en check`
- **हिन्दी:** `voxvera --lang hi check`
जेनरेट किए गए फ्लायर्स स्वचालित रूप से विज़िटर की ब्राउज़र भाषा का पता लगाते हैं और उसके अनुसार UI टेक्स्ट बदलते हैं।
## सर्वर प्रबंधन (Server Management)
एक ही इंटरैक्टिव मेनू से कई फ्लायर्स और उनकी Tor पहचान प्रबंधित करें:
```bash
voxvera manage
```
विशेषताएं:
- **--- नई साइट/फ्लायर बनाएँ ---**: पूरा सेटअप अनुक्रम शुरू करें।
- **--- सभी साइटें शुरू करें ---**: अपने बेड़े के सभी फ्लायर्स को एक साथ शुरू या बंद करें।
- **वास्तविक समय स्थिति**: सक्रिय `.onion` URL और Tor बूटस्ट्रैपिंग प्रगति संकेतक देखें।
- **व्यक्तिगत नियंत्रण**: विशिष्ट साइटों को ZIP में ज़िप में निर्यात करें करें या उन्हें हटा दें।
## यूनिवर्सल मिररिंग (वायरल वितरण)
यह सुनिश्चित करने के लिए कि VoxVera केंद्रीय रिपॉजिटरी सेंसर होने पर भी सुलभ रहे, प्रत्येक फ्लायर टूल के लिए मिरर के रूप में कार्य करता है।
जब आप फ्लायर होस्ट करते हैं, तो लैंडिंग पेज पर **"टूल और कोड डाउनलोड करें"** बटन एक `voxvera-portable.zip` प्रदान करता है जिसमें शामिल हैं:
- पूरा सोर्स कोड और सभी समर्थित भाषाएं।
- सभी पायथन निर्भरताएँ (pre-vendored)।
- क्रॉस-प्लेटफ़ॉर्म Tor बाइनरी।
यह आपके फ्लायर को स्कैन करने वाले किसी भी व्यक्ति को VoxVera टूल का नया वितरक बनने की अनुमति देता है।
## निर्यात और बैकअप (Export & Backup)
अपनी अनूठी Tor पहचान का बैकअप लें (ताकि आपका `.onion` URL कभी न बदले) या अपने फ्लायर्स को दूसरी मशीन पर ले जाएं।
- **एकल साइट निर्यात करें**: `voxvera export <folder_name>`
- **सभी साइटें निर्यात करें**: `voxvera export-all`
**भंडारण स्थान:** सभी निर्यात सभी प्लेटफ़ॉर्म पर उपयोगकर्ता की होम डायरेक्टरी (`~/voxvera-exports/`) में ZIP फ़ाइलों के रूप में सहेजे जाते हैं।
## आयात और पुनर्प्राप्ति (Import & Recovery)
अपनी ZIP फ़ाइलों को `~/voxvera-exports/` में ले जाकर और चलाकर एक नई मशीन पर अपना पूरा सेटअप पुनर्स्थापित करें:
```bash
voxvera import-multiple
```
## पोर्टेबिलिटी और ऑफलाइन उपयोग
यदि आपको बिना इंटरनेट एक्सेस वाली मशीन पर VoxVera चलाने की आवश्यकता है, तो आप पहले निर्भरताओं को "वेंडराइज़" (vendorize) कर सकते हैं:
```bash
voxvera vendorize
```
यह `voxvera/vendor/` में सभी आवश्यक पायथन लाइब्रेरी डाउनलोड करता है। टूल फिर इन स्थानीय फ़ाइलों को प्राथमिकता देगा, जिससे यह `pip install` के बिना चल सकेगा।
## बैच आयात (JSON)
कई JSON कॉन्फ़िगरेशन फ़ाइलों से थोक में फ्लायर्स जेनरेट करने के लिए, उन्हें `imports/` डायरेक्टरी में रखें और चलाएँ:
```bash
voxvera batch-import
```
## URL कैसे काम करते हैं
प्रत्येक फ्लायर के दो अलग-अलग URL होते हैं:
- **टियर-ऑफ लिंक** (स्वचालित रूप से जेनरेट): वह .onion एड्रेस जहाँ फ्लायर होस्ट किया गया है।
- **सामग्री लिंक** (उपयोगकर्ता-कॉन्फ़िगर): वेबसाइट, वीडियो या डाउनलोड की ओर इशारा करने वाला एक बाहरी URL।
आपको मैन्युअल रूप से .onion एड्रेस दर्ज करने की आवश्यकता नहीं है; `serve` चरण के दौरान VoxVera इसे स्वचालित रूप से संभालता है।
-42
View File
@@ -1,42 +0,0 @@
# AI Agent Instructions for VoxVera
This guide is for AI agents (like Gemini, Claude, or GPT) contributing to the VoxVera project. Follow these protocols to maintain the architectural integrity and multi-language support.
## Core Mandates
1. **Security-First**: VoxVera is a Tor-based tool. Never suggest features that leak IP addresses or use non-Tor external resources (CDNs, etc.).
2. **Local-First**: All assets (fonts, dependencies, binaries) must be self-contained within the `voxvera/` package to support the Universal Mirroring model.
3. **Tokenized UI**: Never hardcode user-facing strings. Always add them to `voxvera/locales/en.json` and use the `t('cli.token')` helper.
4. **Markdown Redaction**: Use `~~text~~` in locale JSONs for strike-through effects. Both the build system and the JS engine handle the conversion to `<span class="redacted">` automatically.
5. **Visual Width Testing**: When modifying UI or adding languages, verify that long or complex strings (e.g., Hindi ligatures or CJK characters) do not exceed the visual unit limits defined in the CLI.
## Localization Protocol
When adding a new language or updating an existing one:
- **CLI/Flyers**: Update `voxvera/locales/{lang}.json`. Include `meta`, `cli`, `web`, and `landing` categories.
- **Landing Page**:
- Directly update the `const locales` object in `site/index.html`.
- **Crucial**: Run `voxvera build-site` to generate the latest portable bundle and refresh the pre-rendered HTML.
- **Documentation**:
- Master templates live in `docs/templates/`.
- Localized overrides live in `voxvera/locales/{lang}/docs/`.
- **Crucial**: After any change to locales or templates, you MUST run `voxvera build-docs` to synchronize the output in `docs/{en,es,de}/`.
## Universal Mirroring
VoxVera propagates through its own flyers.
- Every `voxvera build` and `voxvera build-site` generates `voxvera-portable.zip`.
- If you modify the core source code, ensure the `bundle_portable` function in `voxvera/cli.py` still correctly captures all necessary directories (especially `vendor/`, `locales/`, and `resources/`).
## Verification Checklist
Before finishing a task, ensure you have:
1. Run unit tests: `pytest tests/test_cli.py`.
2. Verified the localization: `voxvera --lang {lang} check`.
3. Rebuilt the documentation: `voxvera build-docs`.
4. Synchronized the public site: `voxvera build-site`.
5. Verified the portable bundle exists: `ls -l voxvera/host/*/download/voxvera-portable.zip` and `ls -l site/download/voxvera-portable.zip`.
---
Follow these rules to ensure VoxVera remains a robust, viral, and decentralized tool for truth.
-47
View File
@@ -1,47 +0,0 @@
# Contributing to VoxVera
Thank you for your interest in contributing to VoxVera! This project aims to be a global, censorship-resistant tool, and your help—especially with translations—is vital.
## Adding a New Language
VoxVera uses a centralized token system for the CLI and Web components, and a template-based system for Documentation. To add a new language (e.g., French/`fr`), follow this checklist:
### 1. The Token File
Create a new JSON file in `voxvera/locales/{lang_code}.json`.
- Use `en.json` as your master template.
- **`meta`**: Include the native language name and a flag emoji.
- **`cli`**: Translate all strings used in the terminal interface.
- **`web`**: Translate strings used on the generated landing pages and flyers.
- **`landing`**: Translate the specific content for the official VoxVera website.
- **Formatting**: You can use Markdown-style strike-throughs (`~~redacted text~~`) in any of these strings; they will be automatically converted to the stylized "redacted" effect on the flyers.
### 2. The Landing Page
The main landing page is generated from the shared template and locale files.
- Add your language in `voxvera/locales/{lang_code}.json`.
- Do **not** edit `site/index.html` directly; it is generated output.
- Run `voxvera build-site` to refresh the public assets and inject your new locale into the generated HTML.
### 3. Documentation
VoxVera uses the **Doc-Sync Engine** to keep manuals in sync.
- Create localized Markdown files in `voxvera/locales/{lang_code}/docs/`.
- Use the templates in `docs/templates/` as your guide.
- You can use `cli.token_name` to reference terminal commands automatically.
### 4. Build and Verify
Run the following commands to verify your changes:
- `voxvera --lang {lang_code} check` (Verify CLI translation)
- `voxvera build-docs` (Generate localized manuals)
- `voxvera build-site` (Synchronize the public website and generate the latest portable bundle)
- Open the generated `site/index.html` in a browser and test the language switcher.
## Code Contributions
- **Dependencies**: if you add a new Python library to `requirements.txt`, you MUST run `voxvera vendorize` to include it in the portable distribution.
- **Layout Integrity**: VoxVera uses visual width validation. If you add new UI elements, ensure they respect the physical boundaries of an 8.5"x11" flyer.
- **Tests**: Ensure all tests pass: `pytest tests/`. Run the integrity suite specifically when modifying locales: `pytest tests/test_integrity.py`.
- **Generated artifacts**: Treat `voxvera/resources/bin/` as local build output, not source files. Release binaries belong in GitHub Releases, not hand-edited repo state.
- **Style**: Follow the existing coding style (PEP 8 for Python).
- **Documentation**: If adding a new feature, update the master templates in `docs/templates/` and run `voxvera build-docs`.
---
Together, we can ensure that truth remains accessible to everyone, everywhere.
-19
View File
@@ -1,19 +0,0 @@
# Docker Usage
Experimental: the container path is not yet a production-grade hidden-service deployment target. Linux with `systemd --user` remains the supported persistent-host environment.
A prebuilt image containing Tor, OnionShare and the `voxvera` CLI is published to
`ghcr.io/voxvera/voxvera`.
```bash
# pull the image
docker pull ghcr.io/voxvera/voxvera:latest
# run the experimental container with flyers stored in ./flyers
mkdir -p flyers
docker run -it --rm -v "$(pwd)/flyers:/flyers" ghcr.io/voxvera/voxvera
```
The container stores runtime state under `/flyers`, seeds a default `config.json` if needed, and retries `voxvera start-all` periodically after the initial `quickstart`.
Use this path for testing only until the container runtime and background recovery behavior are validated end-to-end.
-14
View File
@@ -1,14 +0,0 @@
# Flyer Templates
Pre-built flyer templates live in the `templates/` directory. Use the CLI to copy one with:
```bash
voxvera init --template <name>
```
This will create a new folder under `dist/` named `<name>-<YYYYMMDD>` containing the template files.
Available templates:
- **blank** – minimal placeholder files, also used when extracting fields from a PDF.
- **voxvera** – example flyer showcasing the VoxVera project.
-75
View File
@@ -1,75 +0,0 @@
# Troubleshooting
This page collects common issues encountered when hosting or accessing flyers.
## Tor connectivity
- Ensure Tor is allowed through your firewall. On systems using `ufw` you may need to run `sudo ufw allow tor`.
- Some networks block Tor entirely. If you cannot reach onion services, try connecting over a different network or use a Tor bridge.
## Supported deployment target
- The supported persistent-host setup is Linux with `systemd --user`.
- Windows, macOS, Docker, Flatpak, AppImage, Homebrew, and Chocolatey are currently experimental and may not recover hosting automatically after reboot or network interruptions.
## Tor port detection
`voxvera serve` auto-detects Tor by probing common ports (9050/9150 for SOCKS, 9051/9151 for control). If detection fails -- for example when Tor runs on non-standard ports -- you can override with environment variables:
```bash
TOR_SOCKS_PORT=19050 TOR_CONTROL_PORT=19051 voxvera serve
```
If no running Tor is found, the defaults (9050/9051) are used and OnionShare will attempt to connect on those ports.
## Firewall rules
- If `voxvera serve` fails to start OnionShare, verify that outbound connections on ports 9001 and 80 are permitted.
- Corporate or university firewalls can block the hidden service ports required by Tor.
## SELinux
- On SELinux-enabled distributions you may see `permission denied` errors when OnionShare writes to the `host` directory.
- Run `sudo chcon -Rt svirt_sandbox_file_t host` or disable SELinux enforcement for the folder.
## OnionShare crashes
If `voxvera serve` prints "OnionShare exited unexpectedly", check the log file
`host/<folder_name>/onionshare.log` for details. Common causes:
- Tor is not running (`sudo systemctl start tor`)
- A port conflict with another service
- Missing `onionshare-cli` (run `voxvera check`)
## Onion URL changed unexpectedly
The onion URL is tied to the Ed25519 keypair stored in
`host/<folder_name>/.onionshare-session`. If this file is deleted, a new
keypair (and URL) will be generated on the next `voxvera serve`. The
`voxvera import` command preserves this file automatically, but manual
deletion of the `host/` directory will destroy it.
## Hosting does not return after reboot or network loss
On Linux, install or verify the recovery timer:
```bash
voxvera autostart
systemctl --user status voxvera-start.timer
systemctl --user status voxvera-start.service
```
The supported recovery path is the recurring `systemd --user` timer, which reruns `voxvera start-all` every few minutes.
## QR codes not generated
If `voxvera build` reports "No URLs configured yet", this is expected before the first `voxvera serve`. QR codes for tear-off links are generated automatically once the .onion address is known. QR codes for the content link are generated if you provided a URL during `voxvera init`.
## Electron GUI
If `npm start` fails with `spawn voxvera ENOENT`, the `voxvera` command is not in your `PATH`. Install it with `pipx install git+https://github.com/PR0M3TH3AN/VoxVera.git` or run `./install.sh` from the repository.
## Missing dependencies
Run `voxvera check` to verify your setup. The command checks for required
Python packages (`qrcode`, `Pillow`, `jsmin`, `htmlmin`, `pypdf`) and
external tools (`onionshare-cli`), then prints a summary of anything
missing. To install everything:
```bash
# Recommended: use the install script (handles Tor + OnionShare too)
curl -fsSL https://raw.githubusercontent.com/PR0M3TH3AN/VoxVera/main/install.sh | bash
# Or reinstall just the Python package
pipx install --force 'voxvera@git+https://github.com/PR0M3TH3AN/VoxVera.git@main'
```
-130
View File
@@ -1,130 +0,0 @@
# 詳細な使い方
このガイドでは、一般的なCLIワークフローについて説明します。Dockerの手順については `docs/docker.md` を、利用可能なフライヤーテンプレートについては `docs/templates.md` を参照してください。
## 前提条件
VoxVeraは高いポータビリティを実現するように設計されており、システムへの依存関係は最小限です。
### 1. スタンドアロンバイナリ (推奨)
お使いのオペレーティングシステムに合わせて、依存関係のないスタンドアロンバイナリをダウンロードできます。
- **Linux:** `voxvera-linux`
- **Windows:** `voxvera-windows.exe`
- **macOS:** `voxvera-macos`
これらのバイナリには、VoxVeraの実行に必要なすべてのものが含まれています(`onionshare-cli` を除く)。
### 2. ワンラインインストーラー
または、自動スクリプトを使用してインストールします。
```bash
curl -fsSL https://raw.githubusercontent.com/PR0M3TH3AN/VoxVera/main/install.sh | bash
```
### 3. 手動でのPythonインストール
ソースから実行したい場合:
```bash
pipx install 'voxvera@git+https://github.com/PR0M3TH3AN/VoxVera.git@main'
sudo apt install tor onionshare-cli # Debian/Ubuntu
```
## ステップ・バイ・ステップ
1. **初期化:** `voxvera init` を実行し、プロンプトに従います。最初に言語を選択するよう求められます。
2. **ビルド:** フライヤーのアセットを生成します。ビルドを実行するたびに、フライヤーのフォルダ内に `voxvera-portable.zip` が自動的に作成されます。これにより、他の人があなたのフライヤーから直接ツール一式をダウンロードできるようになります。
```bash
voxvera build
```
3. **公開:** Torを介してフライヤーを公開します。
```bash
voxvera serve
```
これにより、実行中のTorインスタンスが自動的に検出され、OnionShareが起動し、生成された .onion アドレスがフライヤーの切り取りセクションのリンクに書き込まれます。
## 言語サポート
VoxVeraは完全にローカライズされています。インタラクティブセレクターまたは直接ショートカットを使用して、言語設定を永続的に変更できます。
- **インタラクティブセレクター:** `voxvera lang`
- **直接ショートカット:** `voxvera --lang ja` (日本語に設定)
### サポートされている言語:
- **英語:** `en`
- **スペイン語:** `es` (エイリアス: `--idioma`)
- **ドイツ語:** `de` (エイリアス: `--sprache`)
- **日本語:** `ja`
永続的な設定を変更せずに、単一のコマンドに対して特定の言語を強制することもできます。
- **英語:** `voxvera --lang en check`
- **日本語:** `voxvera --lang ja check`
生成されたフライヤーは、訪問者のブラウザ言語を自動的に検出し、UIテキストをそれに応じて切り替えます。
## サーバー管理
単一のインタラクティブメニューから、複数のフライヤーとそのTorアイデンティティを管理できます。
```bash
voxvera manage
```
機能:
- **--- 新規サイト/フライヤー作成 ---**: セットアップシーケンスを最初から開始します。
- **--- すべてのサイトを開始 ---**: 管理下のすべてのフライヤーを一括で起動またはシャットダウンします。
- **リアルタイムステータス**: アクティブな .onion URLやTorの起動プログレスインジケーターを表示します。
- **個別制御**: 特定のサイトをZIPに Zipとしてエクスポート したり、削除したりできます。
## ユニバーサルミラーリング(バイラル拡散)
中央のリポジトリが検閲された場合でもVoxVeraを利用し続けられるように、すべてのフライヤーがツールのミラーとして機能します。
フライヤーをホストすると、ランディングページの **「ツールとソースをダウンロード」** ボタンから以下のものを含む `voxvera-portable.zip` が提供されます。
- すべてのサポート言語を含む完全なソースコード。
- すべてのPython依存関係(事前ベンダー化済み)。
- クロスプラットフォームのTorバイナリ。
これにより、あなたのフライヤーをスキャンした誰もが、VoxVeraツールの新しい配布者になることができます。
## エクスポートとバックアップ
独自のTorアイデンティティ(.onion URLが変更されないようにするため)をバックアップしたり、フライヤーを別のマシンに移動したりできます。
- **単一サイトのエクスポート**: `voxvera export <フォルダ名>`
- **全サイトのエクスポート**: `voxvera export-all`
**保存場所:** すべてのエクスポートは、すべてのプラットフォームでユーザーのホームディレクトリにある `~/voxvera-exports/` フォルダに保存されます。
## インポートと復元
ZIPファイルを `~/voxvera-exports/` に移動して以下を実行することで、新しいマシンでセットアップ全体を復元できます。
```bash
voxvera import-multiple
```
## ポータビリティとオフライン利用
インターネット接続のないマシンでVoxVeraを実行する必要がある場合は、まず依存関係を「ベンダー化」できます。
```bash
voxvera vendorize
```
これにより、必要なすべてのPythonライブラリが `voxvera/vendor/` にダウンロードされます。ツールはこれらのローカルファイルを優先的に使用するため、 `pip install` なしで実行できるようになります。
## 一括インポート (JSON)
複数のJSON設定ファイルからフライヤーを一括生成するには、それらを `imports/` ディレクトリに配置して以下を実行します。
```bash
voxvera batch-import
```
## URLの仕組み
各フライヤーには2つの異なるURLがあります。
- **切り取り用リンク** (自動生成): フライヤーがホストされている .onion アドレス。
- **コンテンツリンク** (ユーザー設定): ウェブサイト、動画、またはダウンロードを指す外部URL。
.onion アドレスを手動で入力する必要はありません。VoxVeraが `serve` フェーズ中に自動的に処理します。
-178
View File
@@ -1,178 +0,0 @@
# Linux Hosting Validation
This runbook defines the operational validation standard for VoxVera's only supported hosting target:
- Linux CLI with `systemd --user`
Everything else remains below that bar until equivalent evidence exists.
## Prerequisites
- `voxvera` installed and on `PATH`
- `tor` installed
- `onionshare-cli` available
- a user account that can run `systemctl --user`
## Quick Verification
Use the helper script first:
```bash
bash scripts/linux-recovery-check.sh
```
This checks:
- `platform-status --json`
- `doctor --json`
- `autostart status --json`
- expected Linux support tier and platform id
- presence of `~/host`
- Tor and OnionShare discovery
- autostart artifacts and timer state
- per-site state for `.onionshare-session`, `onionshare.log`, and `server.pid`
## Core Commands
Install autostart:
```bash
voxvera autostart
```
Inspect autostart:
```bash
voxvera autostart status
systemctl --user status voxvera-start.timer
systemctl --user status voxvera-start.service
```
Remove autostart:
```bash
voxvera autostart uninstall
```
Inspect runtime diagnostics:
```bash
voxvera doctor
voxvera doctor --json
```
## Validation Checklist
### 1. Fresh install
Run the Linux installer or install through the supported CLI path, then confirm:
```bash
voxvera platform-status --json
voxvera doctor --json
voxvera autostart status --json
```
Expected:
- `platform_id` is `linux_cli_systemd`
- support tier is `supported`
- `voxvera_cli`, `onionshare_cli`, and `tor_binary` pass
### 2. Build and serve
Create or edit a site, then build and serve it:
```bash
voxvera build
voxvera serve
```
Expected:
- site output appears under `~/host/<folder_name>/`
- `index.html` and QR code images exist
- `onionshare.log` is written
- `.onionshare-session` appears after the hidden service is started
### 3. Identity persistence
Confirm the site keeps its identity across rebuilds:
```bash
ls -la ~/host/<folder_name>/
voxvera build --config ~/host/<folder_name>/config.json
```
Expected:
- `.onionshare-session` still exists after rebuild
### 4. Autostart persistence
Confirm the recovery timer exists and is enabled:
```bash
voxvera autostart status
systemctl --user is-enabled voxvera-start.timer
systemctl --user is-active voxvera-start.timer
```
Expected:
- timer artifacts exist under `~/.config/systemd/user/`
- timer is enabled
### 5. Reboot recovery
After a reboot, verify:
```bash
bash scripts/linux-recovery-check.sh
systemctl --user status voxvera-start.timer
journalctl --user -u voxvera-start.service --no-pager -n 50
```
Expected:
- timer remains enabled
- service has retried `start-all`
- configured sites are restorable without manual reconfiguration
### 6. Offline/reconnect recovery
Temporarily disconnect the host from the network, reconnect, then wait through at least one timer interval.
Verify:
```bash
systemctl --user status voxvera-start.timer
journalctl --user -u voxvera-start.service --no-pager -n 50
bash scripts/linux-recovery-check.sh
```
Expected:
- timer is still active
- `start-all` retries appear in the service logs
- Tor becomes reachable again
## Paths That Matter
- `~/.config/systemd/user/voxvera-start.service`
- `~/.config/systemd/user/voxvera-start.timer`
- `~/host/<folder_name>/config.json`
- `~/host/<folder_name>/.onionshare-session`
- `~/host/<folder_name>/onionshare.log`
- `~/host/<folder_name>/server.pid`
## Failure Interpretation
If `bash scripts/linux-recovery-check.sh` fails:
- missing `onionshare_cli` or `tor_binary` means the runtime is incomplete
- missing `host_root` means no sites are built yet
- missing autostart artifacts means recovery was never installed or was removed
- `tor_socks_reachable` warning means Tor is not currently reachable even if it is installed
Linux should remain the only supported target until this runbook is repeatable on real hosts without caveats.
-99
View File
@@ -1,99 +0,0 @@
# Multi-Language Support Developer Plan
This document outlines the strategy for implementing a token-based multi-language system in VoxVera, covering the CLI, the generated landing page, and documentation.
## 1. Core Architecture: The Token System
All translatable strings will be centralized in JSON files located in `voxvera/locales/`. This allows for easy addition of new languages by simply dropping a new file.
- **Storage:** `voxvera/locales/{lang_code}.json` (e.g., `en.json`, `es.json`).
- **Structure:**
```json
{
"meta": {
"language_name": "English",
"flag": "🇺🇸"
},
"cli": {
"welcome": "Welcome to VoxVera Setup",
"select_lang": "Select your preferred language",
"folder_prompt": "Enter folder name for this flyer:"
},
"web": {
"title": "VoxVera - Anonymous Flyers",
"download_btn": "Download Flyer",
"onion_link_desc": "Scan to view on Tor",
"change_lang": "Change Language"
}
}
```
## 2. CLI Implementation (`voxvera/cli.py`)
The CLI will be updated to handle localization from the start of the user interaction.
### Workflow:
1. **Initial Detection:** On startup, the CLI checks the system locale (`LANG` env var or `locale` module).
2. **Language Selection:** The first prompt in `voxvera init` will be a language selector, defaulting to the detected system locale.
3. **Session Loading:** Once selected, the CLI loads the corresponding JSON. All subsequent `InquirerPy` prompts will use these tokens.
4. **Configuration:** The chosen language code is saved in the flyer's `config.json` as a preference for that specific project.
## 3. Web Implementation (`voxvera/src/index-master.html`)
The landing page will support dynamic language switching without requiring server-side logic (essential for Tor-hidden services).
### Detection Logic:
- **Avoid IP-based Detection:** Since VoxVera is hosted on Tor, IP lookups return the Tor Exit Node location, not the user's.
- **Browser-based Detection:** Use `navigator.language` to detect the user's browser preference.
- **Persistence:** Save the user's manual choice in `localStorage`.
### Frontend Components:
1. **Attributes:** Use `data-i18n="web.token_name"` on HTML elements.
2. **Language Switcher:** A dropdown menu or text-link list (e.g., "EN | ES | FR") placed next to the **Download** button.
3. **I18n Engine:** A lightweight JavaScript snippet injected during the build process that:
- Loads the bundled locale data.
- Detects the best language (Manual Selection > Browser Setting > English Fallback).
- Updates all `data-i18n` elements.
## 4. Build System Updates (`voxvera/build.py`)
The `build` process will be updated to bundle the necessary translations.
- **Multi-bundle:** By default, all available `web` tokens from all locale files will be injected into a single `<script>` tag in the final `index.html`. This ensures instant switching even when offline or on slow Tor connections.
- **Asset Optimization:** Minify the locale JSON data before injection to keep the HTML lightweight.
## 5. Portable & Viral Distribution Model
To ensure VoxVera is truly censorship-resistant, every generated flyer will serve as a mirror for the entire tool, including all supported languages and dependencies.
### Key Requirements:
- **Zero-Dependency Execution:** All Python libraries (from `requirements.txt`) will be bundled into a `voxvera/vendor/` directory. The CLI will be updated to prioritize this local path.
- **Pre-Bundled Tor:** The existing `voxvera/resources/tor/` binaries for Linux, Mac, and Windows will be included in every distribution.
- **Universal Language Bundle:** Every `voxvera-portable.zip` will include the full `voxvera/locales/` directory, ensuring that a user who downloads the tool from an English flyer can immediately switch it to Spanish, French, or any other supported language.
### The "Mirror" Workflow:
1. **Build Phase:** When `voxvera build` is executed, it assembles a `voxvera-portable.zip` containing:
- The full `voxvera/` source code.
- The `vendor/` library directory.
- All `locales/*.json` files.
- Cross-platform Tor binaries.
- A `voxvera-run.sh` / `voxvera-run.bat` entry point.
2. **Injection:** This ZIP is automatically placed in the `voxvera/host/<folder_name>/download/` directory of the generated flyer.
3. **User Access:** The landing page's "Download" button is updated to explicitly offer the "Full Portable Tool & Source," allowing the recipient to become a new node in the distribution network.
## 6. Documentation (`docs/`)
Documentation will follow a subdirectory structure for maximum compatibility with GitHub/Markdown renderers.
- **Structure:**
- `docs/en/usage.md`
- `docs/es/usage.md`
- **Maintenance:** A master English file will serve as the source of truth for all translations.
## 6. Implementation Phases
1. **Phase 1 (Audit):** Extract all hardcoded strings from `cli.py` and `index-master.html` into `en.json`.
2. **Phase 2 (CLI):** Implement the language selector and token loader in `cli.py`.
3. **Phase 3 (Web):** Update the HTML template with `data-i18n` attributes and the JS switcher.
4. **Phase 4 (Build):** Update `build.py` to inject the locale bundle.
5. **Phase 5 (Expansion):** Add a second language (e.g., Spanish) to verify the system.
+401
View File
@@ -0,0 +1,401 @@
# VoxVera Nostr Static Client Spec
Status: `main` is the Nostr static-client branch. The legacy Tor/OnionShare CLI version is preserved on `legacy-tor`.
## Goal
VoxVera should let anyone publish, fetch, and print flyer content without a centralized application server.
The static client is responsible for:
- rendering the flyer
- generating QR codes
- authoring a normalized Nostr flyer payload
- generating anonymous browser-side Nostr keys
- signing and publishing replaceable Nostr events
- fetching events by raw event ID, `note1`, `nevent1`, or `naddr`
- rendering fetched content safely
Nostr relays store the flyer source content. Static hosts only serve the client.
## Active Files
```text
site/
index.html (the client)
nostr-client.css
nostr-client.js
locales.js
board.html (bulletin board page)
board.js
favicon.svg (inline SVG site icon)
CNAME
vendor/
nostr-tools/
qrcode-generator/
nostr/
index.html (redirect stub for legacy /nostr/ URLs)
voxvera/
nostr/
schema.py
tests/
test_nostr_schema.py
```
## Deployment
The deployable static root is `site`.
No build command is required. Vercel should use:
- root directory: repository root
- output directory: `site`
- build command: empty
The client is served from the root (`site/index.html`). `site/nostr/index.html` is a redirect stub that forwards the legacy `/nostr/` path to the root, preserving the query string and `#naddr` fragment, so poster URLs and QR codes printed before the move still resolve.
## Event Model
Recommended event kind: `30078` parameterized replaceable event.
Required tags:
- `["d", "voxvera:<slug>"]`
- `["t", "voxvera"]`
- `["t", "flyer"]`
Recommended language tags:
- `["language", "<lang>"]`
- `["L", "ISO-639-1"]`
- `["l", "<lang>", "ISO-639-1"]`
The payload `lang` field is authoritative. The language tags exist for relay/search metadata and as a fallback for older events whose payload omitted `lang`.
Payload:
```json
{
"type": "voxvera_flyer",
"version": 1,
"folder_name": "voxvera",
"name": "Vox Vera Printable Flyers",
"lang": "en",
"title": "OPERATION VOX VERA",
"subtitle": "DO ~~NOT~~ DISTRIBUTE",
"headline": "TOP SECRET",
"content": "Flyer body text",
"url_message": "Follow this link to learn more.",
"url": "https://creator.example/action",
"tear_off_link": "https://voxvera.org/nostr/#naddr1...",
"footer_message": "0110010",
"qr_target": "flyer_url"
}
```
The UI labels `folder_name` as `Flyer Name`; it acts as the event slug, not a local hosting folder.
## QR Target
Default behavior: `qr_target: "flyer_url"`.
`url` is always the creator-controlled content destination shown in the body of the flyer. The editor must not overwrite this field with generated app URLs.
When publishing, the client computes the replaceable-event `naddr` and writes the generated poster URL to `tear_off_link`. The tear-off tabs and tear-off QR code point at `tear_off_link`, so people can re-open and reprint the flyer. The main flyer QR code points at `url`, so viewers can visit the creator's intended destination.
Each tear-off tab is labeled with the flyer's **title** (`.tear-off-title`, auto-sized by `fitTabTitles()` to be as large as fits the ~1in tab, shrinking rather than overflowing for long titles), a clickable **"Open & reprint this flyer"** link (`tab_link`, the `<a href>` so it stays live in a printed PDF), the tear-off QR, and a **"Reopen at VoxVera.org — Event ID:"** line (`tab_event_id`, the brand stays Latin; the rest is localized) with the full event id. All strings are translated in every supported language.
The `naddr` is encoded with a **single relay hint** (the primary configured relay) instead of the full relay list. This keeps the poster URL short and its tear-off QR code easy to scan — a typical poster URL drops from ~233 characters (full list) to ~171 — while still pointing a fresh viewer at a relay that has the event. Viewers also fall back to `DEFAULT_RELAYS`, which is where flyers are published by default. This stays a standard NIP-19 `naddr`, so any Nostr client can resolve it, and older relay-bearing `naddr` URLs continue to decode and resolve unchanged.
The naddr is carried in the URL **fragment** (`#naddr1...`) rather than a `?addr=` query parameter. The fragment is shorter (less QR clutter), needs no URL-encoding, and never reaches the static host. `getUrlEventReference` reads the naddr from query params, the fragment, or anywhere in the full URL, so older `?addr=` poster URLs and printed QR codes still resolve.
Supported values:
- `flyer_url`: tear-off QR points to the hosted client URL for the poster
- `content_url`: QR points to the payload's content URL
- `nostr_event`: QR points to the Nostr source identifier when available
## Safety
Nostr content is untrusted.
The client and schema helper must:
- reject raw HTML in flyer text fields
- escape rendered flyer content
- reject unsafe URL schemes such as `javascript:` and `data:`
- keep attachments unsupported in V1
- avoid remote frontend dependencies
## Publishing identity
The editor signs flyer events under one of four identities, chosen in the
identity controls (`activeIdentity` / `signActiveEvent` in `nostr-client.js`):
- **Anonymous (default).** The per-device key in `localStorage`
(`voxvera_nostr_anon_secret_hex`); signs locally with `finalizeEvent`.
Unchanged behavior — no connection required. "Generate anonymous npub" rolls a
fresh device key.
- **Browser extension (NIP-07).** Signs via `window.nostr.signEvent`; the secret
never enters the page. The pubkey is fetched with `getPublicKey()`.
- **Private key (nsec).** The user pastes an `nsec`; it is decoded to a secret
key used to sign with `finalizeEvent`. By default the secret lives **only in
memory** for the session. If the user ticks "Remember on this device", the
secret is encrypted with a PIN and stored as `voxvera_identity_nsec_enc`; the
plaintext secret is never written to storage.
- **Remote signer (NIP-46).** The user's real secret never reaches the browser;
the client mints an **ephemeral** local key and exchanges encrypted
kind-`24133` JSON-RPC requests (`connect` → `get_public_key` → `sign_event`)
over a raw WebSocket. Two connect paths are offered:
- **`bunker://` (paste).** The user pastes a link the signer app generated;
the client connects out to that bunker relay.
- **`nostrconnect://` (QR).** The client generates the link itself, renders it
as a QR (`makeQrSvg`) plus a copyable link, and listens on a rendezvous relay
(`relay.nsec.app`); the signer app scans it and connects back, proving the
connection by echoing the client's random `secret`. The discovered signer
pubkey is then used for the durable connection.
Requests are encrypted with **NIP-44** (with a NIP-04 decrypt fallback for
older signers); the vendored nostr-tools bundle has no nip46 module, so this
client is hand-rolled. The connection is **session-only** — nothing is
persisted, so a reload returns to anonymous.
The chosen mode is remembered in `voxvera_identity_mode` (and the npub in
`voxvera_identity_npub` for display). On reload: NIP-07 re-fetches the pubkey;
a remembered nsec shows a **locked** state until the PIN is entered (`unlock`);
a session-only nsec or a remote-signer session falls back to anonymous.
`naddr`/poster-URL/`author npub` outputs all reflect the active identity. A
deliberate identity choice is also mirrored to `voxvera_connected_pubkey` so the
bulletin board reflects the same identity.
**PIN encryption details.** PBKDF2 (`SHA-256`, 600k iterations, random 16-byte
salt) derives an AES-GCM-256 key (random 12-byte IV); the blob stores
`{v, iters, salt, iv, ct}` base64. A minimum 4-digit numeric PIN is enforced,
but longer PINs are allowed and encouraged.
> **Security caveat (documented deliberately).** A short numeric PIN has a tiny
> keyspace (a 4-digit PIN is ~10,000 combinations), so if the encrypted blob is
> exfiltrated (targeted XSS, or devtools access on a shared/stolen device) it is
> brute-forceable offline regardless of PBKDF2 cost. PIN-at-rest protects against
> casual snooping and untargeted localStorage scraping, **not** a determined or
> targeted attacker. The NIP-07 extension path (secret never in the page) and the
> NIP-46 remote signer (secret stays in the signer app; the browser holds only an
> ephemeral key — paste a `bunker://` link) are the stronger options. See
> [`roadmap.md`](roadmap.md).
## Editing, re-publishing, and deleting flyers
Because flyers are addressable replaceable events (`kind 30078`, identified by
`(pubkey, d)` where `d = voxvera:<slug>`), the author can manage a published
flyer by re-publishing under the same key + Flyer Name. When a flyer is loaded
from an event, the editor shows author-only actions (`#loaded-flyer-actions`):
- **Edit** — change fields and publish again; the same `d` tag replaces the
prior version in place, keeping the same `naddr`/poster URL.
- **Re-publish (keep-alive)** — re-sign and re-broadcast the current content so
relays that prune app-data don't age the flyer out (`republishCurrentFlyer`).
- **Delete** (`deleteLoadedFlyer`) — two layers, for robustness across relays:
1. a **replaceable tombstone** (`buildTombstoneEvent`) — same `(kind, d)`, with
`deleted: true` in the payload and a `["deleted"]` tag, so it *overwrites*
the flyer's content; relays honoring replaceable semantics now serve the
tombstone, and
2. a **NIP-09 deletion request** (`buildDeletionEvent`, kind `5`) referencing
the addressable `a` tag (`30078:<pubkey>:voxvera:<slug>`) and the event id,
asking relays to drop it entirely.
All three are **author-only**: the active signing key must match the loaded
flyer's author (`resolveActivePubkey`), and `signAndPublish` refuses to publish
if the signed key diverges from the address. **Tombstone recognition:** the
board's `parseFlyers` keeps the newest event per `(pubkey, d)` and skips it if
that newest version is a tombstone (so a delete can't be undone by an older copy
arriving later); the viewer shows a localized "This flyer was removed." state
(`isFlyerTombstone`). Deletion is **best-effort** — relays that ignore both
replaceable overwrites and NIP-09 may still serve the original — so it is framed
as a request, not a guarantee.
## Importing and exporting a flyer design
The editor can save and load a flyer **design** as a portable `.json` file
(`Export design` / `Import design`), independent of publishing. The file format
is `{ type: "voxvera_flyer_design", version: 1, flyer: <payload>, relays: [] }`,
where `flyer` is exactly `rawPayloadFromForm()` — the content fields plus the
relay list, and **nothing identity-bound**: no npub, `naddr`, event id, or
signature (all of those are derived at publish time by `withPosterUrl` /
`signAndPublish`). That makes a design portable: it can be handed to anyone and
published under *their* key with a fresh address.
- **Export** (`exportDesign`) serializes the current form as-is (draft-friendly,
no strict validation) and downloads `<folder_name>-voxvera-design.json`.
- **Import** (`importDesignFromFile`) reads the picked file (capped at 256 KB),
`JSON.parse`s it, and accepts either the wrapper format or a bare
`voxvera_flyer` payload (`readDesignFile`, lenient). It then shows a **confirm
modal** (`#import-modal`) before overwriting the editor, and on confirm
(`applyPendingImport`) fills the form via `fillEditorFromConfig` and restores
the relay list. Imported content is untrusted, but it flows through the lenient
view path (the renderer escapes every field) and still faces strict
`validatePayload` at publish (raw-HTML rejection, length caps, URL schemes).
This replaced the earlier raw "Export event JSON" button; the published
(signed) event JSON is still shown in `#event-json-output` after a publish.
## Print paper size
The flyer supports two print sizes: **US Letter** (8.5×11in) and **A4**
(210×297mm), covering every country whose language the client supports (Letter
in North America and a few Latin American countries; A4 everywhere else,
including the EU, Russia, China, Japan, and the Middle East).
- Dimensions live in CSS custom properties `--sheet-w` / `--sheet-h`, switched
by a `paper-letter` / `paper-a4` class on `<html>` (`applyPaperSize` in
`nostr-client.js`). The tear-off column (`3.75in`) and QR codes (`1.25in`)
stay fixed physical sizes; the content column flexes to the sheet width.
- The print `@page { size: … }` is injected by JS (an element with id
`voxvera-page-size`), because `@page size` cannot read CSS custom properties
across engines. The static `@media print` block keeps `margin: 0` and a
Letter default for the pre-JS state.
- The default is chosen from the **region subtag** of the browser locale
(`preferredPaperSize` — e.g. `en-GB` → A4, `en-US` → Letter). This is "by
location" without geolocation, using the same signal as language. When no
locale carries a region, it falls back to Letter.
- A user override (the paper-size selector) is stored in `localStorage`
(`voxvera_paper`) and wins over the region default.
- **Paper size is a local print/view preference and is never written into the
Nostr event.** A flyer authored on Letter reprints on A4 for a European
viewer without changing the source event. The live fit-check protects
authoring on whichever size is active; switching to a narrower size after
authoring can ellipsis-truncate a maxed-out single-line field.
Field capacity therefore varies by paper size; see
[`flyer-field-limits.md`](flyer-field-limits.md).
## Bulletin board
`site/board.html` + `site/board.js` are a standalone page that lists the most
recent flyers found on the default relays as a sortable, spreadsheet-style
table: **title**, **link** (the poster URL, rendered as the word "link"),
**posting npub**, **language**, **posted date**, and the **event ID** (shown
shortened, full value in the title attribute, with a per-row copy button). Any
column header sorts (default is date descending); replaceable events are
de-duplicated per author+`d` identifier, keeping the latest.
- The entry point is a small screen-only link below the flyer preview
(`.board-link`, label `bulletin_board`), outside the printable sheet. It must
never print (hidden in the `@media print` block alongside the other app
chrome).
- **The board is gated behind a connected Nostr identity.** On load it shows a
login gate (`#board-gate`) instead of the table, with four ways to connect:
a **NIP-07** extension (`window.nostr.getPublicKey()`), a **NIP-46 remote
signer** (either paste a `bunker://` link or scan a `nostrconnect://` QR; same
hand-rolled client as the editor — it establishes the viewer pubkey via
`get_public_key` and keeps the connection so `getBoardSigner` can sign
reports/deletes remotely this session, then falls back to read-only after a
reload), **pasting an `nsec`** (decoded in-page to
derive the pubkey, then discarded — the secret is never stored or transmitted),
or **creating a new key** (reuses this device's anon key in
`voxvera_nostr_anon_secret_hex` if present, else generates one, and reveals the
`nsec` with a save-it warning before continuing). On success it reveals the
table and surfaces the connected npub (`#board-identity`) with a Disconnect
control. The board only ever needs the *pubkey* to view (it reads to filter),
so the connected pubkey is remembered in `localStorage`
(`voxvera_connected_pubkey`, shared with the main client) and a return visit
reconnects from it directly — no prompt or re-entry, any method. This is
**not access control** — the events are public on the relays regardless — it
establishes the *viewer's* identity for the web-of-trust filter below.
Authoring and printing flyers stays fully anonymous and never requires
connecting.
- **Web-of-trust filter (NIP-02).** Once connected, the board fetches the
viewer's contact list (kind 3) and defaults to showing only flyers whose
author is in the viewer's follow graph (degree 1) plus the viewer themself. A
**"Show all"** checkbox opts out to the full relay firehose. A viewer with no
follow list of their own (a fresh key) is **seeded** from a pinned curator
account's follows (`FALLBACK_CURATOR_PUBKEY` in `board.js`), so a brand-new
viewer still gets a curated board. If no trust data can be fetched at all, the
board falls back to showing everything so it is never mysteriously empty. The
`#board-filter-note` explains which mode is active (following / seeded / all),
and re-localizes with the language selector. See [`roadmap.md`](roadmap.md)
for the phased plan (Phase 1 = the gate; Phase 2 = this filter; Phase 3 =
degree-2 trust, blocklist/report, NIP-05 badges).
- `board.js` is independent of `nostr-client.js` (which exports nothing), so its
UI strings live in `BOARD_UI` (all supported languages); it reuses the
vendored nostr-tools and `locales.js` (for language names + RTL direction).
- The board has its own language selector. It reads/writes the same
`voxvera_nostr_lang` localStorage key as the main client, so the chosen
language carries across both pages, and switching it re-localizes the chrome,
column headers, language labels, and date formatting (and flips RTL).
- Relay content is untrusted: titles and npubs are escaped, and link URLs are
rejected unless `http:`/`https:` (so `javascript:`/`data:` never render as a
link).
- The npub column is forward-looking — anonymous keys today, but a stable
identity per author maps cleanly onto this view later.
- **Per-row actions** (behind a per-row **⋯ menu**). On flyers the connected
viewer authored, the menu offers
**Edit** (a link to `/?edit=1#<naddr>`, which loads the flyer in the editor),
**Re-broadcast** (re-sends the already-signed event to all relays — no signing
needed), and **Delete** (tombstone + NIP-09; the board signs via the device
key or NIP-07, and for a pasted-nsec connection it points to the editor). On
flyers from others it shows **Block** — a per-device blocklist of author
pubkeys (`voxvera_blocked_pubkeys`) that always hides them, with a "Clear
blocked" control. The blocklist is local "hide this," separate from the
web-of-trust filter (roadmap #1).
- **Narrow screens (≤640px):** the table collapses to a card per flyer — the
**title** and the **⋯ menu** stay visible, and the secondary fields (link,
posted-by, language, date, event id) sit behind a per-row **Details**
disclosure (`.board-details-toggle` toggles `tr.expanded`; the columns become
labeled rows via their `data-label`).
On mobile the flyer preview scales to fully fit the screen width
(`updatePreviewScale` / `--flyer-preview-scale`): the sheet keeps its true print
width (`flex: 0 0 auto`, so the viewer-mode flexbox doesn't shrink it) and is
visually scaled with a transform — so it never side-scrolls or clips.
The login gate (Phase 1) and the web-of-trust filter (Phase 2) are in place.
Remaining gaps — degree-2 trust, a blocklist/report flow, NIP-05 badges, and
making the bootstrap curator configurable — are tracked in
[`roadmap.md`](roadmap.md).
## Localization
Flyer defaults come from `site/locales.js`.
Nostr editor/viewer controls and Nostr-specific flyer labels come from `NOSTR_UI` in `site/nostr-client.js`.
Language changes should:
- publish the selected flyer language in payload `lang`
- publish matching Nostr language tags
- infer language from event tags if a fetched payload omits `lang`
- update default flyer content while the flyer is still using default content
- preserve user-authored or fetched event content
- update editor/viewer tool labels
- update printed side-tab labels
- respect RTL direction metadata
### Letter-spacing by script
Flyer text uses tighter letter-spacing than the original design to fit more
characters per line, but `letter-spacing` is not script-neutral, so it is
applied per script via a policy class on the flyer `.container`
(`LETTER_SPACING_POLICY` in `nostr-client.js`; `ls-full` / `ls-cjk` / `ls-none`
rules and `--ls-*` variables in `nostr-client.css`):
- `full` — Latin, Cyrillic, Hebrew: reduced positive tracking on the display
fields plus a slight negative on body/URL to reclaim line width.
- `cjk` — Japanese, Chinese: tracking is clamped to `0` and never negative, so
full-width glyphs do not overlap.
- `none` — Arabic, Persian, Hindi: letter-spacing is turned off entirely. These
are cursive or complex scripts where any tracking breaks the letter joins or
detaches combining marks. (This also corrected the prior behavior, which
applied the design's display tracking to every language unconditionally.)
When adding a language, classify its script in `LETTER_SPACING_POLICY` (default
is `full`) and verify the headline, subtitle, and body render correctly in the
browser.
## Verification
```bash
node --check site/nostr-client.js
pytest -q
```
For UI work, also verify browser rendering and print output from a local static server.
-51
View File
@@ -1,51 +0,0 @@
# Platform Support Matrix
This file is the canonical human-readable summary of VoxVera's actual platform support posture.
The machine-readable companion file is [`support-matrix.json`](/home/user/Documents/GitHub/VoxVera/support-matrix.json).
## Support Tiers
- **Supported**: validated for persistent hidden-service hosting with documented recovery behavior.
- **Beta**: feature-complete enough for broader testing, but not yet validated for production-grade recovery claims.
- **Experimental**: may install or run, but is not yet validated for reliable background hidden-service hosting.
- **Unsupported**: not currently a target for reliable hosting.
## Current Matrix
| Platform | Tier | Canonical Runtime Model | Distribution Surfaces | Notes |
| :--- | :--- | :--- | :--- | :--- |
| Linux CLI with `systemd --user` | Supported | System Tor or Tor Browser plus `onionshare-cli`, with recurring `systemd --user` timer recovery | `install.sh`, `voxvera-install.sh`, `pip/pipx`, Linux binary | Current reference implementation |
| Docker CLI | Experimental | Containerized runtime with `VOXVERA_DIR=/flyers` and periodic `start-all` retries | Dockerfile, GHCR image | Needs end-to-end restart validation |
| macOS CLI | Experimental | CLI runtime with `launchd` autostart path and external Tor/OnionShare dependencies | `install.sh`, `pip/pipx`, macOS binary, DMG | No validated recovery claim yet |
| Windows CLI | Experimental | CLI runtime with Task Scheduler path and external Tor/OnionShare dependencies | `install.ps1`, Windows binary, Chocolatey | Binary naming and runtime model need cleanup |
| Electron GUI | Experimental | GUI frontend over the CLI runtime | `gui/electron` | Must converge on shared runtime behavior |
| Flatpak/AppImage/Homebrew/Chocolatey/Deb | Experimental | Distribution-only until runtime parity exists | packaging scripts/manifests | Package availability does not imply hosting parity |
## What "Supported" Means For VoxVera
To move a platform to **Supported**, VoxVera should have evidence for all of the following:
1. Fresh install works on a clean machine.
2. Manual `build` and `serve` work.
3. `.onionshare-session` survives rebuilds and restarts.
4. Hosting returns after reboot or login.
5. Hosting returns after a temporary offline period.
6. Logs and status are inspectable with documented commands.
7. The docs and release artifacts do not overstate capability.
## Promotion Rules
- Do not promote a package surface before the underlying runtime model is validated.
- Do not call a platform "recommended" unless it is also `supported`.
- If a platform lacks validated auto-recovery after reboot or network interruption, it must remain `experimental` or `beta`.
## Current Recommendation
If your goal is reliable Tor hidden-service hosting today, use the Linux CLI path and install the recurring recovery timer with:
```bash
voxvera autostart
```
That is the current reference deployment model the rest of the platform work should converge toward.
-42
View File
@@ -1,42 +0,0 @@
# AI Agent Instructions for VoxVera
This guide is for AI agents (like Gemini, Claude, or GPT) contributing to the VoxVera project. Follow these protocols to maintain the architectural integrity and multi-language support.
## Core Mandates
1. **Security-First**: VoxVera is a Tor-based tool. Never suggest features that leak IP addresses or use non-Tor external resources (CDNs, etc.).
2. **Local-First**: All assets (fonts, dependencies, binaries) must be self-contained within the `voxvera/` package to support the Universal Mirroring model.
3. **Tokenized UI**: Never hardcode user-facing strings. Always add them to `voxvera/locales/en.json` and use the `t('cli.token')` helper.
4. **Markdown Redaction**: Use `~~text~~` in locale JSONs for strike-through effects. Both the build system and the JS engine handle the conversion to `<span class="redacted">` automatically.
5. **Visual Width Testing**: When modifying UI or adding languages, verify that long or complex strings (e.g., Hindi ligatures or CJK characters) do not exceed the visual unit limits defined in the CLI.
## Localization Protocol
When adding a new language or updating an existing one:
- **CLI/Flyers**: Update `voxvera/locales/{lang}.json`. Include `meta`, `cli`, `web`, and `landing` categories.
- **Landing Page**:
- Directly update the `const locales` object in `site/index.html`.
- **Crucial**: Run `voxvera build-site` to generate the latest portable bundle and refresh the pre-rendered HTML.
- **Documentation**:
- Master templates live in `docs/templates/`.
- Localized overrides live in `voxvera/locales/{lang}/docs/`.
- **Crucial**: After any change to locales or templates, you MUST run `voxvera build-docs` to synchronize the output in `docs/{en,es,de}/`.
## Universal Mirroring
VoxVera propagates through its own flyers.
- Every `voxvera build` and `voxvera build-site` generates `voxvera-portable.zip`.
- If you modify the core source code, ensure the `bundle_portable` function in `voxvera/cli.py` still correctly captures all necessary directories (especially `vendor/`, `locales/`, and `resources/`).
## Verification Checklist
Before finishing a task, ensure you have:
1. Run unit tests: `pytest tests/test_cli.py`.
2. Verified the localization: `voxvera --lang {lang} check`.
3. Rebuilt the documentation: `voxvera build-docs`.
4. Synchronized the public site: `voxvera build-site`.
5. Verified the portable bundle exists: `ls -l voxvera/host/*/download/voxvera-portable.zip` and `ls -l site/download/voxvera-portable.zip`.
---
Follow these rules to ensure VoxVera remains a robust, viral, and decentralized tool for truth.
-47
View File
@@ -1,47 +0,0 @@
# Contributing to VoxVera
Thank you for your interest in contributing to VoxVera! This project aims to be a global, censorship-resistant tool, and your help—especially with translations—is vital.
## Adding a New Language
VoxVera uses a centralized token system for the CLI and Web components, and a template-based system for Documentation. To add a new language (e.g., French/`fr`), follow this checklist:
### 1. The Token File
Create a new JSON file in `voxvera/locales/{lang_code}.json`.
- Use `en.json` as your master template.
- **`meta`**: Include the native language name and a flag emoji.
- **`cli`**: Translate all strings used in the terminal interface.
- **`web`**: Translate strings used on the generated landing pages and flyers.
- **`landing`**: Translate the specific content for the official VoxVera website.
- **Formatting**: You can use Markdown-style strike-throughs (`~~redacted text~~`) in any of these strings; they will be automatically converted to the stylized "redacted" effect on the flyers.
### 2. The Landing Page
The main landing page is generated from the shared template and locale files.
- Add your language in `voxvera/locales/{lang_code}.json`.
- Do **not** edit `site/index.html` directly; it is generated output.
- Run `voxvera build-site` to refresh the public assets and inject your new locale into the generated HTML.
### 3. Documentation
VoxVera uses the **Doc-Sync Engine** to keep manuals in sync.
- Create localized Markdown files in `voxvera/locales/{lang_code}/docs/`.
- Use the templates in `docs/templates/` as your guide.
- You can use `cli.token_name` to reference terminal commands automatically.
### 4. Build and Verify
Run the following commands to verify your changes:
- `voxvera --lang {lang_code} check` (Verify CLI translation)
- `voxvera build-docs` (Generate localized manuals)
- `voxvera build-site` (Synchronize the public website and generate the latest portable bundle)
- Open the generated `site/index.html` in a browser and test the language switcher.
## Code Contributions
- **Dependencies**: if you add a new Python library to `requirements.txt`, you MUST run `voxvera vendorize` to include it in the portable distribution.
- **Layout Integrity**: VoxVera uses visual width validation. If you add new UI elements, ensure they respect the physical boundaries of an 8.5"x11" flyer.
- **Tests**: Ensure all tests pass: `pytest tests/`. Run the integrity suite specifically when modifying locales: `pytest tests/test_integrity.py`.
- **Generated artifacts**: Treat `voxvera/resources/bin/` as local build output, not source files. Release binaries belong in GitHub Releases, not hand-edited repo state.
- **Style**: Follow the existing coding style (PEP 8 for Python).
- **Documentation**: If adding a new feature, update the master templates in `docs/templates/` and run `voxvera build-docs`.
---
Together, we can ensure that truth remains accessible to everyone, everywhere.
-19
View File
@@ -1,19 +0,0 @@
# Docker Usage
Experimental: the container path is not yet a production-grade hidden-service deployment target. Linux with `systemd --user` remains the supported persistent-host environment.
A prebuilt image containing Tor, OnionShare and the `voxvera` CLI is published to
`ghcr.io/voxvera/voxvera`.
```bash
# pull the image
docker pull ghcr.io/voxvera/voxvera:latest
# run the experimental container with flyers stored in ./flyers
mkdir -p flyers
docker run -it --rm -v "$(pwd)/flyers:/flyers" ghcr.io/voxvera/voxvera
```
The container stores runtime state under `/flyers`, seeds a default `config.json` if needed, and retries `voxvera start-all` periodically after the initial `quickstart`.
Use this path for testing only until the container runtime and background recovery behavior are validated end-to-end.
-14
View File
@@ -1,14 +0,0 @@
# Flyer Templates
Pre-built flyer templates live in the `templates/` directory. Use the CLI to copy one with:
```bash
voxvera init --template <name>
```
This will create a new folder under `dist/` named `<name>-<YYYYMMDD>` containing the template files.
Available templates:
- **blank** – minimal placeholder files, also used when extracting fields from a PDF.
- **voxvera** – example flyer showcasing the VoxVera project.
-75
View File
@@ -1,75 +0,0 @@
# Troubleshooting
This page collects common issues encountered when hosting or accessing flyers.
## Tor connectivity
- Ensure Tor is allowed through your firewall. On systems using `ufw` you may need to run `sudo ufw allow tor`.
- Some networks block Tor entirely. If you cannot reach onion services, try connecting over a different network or use a Tor bridge.
## Supported deployment target
- The supported persistent-host setup is Linux with `systemd --user`.
- Windows, macOS, Docker, Flatpak, AppImage, Homebrew, and Chocolatey are currently experimental and may not recover hosting automatically after reboot or network interruptions.
## Tor port detection
`voxvera serve` auto-detects Tor by probing common ports (9050/9150 for SOCKS, 9051/9151 for control). If detection fails -- for example when Tor runs on non-standard ports -- you can override with environment variables:
```bash
TOR_SOCKS_PORT=19050 TOR_CONTROL_PORT=19051 voxvera serve
```
If no running Tor is found, the defaults (9050/9051) are used and OnionShare will attempt to connect on those ports.
## Firewall rules
- If `voxvera serve` fails to start OnionShare, verify that outbound connections on ports 9001 and 80 are permitted.
- Corporate or university firewalls can block the hidden service ports required by Tor.
## SELinux
- On SELinux-enabled distributions you may see `permission denied` errors when OnionShare writes to the `host` directory.
- Run `sudo chcon -Rt svirt_sandbox_file_t host` or disable SELinux enforcement for the folder.
## OnionShare crashes
If `voxvera serve` prints "OnionShare exited unexpectedly", check the log file
`host/<folder_name>/onionshare.log` for details. Common causes:
- Tor is not running (`sudo systemctl start tor`)
- A port conflict with another service
- Missing `onionshare-cli` (run `voxvera check`)
## Onion URL changed unexpectedly
The onion URL is tied to the Ed25519 keypair stored in
`host/<folder_name>/.onionshare-session`. If this file is deleted, a new
keypair (and URL) will be generated on the next `voxvera serve`. The
`voxvera import` command preserves this file automatically, but manual
deletion of the `host/` directory will destroy it.
## Hosting does not return after reboot or network loss
On Linux, install or verify the recovery timer:
```bash
voxvera autostart
systemctl --user status voxvera-start.timer
systemctl --user status voxvera-start.service
```
The supported recovery path is the recurring `systemd --user` timer, which reruns `voxvera start-all` every few minutes.
## QR codes not generated
If `voxvera build` reports "No URLs configured yet", this is expected before the first `voxvera serve`. QR codes for tear-off links are generated automatically once the .onion address is known. QR codes for the content link are generated if you provided a URL during `voxvera init`.
## Electron GUI
If `npm start` fails with `spawn voxvera ENOENT`, the `voxvera` command is not in your `PATH`. Install it with `pipx install git+https://github.com/PR0M3TH3AN/VoxVera.git` or run `./install.sh` from the repository.
## Missing dependencies
Run `voxvera check` to verify your setup. The command checks for required
Python packages (`qrcode`, `Pillow`, `jsmin`, `htmlmin`, `pypdf`) and
external tools (`onionshare-cli`), then prints a summary of anything
missing. To install everything:
```bash
# Recommended: use the install script (handles Tor + OnionShare too)
curl -fsSL https://raw.githubusercontent.com/PR0M3TH3AN/VoxVera/main/install.sh | bash
# Or reinstall just the Python package
pipx install --force 'voxvera@git+https://github.com/PR0M3TH3AN/VoxVera.git@main'
```
-130
View File
@@ -1,130 +0,0 @@
# Uso Detalhado
Este guia cobre os fluxos de trabalho comuns da CLI. Veja `docs/docker.md` para instruções do Docker e `docs/templates.md` para modelos de panfletos disponíveis.
## Pré-requisitos
O VoxVera foi projetado para ser altamente portátil e requer dependências mínimas do sistema.
### 1. Binários Independentes (Recomendado)
Você pode baixar binários independentes e sem dependências para o seu sistema operacional:
- **Linux:** `voxvera-linux`
- **Windows:** `voxvera-windows.exe`
- **macOS:** `voxvera-macos`
Estes binários incluem tudo o que é necessário para executar o VoxVera (exceto o `onionshare-cli`).
### 2. Instalador de Linha Única
Alternativamente, instale através do nosso script automatizado:
```bash
curl -fsSL https://raw.githubusercontent.com/PR0M3TH3AN/VoxVera/main/install.sh | bash
```
### 3. Instalação Manual via Python
Se preferir executar a partir do código-fonte:
```bash
pipx install 'voxvera@git+https://github.com/PR0M3TH3AN/VoxVera.git@main'
sudo apt install tor onionshare-cli # Debian/Ubuntu
```
## Passo a Passo
1. **Inicializar:** Execute `voxvera init` e siga as instruções. Você será solicitado a selecionar seu idioma primeiro.
2. **Construir:** Gere os arquivos do panfleto. Cada construção cria automaticamente um `voxvera-portable.zip` na pasta do panfleto, permitindo que outros baixem a ferramenta completa diretamente do seu panfleto.
```bash
voxvera build
```
3. **Servir:** Publique o panfleto via Tor:
```bash
voxvera serve
```
Isso detecta automaticamente sua instância do Tor, inicia o OnionShare e escreve o endereço .onion gerado nos links destacáveis do panfleto.
## Suporte a Idiomas
O VoxVera é totalmente localizado. Você pode alterar sua preferência de idioma permanentemente usando o seletor interativo ou um atalho direto:
- **Seletor Interativo:** `voxvera lang`
- **Atalho Direto:** `voxvera --lang pt` (define a preferência para português)
### Idiomas Suportados:
- **Inglês:** `en`
- **Espanhol:** `es` (alias: `--idioma`)
- **Alemão:** `de` (alias: `--sprache`)
- **Português:** `pt`
Você também pode forçar um idioma específico para um único comando sem alterar sua preferência permanente:
- **Inglês:** `voxvera --lang en check`
- **Português:** `voxvera --lang pt check`
Os panfletos gerados detectam automaticamente o idioma do navegador do visitante e alteram o texto da interface adequadamente.
## Gerenciamento de Servidores
Gerencie vários panfletos e suas identidades Tor a partir de um único menu interativo:
```bash
voxvera manage
```
Recursos:
- **--- Criar Novo Site/Panfleto ---**: Inicia a sequência completa de configuração.
- **--- Iniciar Todos os Sites ---**: Inicia ou encerra todos os panfletos da sua frota de uma só vez.
- **Status em Tempo Real**: Visualize URLs .onion ativas e indicadores de progresso de inicialização do Tor.
- **Controle Individual**: Exportar para Zip sites específicos para ZIP ou exclua-os.
## Espelhamento Universal (Distribuição Viral)
Para garantir que o VoxVera permaneça acessível mesmo se os repositórios centrais forem censurados, cada panfleto atua como um espelho para a ferramenta.
Quando você hospeda um panfleto, o botão **"Baixar Ferramenta e Código"** na página inicial fornece um `voxvera-portable.zip` contendo:
- O código-fonte completo e todos os idiomas suportados.
- Todas as dependências Python (pré-vendidas).
- Binários Tor multiplataforma.
Isso permite que qualquer pessoa que escaneie seu panfleto se torne um novo distribuidor da ferramenta VoxVera.
## Exportação e Backup
Faça backup de suas identidades Tor exclusivas (para que sua URL .onion nunca mude) ou mova seus panfletos para outra máquina.
- **Exportar um único site**: `voxvera export <nome_da_pasta>`
- **Exportar todos os sites**: `voxvera export-all`
**Local de armazenamento:** Todas as exportações são salvas como arquivos ZIP em uma pasta chamada `voxvera-exports` no diretório inicial do usuário (`~/voxvera-exports/`) em todas as plataformas.
## Importação e Recuperação
Restaure toda a sua configuração em uma nova máquina movendo seus arquivos ZIP para `~/voxvera-exports/` e executando:
```bash
voxvera import-multiple
```
## Portabilidade e Uso Offline
Se precisar executar o VoxVera em uma máquina sem acesso à internet, você pode "venderizar" as dependências primeiro:
```bash
voxvera vendorize
```
Isso baixa todas as bibliotecas Python necessárias para `voxvera/vendor/`. A ferramenta priorizará esses arquivos locais, permitindo que ela funcione sem `pip install`.
## Importação em Lote (JSON)
Para gerar panfletos em massa a partir de vários arquivos de configuração JSON, coloque-os no diretório `imports/` e execute:
```bash
voxvera batch-import
```
## Como as URLs Funcionam
Cada panfleto tem duas URLs separadas:
- **Link destacável** (gerado automaticamente): O endereço .onion onde o panfleto está hospedado.
- **Link de conteúdo** (configurado pelo usuário): Uma URL externa apontando para um site, vídeo ou download.
Você não precisa inserir manualmente o endereço .onion; o VoxVera lida com isso automaticamente durante a fase de `serve`.
-270
View File
@@ -1,270 +0,0 @@
# Platform Parity Roadmap
This roadmap focuses on one question:
How do we expand VoxVera beyond Linux without overstating reliability, while still converging on real cross-platform parity for Tor hidden-service hosting?
## Strategic Principle
Parity is not a packaging milestone. It is a runtime-contract milestone.
Every platform must eventually implement the same hosting contract:
1. install VoxVera
2. ensure Tor and OnionShare are available
3. build site assets
4. serve the hidden service
5. preserve `.onionshare-session`
6. recover hosting after reboot, login, suspend, or offline periods
7. surface logs and status
Package formats should inherit that contract. They should not define independent behavior.
## Phase 0: Truth Alignment
Goal: bring repo claims, docs, and release posture into line with current reality.
Deliverables:
- canonical support matrix
- machine-readable support declaration
- installer/package warnings for experimental paths
- README and docs aligned to the actual supported target
Definition of done:
- no docs imply parity that tests do not support
- every platform surface has an explicit support tier
- release artifacts are not treated as proof of hosting reliability
## Phase 1: Harden Linux As Reference
Goal: make Linux CLI with `systemd --user` the clearly defensible model that other platforms copy.
Work items:
1. Add `voxvera doctor` for runtime validation.
- Check Tor reachability.
- Check OnionShare availability.
- Check `start-all` surfaces.
- Check autostart timer installation.
- Check host directories and session files.
2. Add `voxvera autostart status`.
- Show service and timer files.
- Show whether the timer is enabled.
- Show next/last run timestamps if available.
3. Normalize Linux log/status guidance.
- Document host log paths.
- Document timer/service status commands.
- Document expected recovery flow after reboot/network loss.
4. Validate restart behavior.
- fresh install
- first serve
- reboot
- suspend/resume if possible
- temporary offline period followed by reconnect
Definition of done:
- Linux remains the only `supported` path until the above evidence exists and is documented.
## Phase 2: Platform Adapter Layer
Goal: stop encoding platform logic in ad hoc installer scripts.
Recommended structure:
- `voxvera/platforms/base.py`
- `voxvera/platforms/linux.py`
- `voxvera/platforms/macos.py`
- `voxvera/platforms/windows.py`
- `voxvera/platforms/docker.py`
Each adapter should define:
- support tier
- Tor discovery strategy
- OnionShare discovery strategy
- state root
- autostart installation strategy
- autostart status strategy
- log/status surface
- known limitations
CLI surfaces to add:
- `voxvera doctor`
- `voxvera platform-status`
- `voxvera autostart`
- `voxvera autostart status`
- `voxvera autostart uninstall`
Definition of done:
- shell installers become thin wrappers over shared Python logic instead of owning runtime policy themselves
## Phase 3: Docker Beta Candidate
Goal: make Docker a coherent, testable deployment surface.
Decisions to settle:
- single-container runtime vs compose-based runtime
- host Tor vs container Tor
- log and state persistence model
Recommended direction:
- keep runtime state under one explicit volume root
- document restart policy clearly
- make health and recovery behavior observable
Validation checklist:
- container restart preserves onion identity
- host reboot with restart policy restores hosting
- state remains in mounted volume
- logs remain inspectable
Promotion target:
- `experimental` -> `beta`
## Phase 4: macOS CLI
Goal: establish one honest CLI-based macOS hosting model before packaging.
Work items:
1. define Tor discovery strategy
2. define OnionShare discovery/install strategy
3. validate manual `build` + `serve`
4. implement and validate `launchd` recovery
5. document known limitations
Promotion target:
- remain `experimental` until `launchd` recovery is validated
- move to `beta` only after login/reboot/offline recovery evidence exists
## Phase 5: Windows CLI
Goal: establish one canonical Windows runtime model before claiming package parity.
Work items:
1. unify binary naming across installer, Chocolatey, docs, and release assets
2. define Tor discovery strategy
3. define OnionShare discovery strategy
4. validate manual `build` + `serve`
5. implement Task Scheduler recovery path
6. add Windows-specific status/log guidance
Promotion target:
- remain `experimental` until scheduled recovery and state persistence are proven
- move to `beta` only after reboot/login/offline recovery evidence exists
## Phase 6: Electron GUI Convergence
Goal: make the GUI a frontend to the supported runtime, not a separate runtime.
Work items:
1. route the GUI through shared CLI/runtime surfaces
2. reduce duplicated Tor startup behavior
3. add visibility for:
- Tor status
- OnionShare status
- hosting status
- onion URL
- logs
4. make window-close behavior explicit and safe
Promotion target:
- GUI remains `experimental` until it stops diverging from the CLI runtime contract
## Phase 7: Package Surface Promotion
Goal: package formats should become trustworthy wrappers around validated runtimes.
Work items:
1. Debian package
- declare actual runtime dependencies
- validate install + host + recovery path
2. AppImage
- decide whether it is distribution-only or a real hosting target
3. Homebrew
- fix artifact URL/sha/version policy
- clarify whether it installs a hosting target or just a CLI
4. Chocolatey
- align artifact naming and installer semantics
5. Flatpak
- decide whether Tor/OnionShare can be supported sanely in-sandbox
Rule:
- no package surface should be promoted above the support tier of its underlying runtime
## Testing Program
### 1. Unit tests
- config/state logic
- autostart file generation
- platform adapter selection
### 2. Mocked integration tests
- `serve`
- `autostart`
- `doctor`
- `platform-status`
### 3. Platform smoke tests
- fresh install
- build
- serve
- persist identity
- restart
- recover
Current smoke target names:
- `linux-cli`
- `macos-cli`
- `windows-cli`
- `docker-cli`
These target names are contract-level validation entry points. Only `linux-cli` currently represents a supported hosting path; the others should be used to validate experimental posture and dependency discovery on their native platforms until their recovery behavior is proven.
### 4. Release checks
- support matrix is current
- docs match support tiers
- artifact names match scripts and package manifests
## Immediate Next Tasks
1. Add `voxvera doctor`.
2. Add `voxvera autostart status`.
3. Add the platform adapter scaffold.
4. Capture Linux reboot/offline recovery validation steps in docs and CI notes.
5. Pick Docker's canonical runtime model.
6. Normalize Windows binary naming before further Windows work.
## Non-Goals
- claiming parity before recovery behavior is validated
- treating package availability as support proof
- maintaining separate runtime semantics in GUI vs CLI
-93
View File
@@ -1,93 +0,0 @@
# VoxVera Roadmap & Technical Specification (v0.2.0)
This document outlines the next major evolution of the VoxVera project, focusing on trust, social amplification, visual versatility, and network resilience.
---
## 1. Integrity & Trust (PGP Signing)
**Goal:** Provide cryptographic proof that the `voxvera-portable.zip` provided by a flyer has not been tampered with by the hoster.
### Technical Requirements
- **CLI:** Add `voxvera sign <folder_name>` command.
- **Dependency:** Use a lightweight PGP implementation (e.g., `python-gnupg` or `pgpy`) to sign the portable ZIP.
- **Storage:** Generate a `.sig` or `.asc` file alongside the ZIP in the `download/` folder.
- **Web:** The landing page will look for `voxvera-portable.zip.asc`. If found, a **"Verified Source"** badge with the signer's Fingerprint will appear next to the download button.
### Implementation Phases
1. **Phase 1:** Add PGP key generation/import logic to `voxvera init`.
2. **Phase 2:** Update `build_assets` to optionally sign the generated ZIP.
3. **Phase 3:** Update `index-master.html` to display verification status.
---
## 2. Nostr Integration (Social Amplification)
**Goal:** Bridge the physical world (flyers) with the decentralized digital world (Nostr) by automatically broadcasting live .onion sites.
### Technical Requirements
- **CLI:** Add `voxvera serve --nostr` flag.
- **Workflow:** When a site goes live and the `.onion` URL is generated, the tool posts a "Flyer Event" to a list of configured Nostr relays.
- **Identity:** Users can provide an existing NSEC or have VoxVera generate a "Flyer Identity" (new NPUB) for that specific server.
- **Metadata:** Include tags for the flyer title, headline, and the `.onion` link.
### Implementation Phases
1. **Phase 1:** Add `nostr` and `bech32` to the `vendor/` directory.
2. **Phase 2:** Implement a background broadcast thread in `serve()`.
3. **Phase 3:** Add "View on Nostr" links to the flyer footer.
---
## 3. The "Tear-off" Designer (Template Gallery)
**Goal:** Expand the utility of VoxVera to new use cases like missing person alerts, protest organizing, and artistic distribution.
### Technical Requirements
- **Restructuring:** Move from a single `voxvera` template to a category-based system:
- `/templates/default/` (The original Operation VoxVera style)
- `/templates/minimal/` (Clean, text-heavy)
- `/templates/alert/` (High-contrast, for emergencies)
- `/templates/art/` (Image-focused)
- **CLI:** Update `voxvera init` to include a visual description and selector for templates.
### Implementation Phases
1. **Phase 1:** Refactor `copy_template` to support categories.
2. **Phase 2:** Design and implement 3 new HTML/CSS templates.
3. **Phase 3:** Allow templates to define their own custom character limits (e.g., "Alert" might allow larger headlines).
---
## 4. Self-Healing Network (Update Logic)
**Goal:** Ensure the decentralized "Viral" network stays current with security fixes and features.
### Technical Requirements
- **Discovery:** The tool will check a "Source of Truth" (e.g., `voxvera.org/version.json` or a hardcoded list of onion mirrors).
- **Notification:** `voxvera manage` will show a 🌟 or ⚠️ next to the version number if an update is available.
- **Update Workflow:** Provide a `voxvera update` command that downloads the latest `voxvera-portable.zip` and safely replaces the `vendor/` and `voxvera/` directories.
### Implementation Phases
1. **Phase 1:** Implement version-checking logic via Tor SOCKS proxy.
2. **Phase 2:** Add update notifications to the management menu.
3. **Phase 3:** (Advanced) Implement "In-Place" updates for the vendored dependencies.
---
## 5. GUI Modernization
**Goal:** Transition the Electron wrapper from a CLI mirror to a rich, visual dashboard.
### Technical Requirements
- **Flyer Cards:** Replace the text list with visual "cards" showing the flyer's headline and a mini QR preview.
- **Tor Dashboard:** A dedicated tab showing all active hidden services, their uptime, and their `.onion` links.
- **One-Click Actions:** Visual buttons for "Export All," "Start All," and "New Flyer."
- **Direct Log Stream:** A collapsible panel to see the OnionShare logs in real-time.
### Implementation Phases
1. **Phase 1:** Update the IPC bridge between Electron and the Python CLI.
2. **Phase 2:** Redesign the frontend using a modern, dark-themed CSS framework (keeping it local-first).
3. **Phase 3:** Add a "Theme Preview" during the flyer creation process.
---
## Summary of Impact
By completing this roadmap, VoxVera moves from a standalone utility to a **Decentralized Information Ecosystem**.
- **Security** is solved via PGP.
- **Reach** is solved via Nostr.
- **Versatility** is solved via the Template Gallery.
- **Sustainability** is solved via Update Logic.
+340
View File
@@ -0,0 +1,340 @@
# VoxVera Roadmap & Known Issues
This document captures known limitations and the development directions that
would address them. None of these are code bugs — they are product- and
threat-model-level gaps in the current static Nostr client. They are listed
roughly in priority order: the trust model (#1–#2) is the highest-leverage area
because almost every other risk flows from it being undefined.
Status legend: **Open** (not started) · **Partial** (some mitigation exists) ·
**Planned** (committed direction) · **In progress** (partially shipped).
## Shipped so far (2026-06-10)
The trust model (#1–#2) has moved from undefined to implemented:
- **Bulletin board login gate** — viewing the board requires a connected Nostr
identity (NIP-07 extension, a pasted `nsec`, or a generated key).
- **Web-of-trust filter (degree-2)** — the board defaults to flyers from authors
in the viewer's NIP-02 follow graph *and the people those follows follow*
(follows-of-follows), seeded from a curator account for fresh keys, with a
"Show all" opt-out (so it is no longer an unmoderated firehose).
- **Editor↔board identity sync** — a deliberate editor identity choice (NIP-07,
imported/generated/unlocked nsec, or anonymous) is shared with the board via a
local pubkey, so the same person sees a consistent identity across both pages.
- **Editor publishing identity** — authors can publish anonymously (default),
via NIP-07, or with an imported `nsec` that is optionally PIN-encrypted at
rest (PBKDF2 → AES-GCM; plaintext never stored).
- **Flyer management (edit / re-publish / delete)** — an author can edit a
loaded flyer (re-publish replaces in place via the `d` tag), re-publish as a
keep-alive, or delete it. Delete is belt-and-suspenders: a replaceable
**tombstone** (so the board/viewer hide it even on relays that ignore NIP-09)
plus a **NIP-09** deletion request. Best-effort, author-only. These actions are
available in the editor and inline on the bulletin board (Edit / Re-broadcast /
Delete on your own rows).
- **Local blocklist** — a per-device "Block" on the board hides flyers from any
author you didn't post (separate from the web-of-trust filter), with a clear
control. This is the local blocklist direction from #1.
- **Report (NIP-56)** — a board "Report" action on others' flyers publishes a
signed **kind-1984** report (category + optional reason) referencing the flyer
(`e`) and author (`p`), so other clients and moderators can aggregate it.
Reporting also hides the flyer locally (pairs with the blocklist).
- **Author display names** — the board shows each author's kind-0 display name
(falling back to the npub), so flyers aren't labeled by bare keys. (NIP-05
*verification* is still a future addition.)
- **"My flyers" filter** — a board toggle to show only the connected user's own
flyers (overrides the trust filter, since your own may not be in your graph).
All of the above is localized across the 14 languages and covered by the
cross-engine Playwright suite. **What remains** on #1–#2 is polish (NIP-05
badges, an identified-vs-anonymous display) plus
the editor follow-ups noted under the *Planned direction* section. **#3–#5 are
still fully open** — distribution centralization (#3) is now the
highest-leverage untouched item.
---
## 1. Bulletin board has no moderation or abuse story — **In progress**
> Direction agreed and **Phases 1–2 shipped**: the board requires a connected
> Nostr identity to view, and it now filters to flyers from the viewer's NIP-02
> web of trust (with a bootstrap seed for new keys). See *Planned direction:
> identity + web-of-trust on the board* below (jointly addresses #1 and #2).
> Remaining: NIP-05 badges (Phase 3). Degree-2 trust + NIP-56 report shipped.
**Problem.** `board.html` lists every Nostr event tagged `t=voxvera` / `t=flyer`
from the public default relays, with no filtering, verification, or moderation.
Anyone can publish a kind-`30078` event with those tags and immediately appear
on the board — including spam, hostile titles, or links to harmful content, all
under VoxVera's branding.
**Current mitigation (Partial on safety, not abuse).** Relay content is treated
as untrusted: titles and npubs are HTML-escaped, and link URLs are rejected
unless `http(s)` (so `javascript:`/`data:` never render). This prevents script
injection but does nothing about spam or unwanted-but-valid content.
**Why it matters.** A static client cannot rate-limit or moderate server-side,
so the board is trivially gameable the moment it is used adversarially. This is
the single biggest liability for promoting the board publicly.
**Possible directions.**
- Client-side curation: an allowlist of npubs (a "follows"/featured set) so the
default view shows only vetted authors.
- A local, user-controlled blocklist / "hide this" with `localStorage`
persistence (per-device, no server needed). **✅ Shipped** — the board's
per-row **Block** (`voxvera_blocked_pubkeys`).
- A dedicated VoxVera relay (or relay set) that applies its own admission
policy, with the public relays as fallback.
- A "report" affordance that records to a relay/list a curator can act on.
- Make the unfiltered firehose an explicit opt-in mode, not the default.
Depends on **#2** (without identity, allowlists/blocklists are weak).
## 2. Anonymous keys give no authenticity or accountability — **In progress**
> Phases 1–2 shipped: the board viewer connects a real Nostr identity (NIP-07)
> and the board is filtered by that viewer's web of trust (with a curator seed
> for new keys), so spam from unknown authors is hidden by default. The **editor
> now lets authors publish under their own identity too** — NIP-07, an imported
> `nsec` (optionally PIN-encrypted at rest), or stay anonymous (default) — so a
> flyer can carry a stable, identifiable author when the creator wants one.
> Authenticity *display* on the board (NIP-05 badges, an identified/anonymous
> distinction) remains ahead.
**Problem.** The client generates a fresh anonymous key per browser, so the
board's "Posted by" npub is effectively random and there is no way to verify a
flyer came from who it claims. The trust model is currently empty.
**Why it matters.** Authenticity underpins the board, "report"/blocklist
features, and any notion of a trusted author. Without stable identity, #1 has no
foundation to build on.
**Possible directions.**
- Optional persistent identity: let a user keep/reuse a key (or import one) and
associate it with their flyers, while keeping anonymous-by-default.
- First-class NIP-07 support for users who already have a Nostr identity.
- Optional NIP-05 / verified handle display on the board.
- A clear UI distinction between "anonymous" and "identified" flyers.
The npub column on the board was built deliberately forward-looking so this
maps in cleanly.
## Planned direction: identity + web-of-trust on the board
Jointly addresses #1 and #2. The goal is to make the board accountable without
abandoning anonymous-by-default authoring.
**Key reality that shapes the design.** You cannot gate *writing* to public
relays — anyone can publish a `t=voxvera` event directly, never touching this
client. So a "login required to post" button is only a soft deterrent; it can't
bound what is on the board. The real lever is **filtering what the board
displays**. Login's actual job is to supply the *viewer's* identity so the
board can show them flyers from people they trust.
**Principles.**
- **Login enables a trust-filtered view; it is not access control.** The data
is public on relays regardless, so hiding it in the UI is cosmetic. Treat
login as "we know who you are, so we can show you a trustworthy board."
- **Keep anonymous creation + printing fully available.** The core authoring
tool must not require a persistent, linkable identity (activist threat model).
Identity is required only to *appear on the public board*, not to make/print a
flyer.
- **Web-of-trust is the actual spam defense, not login.** NIP-07 keys are free
and unlimited, so "must have a key" alone just makes a spammer generate one.
Filtering by the viewer's NIP-02 follow graph (degree 1, optionally
follows-of-follows) is what raises the cost.
- **Don't lock out mobile.** NIP-07 (`window.nostr`) needs a desktop extension,
but scanned-QR flyers open on phones. "Login" should support NIP-07 **plus**
nsec import (with warnings) and/or NIP-46 remote signer, and/or promoting the
existing anonymous key to a kept identity.
**Phased plan.**
- **Phase 1 — Identity. ✅ Shipped.** The board (`board.html` / `board.js`) shows
a login gate instead of the table until the viewer connects. Three methods: a
NIP-07 extension (`window.nostr.getPublicKey()`), pasting an `nsec`, or creating
a new key (see decision 2 below). On success it reveals the table, surfaces the
connected npub with a Disconnect control, and remembers the pubkey in
`localStorage` (`voxvera_connected_pubkey`) so a return visit reconnects from
the pubkey alone — no prompt or re-entry, regardless of method. Anonymous
create/print is untouched — connecting is required only to *view the board*.
- **Phase 2 — Web-of-trust filter. ✅ Shipped.** On connect the board fetches
the viewer's NIP-02 contact list (kind 3) and defaults to flyers from authors
in their follow graph (degree 1) plus themselves, with a **"Show all"**
opt-out. **Bootstrap seed:** a viewer with no follow list of their own (a
fresh key) is seeded from a pinned curator account's follows
(`FALLBACK_CURATOR_PUBKEY` in `board.js` =
`npub15jnttpymeytm80hatjqcvhhqhzrhx6gxp8pq0wn93rhnu8s9h9dsha32lx`), so a brand-
new viewer still gets a curated board instead of the unmoderated firehose. If
no trust data can be fetched at all, the board falls back to showing
everything (never mysteriously empty). Covered by the cross-engine e2e suite
(followed-only view + show-all opt-out; curator-seeded fallback).
- **Phase 3 — In progress.** Degree-2 trust (follows-of-follows) ✅ shipped; the
local blocklist / "hide this" ✅ shipped; NIP-56 reporting (kind 1984) ✅
shipped. **Remaining:** NIP-05 verified badges, and a curator-side flow that
*consumes* reports (today a report is published for others to aggregate, but
the board does not yet act on report counts). Also: the bootstrap curator is a
single hardcoded pubkey — consider making it configurable or a small set.
**Decisions made (2026-06-10).**
1. **Board viewing: login-required.** The board is blank (a Connect prompt)
until a Nostr identity is connected — framed as a members' space rather than a
public discovery surface.
2. **Login methods: NIP-07 + nsec import + key generation. ✅ Shipped.** The gate
offers three ways in: a NIP-07 browser extension, pasting a private key
(`nsec`), or creating a new key. The nsec is decoded **in-page** to derive the
pubkey and then discarded — only the pubkey is persisted, since the board only
reads (never signs). "Create a new key" reuses this device's existing
anonymous key if present (so it doesn't orphan an editor identity) or
generates one, and reveals the `nsec` with a "save this — we can't recover it"
warning before continuing. This **resolves the earlier mobile-lockout
trade-off**: a phone visitor with no extension can now generate or paste a key
to view the board. Covered by the cross-engine e2e suite (nsec import +
pubkey-only persistence + reload restore; invalid nsec; key generation +
reveal + connect).
**Follow-ups this opens.**
- **In-page nsec handling.** Pasting a secret key into a web page is inherently
riskier than a NIP-07 extension that keeps the key isolated; the input is a
password field, the value is cleared after use, and nothing is transmitted. The
**NIP-46 remote signer** (below) is now the safer mobile path.
- **NIP-46 remote signer (shipped — editor *and* board, both connect paths).**
Both the editor's publishing identity and the board's login gate can connect a
remote signer two ways: **(a) `bunker://`** — paste a link the signer app
generated; and **(b) `nostrconnect://` (QR)** — *we* generate the link, show it
as a QR (and a copyable link for one-device use), and the signer app scans it
and connects back (verified by echoing our secret). Either way the user's
secret stays in their signer app (nsec.app, Amber, …) and the browser holds
only an ephemeral local key. The client is hand-rolled over a raw WebSocket
using the vendored NIP-44 (with a NIP-04 decrypt fallback) — the bundle ships
no nip46 module; the QR flow uses `relay.nsec.app` as the rendezvous relay. On
the board it establishes the viewer pubkey and keeps the connection so
reports/deletes are signed remotely (read-only after a reload). Connections are
**session-only** (nothing is written to disk, so a reload returns to anonymous
/ read-only). Covered by the cross-engine e2e suite for both paths on both
pages (bunker and nostrconnect), against a fake signer doing real NIP-44
crypto.
- **Editor identity (shipped).** The editor signs under anon / NIP-07 / imported
nsec / remote signer. A remembered nsec is PIN-encrypted at rest (PBKDF2 600k →
AES-GCM); plaintext is never stored. **Known weakness:** a short numeric PIN is
brute-forceable offline if the encrypted blob leaks — it guards casual snooping,
not a targeted attacker. A **wrong-PIN lockout** is now in place (3 bad PINs →
a 30s cooldown, persisted across reloads). Optionally encrypting the anonymous
device key the same way is still open (today it is stored in plaintext, as
before).
- **Editor↔board identity sync (shipped).** A deliberate editor identity choice
(NIP-07 / imported / generated / unlocked nsec / remote signer) writes a shared
local pubkey the board reads, so one connected identity is reflected across both
pages.
## 3. Client distribution is centralized (a single chokepoint) — **Open**
**Problem.** The content lives on decentralized relays, but the *client* is one
domain (`voxvera.org`) on a centralized host (Vercel). A censor can block the
domain and most users are stuck, which undercuts the censorship-resistance
premise even though the backend is robust.
**Current mitigation (Partial).** The client is fully static and host-agnostic,
so it *can* be served from any static host or mirror — but discovery and trust
of mirrors is unsolved, so in practice users depend on the canonical domain.
**Possible directions.**
- Document and support official mirrors (IPFS/IPNS, other static hosts) with a
verifiable build (subresource integrity / reproducible hash).
- A one-file/offline build users can save and reopen (`file://`) — verify
WebCrypto/clipboard degrade gracefully off a secure context.
- Revisit the dropped Tor/onion distribution path as an *optional* mirror (kept
off `main` per current guardrails, but a documented option).
- Publish the client itself to a content-addressed network so the front door is
not a single DNS name.
## 4. Relay permanence is overstated — **Partial**
> Partial mitigation shipped: the editor now has a **Re-publish (keep-alive)**
> action, so an author can refresh a flyer before relays age it out. The durable
> fix (a pinned/dedicated relay) is still open.
**Problem.** The app depends on a few general-purpose relays
(`relay.damus.io`, `nos.lol`, `relay.primal.net`) that can prune app-data kinds,
rate-limit, or drop events. "Your flyer is still there later" is therefore not
guaranteed. The single relay hint in the `naddr` also reduces fetch robustness
for events not on the default set.
**Possible directions.**
- Run/pin a dedicated VoxVera relay (or several) so published flyers have a
durable home, with the public relays as redundancy.
- Let authors configure and embed their own preferred relays.
- Consider a re-broadcast / "keep alive" helper for important flyers.
- Reconsider how many relay hints to embed in the poster `naddr` (tradeoff:
URL length / QR density vs. fetch robustness — see the QR Target notes in the
spec).
- **Self-contained fallback payload in the URL fragment (future).** Because a
printed flyer cannot be edited, a pruned/unreachable event leaves a dead QR.
The flyer payload is small (text only), so it could be compressed and encoded
into the URL `#fragment` alongside the `naddr`, letting the viewer render the
flyer *even when no relay has the event* — relay-independent durability, which
fits the censorship-resistance pitch. **Constraint:** the tear-off QR URL is
already near scannable capacity, so this likely can't be added without
reducing the number of tear-off tabs and/or enlarging the QR (denser code,
harder scan). Best treated as an opt-in "durable QR" mode rather than the
default, and decided alongside the tab-count/QR-size tradeoff. The `naddr`
remains the primary resolver; the embedded payload is a last-resort fallback.
## 5. Content-safety guardrails are minimal — **Open**
**Problem.** Beyond HTML-escaping and URL-scheme rejection, there is nothing
preventing the tool (and especially the public board) from being used to author
or surface illegal/harmful content carrying VoxVera's branding.
**Possible directions.** Tie this to #1/#2: curation, reporting, and a clear
terms/acceptable-use stance for any hosted board. A purely local authoring tool
has a smaller surface than a public discovery board, so scope decisions here
should follow the board's trust model.
---
## Smaller / lower-priority items
- **Field-fit is layout-measured, not a fixed cap.** Robust, but capacity
varies with font availability and zoom; the
[cheat sheet](flyer-field-limits.md) is explicitly approximate. Fine as-is;
noted so it is not mistaken for a contract.
- **Favicon — ✅ done.** A small inline SVG (`site/favicon.svg`) is linked from
both pages, so browsers no longer request (and 404 on) `/favicon.ico`.
- **i18n key-parity guard — ✅ done.** `e2e/i18n.spec.js` fails if any
`NOSTR_UI` / `BOARD_UI` / `SAFETY_UI` / locales dictionary is missing (or has
an extra) key in some language (and that the `SAFETY_UI` bullet lists are the
same length in every language). It immediately caught `field_too_long`, which
had been English-only across all 13 other languages.
- **Safety & privacy page — ✅ done.** A standalone `/safety` page
(`safety.html` / `safety.js`), localized across all 14 languages, in plain
language: what VoxVera protects, what it does **not** (relays see your IP; the
anon key is plaintext in the browser; a short PIN won't stop a targeted
attacker; published events are public/permanent; nsec-paste risk; reports are
public; the host/relays still see requests), and operational tips (Tor/VPN,
disposable keys, signer apps). Linked from the editor and the board. Aimed at
the activist/whistleblower audience the aesthetic invites — being honest about
limits matters more than any feature.
- **Link previews / Open Graph — shipped (site-wide).** Static OG +
Twitter-card meta are on the home, board, and safety pages, including a
**1200×630 preview image** (`site/og-card.jpg`, `summary_large_image`), so a
shared `voxvera.org` link renders a real title, description, and image card.
**Per-flyer previews remain a deliberate non-goal:** the poster `naddr` lives
in the URL `#fragment` (invisible to servers), and a static host can't render
per-flyer `<meta>`/image without server-side code — out of scope by choice
(this stays a free, purely static site). Revisit only if that constraint ever
changes.
- **Publish transparency — ✅ done.** The publish confirmation modal now reports
how many relays accepted the event ("Relays accepted: N / M") and flags a
zero-acceptance publish, so a weak publish is visible immediately.
- **WebKit/Safari coverage in CI** needs `libavif16` on Linux runners
(`sudo npx playwright install-deps`); headless WebKit is also not a perfect
stand-in for real Safari/iOS print + clipboard behavior, so a real-device
pass before releases is still worth it.
---
*Reviewed 2026-06-10. The trust model (#1–#2) is now implemented — see "Shipped
so far" above. The highest-leverage untouched item is now #3 (the client is a
single centralized domain), since it most undercuts the censorship-resistance
premise even with the backend on decentralized relays.*
-42
View File
@@ -1,42 +0,0 @@
# AI Agent Instructions for VoxVera
This guide is for AI agents (like Gemini, Claude, or GPT) contributing to the VoxVera project. Follow these protocols to maintain the architectural integrity and multi-language support.
## Core Mandates
1. **Security-First**: VoxVera is a Tor-based tool. Never suggest features that leak IP addresses or use non-Tor external resources (CDNs, etc.).
2. **Local-First**: All assets (fonts, dependencies, binaries) must be self-contained within the `voxvera/` package to support the Universal Mirroring model.
3. **Tokenized UI**: Never hardcode user-facing strings. Always add them to `voxvera/locales/en.json` and use the `t('cli.token')` helper.
4. **Markdown Redaction**: Use `~~text~~` in locale JSONs for strike-through effects. Both the build system and the JS engine handle the conversion to `<span class="redacted">` automatically.
5. **Visual Width Testing**: When modifying UI or adding languages, verify that long or complex strings (e.g., Hindi ligatures or CJK characters) do not exceed the visual unit limits defined in the CLI.
## Localization Protocol
When adding a new language or updating an existing one:
- **CLI/Flyers**: Update `voxvera/locales/{lang}.json`. Include `meta`, `cli`, `web`, and `landing` categories.
- **Landing Page**:
- Directly update the `const locales` object in `site/index.html`.
- **Crucial**: Run `voxvera build-site` to generate the latest portable bundle and refresh the pre-rendered HTML.
- **Documentation**:
- Master templates live in `docs/templates/`.
- Localized overrides live in `voxvera/locales/{lang}/docs/`.
- **Crucial**: After any change to locales or templates, you MUST run `voxvera build-docs` to synchronize the output in `docs/{en,es,de}/`.
## Universal Mirroring
VoxVera propagates through its own flyers.
- Every `voxvera build` and `voxvera build-site` generates `voxvera-portable.zip`.
- If you modify the core source code, ensure the `bundle_portable` function in `voxvera/cli.py` still correctly captures all necessary directories (especially `vendor/`, `locales/`, and `resources/`).
## Verification Checklist
Before finishing a task, ensure you have:
1. Run unit tests: `pytest tests/test_cli.py`.
2. Verified the localization: `voxvera --lang {lang} check`.
3. Rebuilt the documentation: `voxvera build-docs`.
4. Synchronized the public site: `voxvera build-site`.
5. Verified the portable bundle exists: `ls -l voxvera/host/*/download/voxvera-portable.zip` and `ls -l site/download/voxvera-portable.zip`.
---
Follow these rules to ensure VoxVera remains a robust, viral, and decentralized tool for truth.
-47
View File
@@ -1,47 +0,0 @@
# Contributing to VoxVera
Thank you for your interest in contributing to VoxVera! This project aims to be a global, censorship-resistant tool, and your help—especially with translations—is vital.
## Adding a New Language
VoxVera uses a centralized token system for the CLI and Web components, and a template-based system for Documentation. To add a new language (e.g., French/`fr`), follow this checklist:
### 1. The Token File
Create a new JSON file in `voxvera/locales/{lang_code}.json`.
- Use `en.json` as your master template.
- **`meta`**: Include the native language name and a flag emoji.
- **`cli`**: Translate all strings used in the terminal interface.
- **`web`**: Translate strings used on the generated landing pages and flyers.
- **`landing`**: Translate the specific content for the official VoxVera website.
- **Formatting**: You can use Markdown-style strike-throughs (`~~redacted text~~`) in any of these strings; they will be automatically converted to the stylized "redacted" effect on the flyers.
### 2. The Landing Page
The main landing page is generated from the shared template and locale files.
- Add your language in `voxvera/locales/{lang_code}.json`.
- Do **not** edit `site/index.html` directly; it is generated output.
- Run `voxvera build-site` to refresh the public assets and inject your new locale into the generated HTML.
### 3. Documentation
VoxVera uses the **Doc-Sync Engine** to keep manuals in sync.
- Create localized Markdown files in `voxvera/locales/{lang_code}/docs/`.
- Use the templates in `docs/templates/` as your guide.
- You can use `cli.token_name` to reference terminal commands automatically.
### 4. Build and Verify
Run the following commands to verify your changes:
- `voxvera --lang {lang_code} check` (Verify CLI translation)
- `voxvera build-docs` (Generate localized manuals)
- `voxvera build-site` (Synchronize the public website and generate the latest portable bundle)
- Open the generated `site/index.html` in a browser and test the language switcher.
## Code Contributions
- **Dependencies**: if you add a new Python library to `requirements.txt`, you MUST run `voxvera vendorize` to include it in the portable distribution.
- **Layout Integrity**: VoxVera uses visual width validation. If you add new UI elements, ensure they respect the physical boundaries of an 8.5"x11" flyer.
- **Tests**: Ensure all tests pass: `pytest tests/`. Run the integrity suite specifically when modifying locales: `pytest tests/test_integrity.py`.
- **Generated artifacts**: Treat `voxvera/resources/bin/` as local build output, not source files. Release binaries belong in GitHub Releases, not hand-edited repo state.
- **Style**: Follow the existing coding style (PEP 8 for Python).
- **Documentation**: If adding a new feature, update the master templates in `docs/templates/` and run `voxvera build-docs`.
---
Together, we can ensure that truth remains accessible to everyone, everywhere.
-19
View File
@@ -1,19 +0,0 @@
# Docker Usage
Experimental: the container path is not yet a production-grade hidden-service deployment target. Linux with `systemd --user` remains the supported persistent-host environment.
A prebuilt image containing Tor, OnionShare and the `voxvera` CLI is published to
`ghcr.io/voxvera/voxvera`.
```bash
# pull the image
docker pull ghcr.io/voxvera/voxvera:latest
# run the experimental container with flyers stored in ./flyers
mkdir -p flyers
docker run -it --rm -v "$(pwd)/flyers:/flyers" ghcr.io/voxvera/voxvera
```
The container stores runtime state under `/flyers`, seeds a default `config.json` if needed, and retries `voxvera start-all` periodically after the initial `quickstart`.
Use this path for testing only until the container runtime and background recovery behavior are validated end-to-end.
-14
View File
@@ -1,14 +0,0 @@
# Flyer Templates
Pre-built flyer templates live in the `templates/` directory. Use the CLI to copy one with:
```bash
voxvera init --template <name>
```
This will create a new folder under `dist/` named `<name>-<YYYYMMDD>` containing the template files.
Available templates:
- **blank** – minimal placeholder files, also used when extracting fields from a PDF.
- **voxvera** – example flyer showcasing the VoxVera project.
-75
View File
@@ -1,75 +0,0 @@
# Troubleshooting
This page collects common issues encountered when hosting or accessing flyers.
## Tor connectivity
- Ensure Tor is allowed through your firewall. On systems using `ufw` you may need to run `sudo ufw allow tor`.
- Some networks block Tor entirely. If you cannot reach onion services, try connecting over a different network or use a Tor bridge.
## Supported deployment target
- The supported persistent-host setup is Linux with `systemd --user`.
- Windows, macOS, Docker, Flatpak, AppImage, Homebrew, and Chocolatey are currently experimental and may not recover hosting automatically after reboot or network interruptions.
## Tor port detection
`voxvera serve` auto-detects Tor by probing common ports (9050/9150 for SOCKS, 9051/9151 for control). If detection fails -- for example when Tor runs on non-standard ports -- you can override with environment variables:
```bash
TOR_SOCKS_PORT=19050 TOR_CONTROL_PORT=19051 voxvera serve
```
If no running Tor is found, the defaults (9050/9051) are used and OnionShare will attempt to connect on those ports.
## Firewall rules
- If `voxvera serve` fails to start OnionShare, verify that outbound connections on ports 9001 and 80 are permitted.
- Corporate or university firewalls can block the hidden service ports required by Tor.
## SELinux
- On SELinux-enabled distributions you may see `permission denied` errors when OnionShare writes to the `host` directory.
- Run `sudo chcon -Rt svirt_sandbox_file_t host` or disable SELinux enforcement for the folder.
## OnionShare crashes
If `voxvera serve` prints "OnionShare exited unexpectedly", check the log file
`host/<folder_name>/onionshare.log` for details. Common causes:
- Tor is not running (`sudo systemctl start tor`)
- A port conflict with another service
- Missing `onionshare-cli` (run `voxvera check`)
## Onion URL changed unexpectedly
The onion URL is tied to the Ed25519 keypair stored in
`host/<folder_name>/.onionshare-session`. If this file is deleted, a new
keypair (and URL) will be generated on the next `voxvera serve`. The
`voxvera import` command preserves this file automatically, but manual
deletion of the `host/` directory will destroy it.
## Hosting does not return after reboot or network loss
On Linux, install or verify the recovery timer:
```bash
voxvera autostart
systemctl --user status voxvera-start.timer
systemctl --user status voxvera-start.service
```
The supported recovery path is the recurring `systemd --user` timer, which reruns `voxvera start-all` every few minutes.
## QR codes not generated
If `voxvera build` reports "No URLs configured yet", this is expected before the first `voxvera serve`. QR codes for tear-off links are generated automatically once the .onion address is known. QR codes for the content link are generated if you provided a URL during `voxvera init`.
## Electron GUI
If `npm start` fails with `spawn voxvera ENOENT`, the `voxvera` command is not in your `PATH`. Install it with `pipx install git+https://github.com/PR0M3TH3AN/VoxVera.git` or run `./install.sh` from the repository.
## Missing dependencies
Run `voxvera check` to verify your setup. The command checks for required
Python packages (`qrcode`, `Pillow`, `jsmin`, `htmlmin`, `pypdf`) and
external tools (`onionshare-cli`), then prints a summary of anything
missing. To install everything:
```bash
# Recommended: use the install script (handles Tor + OnionShare too)
curl -fsSL https://raw.githubusercontent.com/PR0M3TH3AN/VoxVera/main/install.sh | bash
# Or reinstall just the Python package
pipx install --force 'voxvera@git+https://github.com/PR0M3TH3AN/VoxVera.git@main'
```
-130
View File
@@ -1,130 +0,0 @@
# Подробное руководство
Это руководство охватывает основные рабочие процессы CLI. См. `docs/docker.md` для инструкций по Docker и `docs/templates.md` для доступных шаблонов листовок.
## Предварительные требования
VoxVera разработан как высокопортативный инструмент и требует минимум системных зависимостей.
### 1. Автономные бинарные файлы (Рекомендуется)
Вы можете скачать автономные исполняемые файлы без зависимостей для вашей операционной системы:
- **Linux:** `voxvera-linux`
- **Windows:** `voxvera-windows.exe`
- **macOS:** `voxvera-macos`
Эти файлы включают все необходимое для запуска VoxVera (кроме `onionshare-cli`).
### 2. Однострочный установщик
Или установите с помощью нашего автоматического скрипта:
```bash
curl -fsSL https://raw.githubusercontent.com/PR0M3TH3AN/VoxVera/main/install.sh | bash
```
### 3. Ручная установка через Python
Если вы предпочитаете запускать из исходного кода:
```bash
pipx install 'voxvera@git+https://github.com/PR0M3TH3AN/VoxVera.git@main'
sudo apt install tor onionshare-cli # Debian/Ubuntu
```
## Шаг за шагом
1. **Инициализация:** Запустите `voxvera init` и следуйте подсказкам. Вам будет предложено сначала выбрать язык.
2. **Сборка:** Сгенерируйте ресурсы листовки. Каждая сборка автоматически создает файл `voxvera-portable.zip` в папке листовки, позволяя другим скачивать полный инструмент прямо с вашей листовки.
```bash
voxvera build
```
3. **Запуск:** Опубликуйте листовку через Tor:
```bash
voxvera serve
```
Это автоматически обнаружит ваш экземпляр Tor, запустит OnionShare и запишет сгенерированный .onion адрес в отрывные ссылки листовки.
## Поддержка языков
VoxVera полностью локализован. Вы можете изменить свои языковые предпочтения навсегда, используя интерактивный селектор или прямой ярлык:
- **Интерактивный селектор:** `voxvera lang`
- **Прямой ярлык:** `voxvera --lang ru` (устанавливает русский язык)
### Поддерживаемые языки:
- **Английский:** `en`
- **Испанский:** `es` (алиас: `--idioma`)
- **Немецкий:** `de` (алиас: `--sprache`)
- **Русский:** `ru`
Вы также можете принудительно использовать определенный язык для одной команды, не меняя постоянные настройки:
- **Английский:** `voxvera --lang en check`
- **Русский:** `voxvera --lang ru check`
Сгенерированные листовки автоматически определяют язык браузера посетителя и соответствующим образом переключают текст интерфейса.
## Управление серверами
Управляйте несколькими листовками и их Tor-идентификаторами из единого интерактивного меню:
```bash
voxvera manage
```
Возможности:
- **--- Создать новый сайт/листовку ---**: Запуск полной последовательности настройки.
- **--- Запустить все сайты ---**: Запуск или остановка всех листовок в вашем парке одновременно.
- **Статус в реальном времени**: Просмотр активных .onion URL и индикаторов прогресса загрузки Tor.
- **Индивидуальный контроль**: Экспорт в Zip определенных сайтов в ZIP или их удаление.
## Универсальное зеркалирование (Вирусное распространение)
Чтобы VoxVera оставался доступным, даже если центральные репозитории будут подвергнуты цензуре, каждая листовка выступает в качестве зеркала для инструмента.
Когда вы хостите листовку, кнопка **"Скачать инструмент и код"** на целевой странице предоставляет `voxvera-portable.zip`, содержащий:
- Полный исходный код и все поддерживаемые языки.
- Все зависимости Python (пре-вендоризованные).
- Кроссплатформенные бинарные файлы Tor.
Это позволяет любому, кто сканирует вашу листовку, стать новым распространителем инструмента VoxVera.
## Экспорт и резервное копирование
Создавайте резервные копии своих уникальных Tor-идентификаторов (чтобы ваш .onion URL никогда не менялся) или переносите листовки на другую машину.
- **Экспорт одного сайта**: `voxvera export <имя_папки>`
- **Экспорт всех сайтов**: `voxvera export-all`
**Место хранения:** Все экспорты сохраняются в виде ZIP-файлов в папке `voxvera-exports` в домашнем каталоге пользователя (`~/voxvera-exports/`) на всех платформах.
## Импорт и восстановление
Восстановите всю свою настройку на новой машине, переместив ZIP-файлы в `~/voxvera-exports/` и запустив:
```bash
voxvera import-multiple
```
## Портативность и работа оффлайн
Если вам нужно запустить VoxVera на машине без доступа к Интернету, вы можете сначала «вендоризовать» зависимости:
```bash
voxvera vendorize
```
Это загрузит все необходимые библиотеки Python в `voxvera/vendor/`. Инструмент будет отдавать приоритет этим локальным файлам, что позволит ему работать без `pip install`.
## Пакетный импорт (JSON)
Чтобы массово генерировать листовки из нескольких конфигурационных файлов JSON, поместите их в директорию `imports/` и запустите:
```bash
voxvera batch-import
```
## Как работают URL-адреса
У каждой листовки есть два отдельных URL-адреса:
- **Отрывная ссылка** (автоматически генерируется): .onion адрес, по которому размещена листовка.
- **Ссылка на контент** (настраивается пользователем): Внешний URL, указывающий на веб-сайт, видео или загрузку.
Вам не нужно вручную вводить .onion адрес; VoxVera обрабатывает это автоматически на этапе `serve`.
-42
View File
@@ -1,42 +0,0 @@
# AI Agent Instructions for VoxVera
This guide is for AI agents (like Gemini, Claude, or GPT) contributing to the VoxVera project. Follow these protocols to maintain the architectural integrity and multi-language support.
## Core Mandates
1. **Security-First**: VoxVera is a Tor-based tool. Never suggest features that leak IP addresses or use non-Tor external resources (CDNs, etc.).
2. **Local-First**: All assets (fonts, dependencies, binaries) must be self-contained within the `voxvera/` package to support the Universal Mirroring model.
3. **Tokenized UI**: Never hardcode user-facing strings. Always add them to `voxvera/locales/en.json` and use the `t('cli.token')` helper.
4. **Markdown Redaction**: Use `~~text~~` in locale JSONs for strike-through effects. Both the build system and the JS engine handle the conversion to `<span class="redacted">` automatically.
5. **Visual Width Testing**: When modifying UI or adding languages, verify that long or complex strings (e.g., Hindi ligatures or CJK characters) do not exceed the visual unit limits defined in the CLI.
## Localization Protocol
When adding a new language or updating an existing one:
- **CLI/Flyers**: Update `voxvera/locales/{lang}.json`. Include `meta`, `cli`, `web`, and `landing` categories.
- **Landing Page**:
- Directly update the `const locales` object in `site/index.html`.
- **Crucial**: Run `voxvera build-site` to generate the latest portable bundle and refresh the pre-rendered HTML.
- **Documentation**:
- Master templates live in `docs/templates/`.
- Localized overrides live in `voxvera/locales/{lang}/docs/`.
- **Crucial**: After any change to locales or templates, you MUST run `voxvera build-docs` to synchronize the output in `docs/{en,es,de}/`.
## Universal Mirroring
VoxVera propagates through its own flyers.
- Every `voxvera build` and `voxvera build-site` generates `voxvera-portable.zip`.
- If you modify the core source code, ensure the `bundle_portable` function in `voxvera/cli.py` still correctly captures all necessary directories (especially `vendor/`, `locales/`, and `resources/`).
## Verification Checklist
Before finishing a task, ensure you have:
1. Run unit tests: `pytest tests/test_cli.py`.
2. Verified the localization: `voxvera --lang {lang} check`.
3. Rebuilt the documentation: `voxvera build-docs`.
4. Synchronized the public site: `voxvera build-site`.
5. Verified the portable bundle exists: `ls -l voxvera/host/*/download/voxvera-portable.zip` and `ls -l site/download/voxvera-portable.zip`.
---
Follow these rules to ensure VoxVera remains a robust, viral, and decentralized tool for truth.
-47
View File
@@ -1,47 +0,0 @@
# Contributing to VoxVera
Thank you for your interest in contributing to VoxVera! This project aims to be a global, censorship-resistant tool, and your help—especially with translations—is vital.
## Adding a New Language
VoxVera uses a centralized token system for the CLI and Web components, and a template-based system for Documentation. To add a new language (e.g., French/`fr`), follow this checklist:
### 1. The Token File
Create a new JSON file in `voxvera/locales/{lang_code}.json`.
- Use `en.json` as your master template.
- **`meta`**: Include the native language name and a flag emoji.
- **`cli`**: Translate all strings used in the terminal interface.
- **`web`**: Translate strings used on the generated landing pages and flyers.
- **`landing`**: Translate the specific content for the official VoxVera website.
- **Formatting**: You can use Markdown-style strike-throughs (`~~redacted text~~`) in any of these strings; they will be automatically converted to the stylized "redacted" effect on the flyers.
### 2. The Landing Page
The main landing page is generated from the shared template and locale files.
- Add your language in `voxvera/locales/{lang_code}.json`.
- Do **not** edit `site/index.html` directly; it is generated output.
- Run `voxvera build-site` to refresh the public assets and inject your new locale into the generated HTML.
### 3. Documentation
VoxVera uses the **Doc-Sync Engine** to keep manuals in sync.
- Create localized Markdown files in `voxvera/locales/{lang_code}/docs/`.
- Use the templates in `docs/templates/` as your guide.
- You can use `cli.token_name` to reference terminal commands automatically.
### 4. Build and Verify
Run the following commands to verify your changes:
- `voxvera --lang {lang_code} check` (Verify CLI translation)
- `voxvera build-docs` (Generate localized manuals)
- `voxvera build-site` (Synchronize the public website and generate the latest portable bundle)
- Open the generated `site/index.html` in a browser and test the language switcher.
## Code Contributions
- **Dependencies**: if you add a new Python library to `requirements.txt`, you MUST run `voxvera vendorize` to include it in the portable distribution.
- **Layout Integrity**: VoxVera uses visual width validation. If you add new UI elements, ensure they respect the physical boundaries of an 8.5"x11" flyer.
- **Tests**: Ensure all tests pass: `pytest tests/`. Run the integrity suite specifically when modifying locales: `pytest tests/test_integrity.py`.
- **Generated artifacts**: Treat `voxvera/resources/bin/` as local build output, not source files. Release binaries belong in GitHub Releases, not hand-edited repo state.
- **Style**: Follow the existing coding style (PEP 8 for Python).
- **Documentation**: If adding a new feature, update the master templates in `docs/templates/` and run `voxvera build-docs`.
---
Together, we can ensure that truth remains accessible to everyone, everywhere.
-19
View File
@@ -1,19 +0,0 @@
# Docker Usage
Experimental: the container path is not yet a production-grade hidden-service deployment target. Linux with `systemd --user` remains the supported persistent-host environment.
A prebuilt image containing Tor, OnionShare and the `voxvera` CLI is published to
`ghcr.io/voxvera/voxvera`.
```bash
# pull the image
docker pull ghcr.io/voxvera/voxvera:latest
# run the experimental container with flyers stored in ./flyers
mkdir -p flyers
docker run -it --rm -v "$(pwd)/flyers:/flyers" ghcr.io/voxvera/voxvera
```
The container stores runtime state under `/flyers`, seeds a default `config.json` if needed, and retries `voxvera start-all` periodically after the initial `quickstart`.
Use this path for testing only until the container runtime and background recovery behavior are validated end-to-end.
-14
View File
@@ -1,14 +0,0 @@
# Flyer Templates
Pre-built flyer templates live in the `templates/` directory. Use the CLI to copy one with:
```bash
voxvera init --template <name>
```
This will create a new folder under `dist/` named `<name>-<YYYYMMDD>` containing the template files.
Available templates:
- **blank** – minimal placeholder files, also used when extracting fields from a PDF.
- **voxvera** – example flyer showcasing the VoxVera project.
-75
View File
@@ -1,75 +0,0 @@
# Troubleshooting
This page collects common issues encountered when hosting or accessing flyers.
## Tor connectivity
- Ensure Tor is allowed through your firewall. On systems using `ufw` you may need to run `sudo ufw allow tor`.
- Some networks block Tor entirely. If you cannot reach onion services, try connecting over a different network or use a Tor bridge.
## Supported deployment target
- The supported persistent-host setup is Linux with `systemd --user`.
- Windows, macOS, Docker, Flatpak, AppImage, Homebrew, and Chocolatey are currently experimental and may not recover hosting automatically after reboot or network interruptions.
## Tor port detection
`voxvera serve` auto-detects Tor by probing common ports (9050/9150 for SOCKS, 9051/9151 for control). If detection fails -- for example when Tor runs on non-standard ports -- you can override with environment variables:
```bash
TOR_SOCKS_PORT=19050 TOR_CONTROL_PORT=19051 voxvera serve
```
If no running Tor is found, the defaults (9050/9051) are used and OnionShare will attempt to connect on those ports.
## Firewall rules
- If `voxvera serve` fails to start OnionShare, verify that outbound connections on ports 9001 and 80 are permitted.
- Corporate or university firewalls can block the hidden service ports required by Tor.
## SELinux
- On SELinux-enabled distributions you may see `permission denied` errors when OnionShare writes to the `host` directory.
- Run `sudo chcon -Rt svirt_sandbox_file_t host` or disable SELinux enforcement for the folder.
## OnionShare crashes
If `voxvera serve` prints "OnionShare exited unexpectedly", check the log file
`host/<folder_name>/onionshare.log` for details. Common causes:
- Tor is not running (`sudo systemctl start tor`)
- A port conflict with another service
- Missing `onionshare-cli` (run `voxvera check`)
## Onion URL changed unexpectedly
The onion URL is tied to the Ed25519 keypair stored in
`host/<folder_name>/.onionshare-session`. If this file is deleted, a new
keypair (and URL) will be generated on the next `voxvera serve`. The
`voxvera import` command preserves this file automatically, but manual
deletion of the `host/` directory will destroy it.
## Hosting does not return after reboot or network loss
On Linux, install or verify the recovery timer:
```bash
voxvera autostart
systemctl --user status voxvera-start.timer
systemctl --user status voxvera-start.service
```
The supported recovery path is the recurring `systemd --user` timer, which reruns `voxvera start-all` every few minutes.
## QR codes not generated
If `voxvera build` reports "No URLs configured yet", this is expected before the first `voxvera serve`. QR codes for tear-off links are generated automatically once the .onion address is known. QR codes for the content link are generated if you provided a URL during `voxvera init`.
## Electron GUI
If `npm start` fails with `spawn voxvera ENOENT`, the `voxvera` command is not in your `PATH`. Install it with `pipx install git+https://github.com/PR0M3TH3AN/VoxVera.git` or run `./install.sh` from the repository.
## Missing dependencies
Run `voxvera check` to verify your setup. The command checks for required
Python packages (`qrcode`, `Pillow`, `jsmin`, `htmlmin`, `pypdf`) and
external tools (`onionshare-cli`), then prints a summary of anything
missing. To install everything:
```bash
# Recommended: use the install script (handles Tor + OnionShare too)
curl -fsSL https://raw.githubusercontent.com/PR0M3TH3AN/VoxVera/main/install.sh | bash
# Or reinstall just the Python package
pipx install --force 'voxvera@git+https://github.com/PR0M3TH3AN/VoxVera.git@main'
```
-130
View File
@@ -1,130 +0,0 @@
# Maelezo ya Matumizi
Mwongozo huu unashughulikia taratibu za kawaida za CLI. Angalia `docs/docker.md` kwa maelekezo ya Docker na `docs/templates.md` kwa violezo vya vipeperushi vinavyopatikana.
## Mahitaji ya Awali
VoxVera imeundwa kuwa rahisi kubebeka na inahitaji vitegemezi vichache vya mfumo.
### 1. Programu Zinazojitegemea (Zinazopendekezwa)
Unaweza kupakua programu zinazojitegemea na zisizo na vitegemezi kwa mfumo wako wa uendeshaji:
- **Linux:** `voxvera-linux`
- **Windows:** `voxvera-windows.exe`
- **macOS:** `voxvera-macos`
Programu hizi zinajumuisha kila kitu kinachohitajika ili kuendesha VoxVera (isipokuwa `onionshare-cli`).
### 2. Kisakinishi cha Mstari Mmoja
Vinginevyo, sakinisha kupitia hati yetu ya kiotomatiki:
```bash
curl -fsSL https://raw.githubusercontent.com/PR0M3TH3AN/VoxVera/main/install.sh | bash
```
### 3. Usakinishaji wa Mwongozo wa Python
Ikiwa unapendelea kuendesha kutoka kwenye chanzo:
```bash
pipx install 'voxvera@git+https://github.com/PR0M3TH3AN/VoxVera.git@main'
sudo apt install tor onionshare-cli # Debian/Ubuntu
```
## Hatua kwa Hatua
1. **Anzisha:** Endesha `voxvera init` na ufuate maelekezo. Utaulizwa kuchagua lugha yako kwanza.
2. **Jenga:** Tengeneza rasilimali za kipeperushi. Kila ujenzi huunda kiotomatiki faili ya `voxvera-portable.zip` kwenye folda ya kipeperushi, ikiruhusu wengine kupakua zana nzima moja kwa moja kutoka kwenye kipeperushi chako.
```bash
voxvera build
```
3. **Tumia:** Chapisha kipeperushi kupitia Tor:
```bash
voxvera serve
```
Hii hutambua kiotomatiki mfumo wako wa Tor, inaanzisha OnionShare, na kuandika anwani ya .onion iliyozalishwa kwenye viungo vya kipeperushi.
## Usaidizi wa Lugha
VoxVera imetafsiriwa kikamilifu. Unaweza kubadilisha upendeleo wako wa lugha kwa kudumu ukitumia kiteuzi shirikishi au njia ya mkato ya moja kwa moja:
- **Kiteuzi Shirikishi:** `voxvera lang`
- **Njia ya Mkato ya Moja kwa Moja:** `voxvera --lang sw` (inaweka upendeleo kuwa Kiswahili)
### Lugha Zinazotumika:
- **Kiingereza:** `en`
- **Kihispania:** `es` (jina mbadala: `--idioma`)
- **Kijerumani:** `de` (jina mbadala: `--sprache`)
- **Kiswahili:** `sw`
Unaweza pia kulazimisha lugha maalum kwa amri moja bila kubadilisha upendeleo wako wa kudumu:
- **Kiingereza:** `voxvera --lang en check`
- **Kiswahili:** `voxvera --lang sw check`
Vipeperushi vilivyozalishwa hutambua kiotomatiki lugha ya kivinjari cha mgeni na kubadilisha maandishi ya UI ipasavyo.
## Usimamizi wa Seva
Simamia vipeperushi vingi na utambulisho wao wa Tor kutoka kwenye menyu moja shirikishi:
```bash
voxvera manage
```
Vipengele:
- **--- Unda Tovuti/Kipeperushi Kipya ---**: Anza mchakato mzima wa usanidi.
- **--- Anzisha Tovuti Zote ---**: Anzisha au simamisha vipeperushi vyote kwenye kundi lako kwa mpigo mmoja.
- **Hali ya Wakati Halisi**: Angalia URL za .onion zinazofanya kazi na viashiria vya maendeleo ya kuanza kwa Tor.
- **Udhibiti wa Kibinafsi**: Hamisha kama Zip tovuti maalum kwenye ZIP au uzifute.
## Uakisi wa Ulimwengu (Usambazaji wa Virusi)
Ili kuhakikisha VoxVera inaendelea kupatikana hata kama hifadhi kuu zitadhibitiwa, kila kipeperushi hufanya kazi kama kioo cha zana hiyo.
Unapohifadhi kipeperushi, kitufe cha **"Pakua Zana na Chanzo"** kwenye ukurasa wa kutua hutoa `voxvera-portable.zip` iliyo na:
- Chanzo kamili na lugha zote zinazotumika.
- Vitegemezi vyote vya Python (vilivyowekwa mapema).
- Programu za Tor za mifumo mbalimbali.
Hii inaruhusu kila mtu anayekagua kipeperushi chako kuwa msambazaji mpya wa zana ya VoxVera.
## Hamisha na Hifadhi Nakala
Hifadhi nakala za utambulisho wako wa kipekee wa Tor (ili URL yako ya .onion isibadilike kamwe) au hamisha vipeperushi vyako kwenye mashine nyingine.
- **Hamisha tovuti moja**: `voxvera export <jina_la_folda>`
- **Hamisha tovuti zote**: `voxvera export-all`
**Mahali pa kuhifadhi:** Hamisho zote zinahifadhiwa kwenye `~/voxvera-exports/` kwenye mifumo yote.
## Ingiza na Rejesha
Rejesha usanidi wako wote kwenye mashine mpya kwa kuhamisha faili zako za ZIP kwenda `~/voxvera-exports/` na uendeshe:
```bash
voxvera import-multiple
```
## Uwezo wa Kubebeka na Matumizi ya Nje ya Mtandao
Ikiwa unahitaji kuendesha VoxVera kwenye mashine isiyo na ufikiaji wa mtandao, unaweza kupakua vitegemezi kwanza:
```bash
voxvera vendorize
```
Hii inapakua maktaba zote za Python zinazohitajika kwenye `voxvera/vendor/`. Kisha zana itatoa kipaumbele kwa faili hizi za kienyeji, ikiruhusu iendeshe bila `pip install`.
## Ingiza kwa Wingi (JSON)
Ili kuzalisha vipeperushi kwa wingi kutoka kwa faili nyingi za usanidi wa JSON, ziweke kwenye folda ya `imports/` na uendeshe:
```bash
voxvera batch-import
```
## Jinsi URL Zinavyofanya Kazi
Kila kipeperushi kina URL mbili tofauti:
- **Kiungo cha kutolewa** (kinachozalishwa kiotomatiki): Anwani ya .onion ambapo kipeperushi kinahifadhiwa.
- **Kiungo cha maudhui** (kilichosanidiwa na mtumiaji): URL ya nje inayoelekeza kwenye tovuti, video, au upakuaji.
Huna haja ya kuingiza anwani ya .onion kwa mikono; VoxVera inashughulikia hili kiotomatiki wakati wa awamu ya `serve`.
-42
View File
@@ -1,42 +0,0 @@
# AI Agent Instructions for VoxVera
This guide is for AI agents (like Gemini, Claude, or GPT) contributing to the VoxVera project. Follow these protocols to maintain the architectural integrity and multi-language support.
## Core Mandates
1. **Security-First**: VoxVera is a Tor-based tool. Never suggest features that leak IP addresses or use non-Tor external resources (CDNs, etc.).
2. **Local-First**: All assets (fonts, dependencies, binaries) must be self-contained within the `voxvera/` package to support the Universal Mirroring model.
3. **Tokenized UI**: Never hardcode user-facing strings. Always add them to `voxvera/locales/en.json` and use the `t('cli.token')` helper.
4. **Markdown Redaction**: Use `~~text~~` in locale JSONs for strike-through effects. Both the build system and the JS engine handle the conversion to `<span class="redacted">` automatically.
5. **Visual Width Testing**: When modifying UI or adding languages, verify that long or complex strings (e.g., Hindi ligatures or CJK characters) do not exceed the visual unit limits defined in the CLI.
## Localization Protocol
When adding a new language or updating an existing one:
- **CLI/Flyers**: Update `voxvera/locales/{lang}.json`. Include `meta`, `cli`, `web`, and `landing` categories.
- **Landing Page**:
- Directly update the `const locales` object in `site/index.html`.
- **Crucial**: Run `voxvera build-site` to generate the latest portable bundle and refresh the pre-rendered HTML.
- **Documentation**:
- Master templates live in `docs/templates/`.
- Localized overrides live in `voxvera/locales/{lang}/docs/`.
- **Crucial**: After any change to locales or templates, you MUST run `voxvera build-docs` to synchronize the output in `docs/{en,es,de}/`.
## Universal Mirroring
VoxVera propagates through its own flyers.
- Every `voxvera build` and `voxvera build-site` generates `voxvera-portable.zip`.
- If you modify the core source code, ensure the `bundle_portable` function in `voxvera/cli.py` still correctly captures all necessary directories (especially `vendor/`, `locales/`, and `resources/`).
## Verification Checklist
Before finishing a task, ensure you have:
1. Run unit tests: `pytest tests/test_cli.py`.
2. Verified the localization: `voxvera --lang {lang} check`.
3. Rebuilt the documentation: `voxvera build-docs`.
4. Synchronized the public site: `voxvera build-site`.
5. Verified the portable bundle exists: `ls -l voxvera/host/*/download/voxvera-portable.zip` and `ls -l site/download/voxvera-portable.zip`.
---
Follow these rules to ensure VoxVera remains a robust, viral, and decentralized tool for truth.
-47
View File
@@ -1,47 +0,0 @@
# Contributing to VoxVera
Thank you for your interest in contributing to VoxVera! This project aims to be a global, censorship-resistant tool, and your help—especially with translations—is vital.
## Adding a New Language
VoxVera uses a centralized token system for the CLI and Web components, and a template-based system for Documentation. To add a new language (e.g., French/`fr`), follow this checklist:
### 1. The Token File
Create a new JSON file in `voxvera/locales/{lang_code}.json`.
- Use `en.json` as your master template.
- **`meta`**: Include the native language name and a flag emoji.
- **`cli`**: Translate all strings used in the terminal interface.
- **`web`**: Translate strings used on the generated landing pages and flyers.
- **`landing`**: Translate the specific content for the official VoxVera website.
- **Formatting**: You can use Markdown-style strike-throughs (`~~redacted text~~`) in any of these strings; they will be automatically converted to the stylized "redacted" effect on the flyers.
### 2. The Landing Page
The main landing page is generated from the shared template and locale files.
- Add your language in `voxvera/locales/{lang_code}.json`.
- Do **not** edit `site/index.html` directly; it is generated output.
- Run `voxvera build-site` to refresh the public assets and inject your new locale into the generated HTML.
### 3. Documentation
VoxVera uses the **Doc-Sync Engine** to keep manuals in sync.
- Create localized Markdown files in `voxvera/locales/{lang_code}/docs/`.
- Use the templates in `docs/templates/` as your guide.
- You can use `{{t('cli.token_name')}}` to reference terminal commands automatically.
### 4. Build and Verify
Run the following commands to verify your changes:
- `voxvera --lang {lang_code} check` (Verify CLI translation)
- `voxvera build-docs` (Generate localized manuals)
- `voxvera build-site` (Synchronize the public website and generate the latest portable bundle)
- Open the generated `site/index.html` in a browser and test the language switcher.
## Code Contributions
- **Dependencies**: if you add a new Python library to `requirements.txt`, you MUST run `voxvera vendorize` to include it in the portable distribution.
- **Layout Integrity**: VoxVera uses visual width validation. If you add new UI elements, ensure they respect the physical boundaries of an 8.5"x11" flyer.
- **Tests**: Ensure all tests pass: `pytest tests/`. Run the integrity suite specifically when modifying locales: `pytest tests/test_integrity.py`.
- **Generated artifacts**: Treat `voxvera/resources/bin/` as local build output, not source files. Release binaries belong in GitHub Releases, not hand-edited repo state.
- **Style**: Follow the existing coding style (PEP 8 for Python).
- **Documentation**: If adding a new feature, update the master templates in `docs/templates/` and run `voxvera build-docs`.
---
Together, we can ensure that truth remains accessible to everyone, everywhere.
-19
View File
@@ -1,19 +0,0 @@
# Docker Usage
Experimental: the container path is not yet a production-grade hidden-service deployment target. Linux with `systemd --user` remains the supported persistent-host environment.
A prebuilt image containing Tor, OnionShare and the `voxvera` CLI is published to
`ghcr.io/voxvera/voxvera`.
```bash
# pull the image
docker pull ghcr.io/voxvera/voxvera:latest
# run the experimental container with flyers stored in ./flyers
mkdir -p flyers
docker run -it --rm -v "$(pwd)/flyers:/flyers" ghcr.io/voxvera/voxvera
```
The container stores runtime state under `/flyers`, seeds a default `config.json` if needed, and retries `voxvera start-all` periodically after the initial `quickstart`.
Use this path for testing only until the container runtime and background recovery behavior are validated end-to-end.
Loaded 100 of 3046 files, more files were not shown because too many files have changed in this diff. Show more