Releases: pointbreaklab-hub/Webiste
Whispr v1.1.15 — Whispr v1.1.15 — in-app bridges guide
In-app guide for users in censored regions
The Bridges feature shipped in v1.1.14 needed clearer guidance for
users in countries / on networks where Tor is blocked. This release
replaces the brief Bridges info popup with a full step-by-step guide
inside the app — no need to leave Whispr or visit the website to
figure out how to use it.
What changed
Settings → Network → Bridges → tap the (i) icon now opens a
proper getting-started sheet titled "Using Whispr where Tor is
blocked." It covers:
- When you need bridges (India, Iran, China, UAE, restrictive
Wi-Fi) and how to recognise the symptom - A 3-step setup walkthrough with example bridge format
- Where to get bridges (bridges.torproject.org or the Tor Telegram
bot @GetBridgesBot) - What this release supports (vanilla bridges) and what's coming
(obfs4 / DPI-resistance) - Key clarifications: bridges don't change end-to-end encryption,
they age out and need refreshing, and the same line works across
all Tor-based apps
The sheet is scrollable, so it fits without truncation on small
screens.
No code changes outside the help sheet — the bridges feature itself
behaves identically to v1.1.14.
Verification
- Architecture: arm64-v8a
- Signed: release keystore (CN=Whispr)
SHA-256: cb546b2e5cc138f81976dcae065bbacd1e4131375aafefbaf9bd1e97393d41c5
Whispr v1.1.14 — Whispr v1.1.14 — Tor bridges (vanilla)
New: Tor bridges
Settings → Network → Bridges. When Tor is blocked or filtered on
your network — common in India, Iran, China, restrictive Wi-Fi — you
can now route through unlisted entry points (bridges) instead of
public Tor relays.
How to use
- Get bridge lines from
bridges.torproject.org or the
Tor@GetBridgesBoton Telegram. - Settings → Network → toggle Bridges on.
- Paste one bridge per line into the text field.
- Tap Apply & reconnect.
Tor restarts using the new config and connects through the bridges
instead of trying public relays. Toggling Bridges off restores
default behaviour.
Default is OFF — users who already have working Tor see zero change.
Scope of v1.1.14: vanilla bridges only
This release supports vanilla bridges — unlisted Tor relays that
help against IP-list-based blocking (e.g., ISPs that maintain a
blocklist of known public Tor relay IPs). It works for some Indian
and Iranian carriers.
It does not yet support pluggable transports like obfs4, which
disguise Tor traffic as random TLS to defeat deep packet inspection
(DPI). Networks doing DPI-based Tor fingerprinting (parts of China,
Russia, and increasingly India) need obfs4. That follows in v1.1.15
once IPtProxy integration is tested on a real device — shipping it
without verification would risk breaking Tor for every user, not
just the ones that need bridges.
Implementation notes
- Bridges config is persisted in
SharedPreferences
(bridges_enabled,bridges_lines). MainActivity.prepareTorConfigreads those keys directly when
building torrc and emitsUseBridges 1+ oneBridge <line>
per non-empty entry. Comments (# ...) are ignored.- Apply triggers a Tor restart via the existing
securechat/tor
MethodChannel.
Verification
- Architecture: arm64-v8a
- Signed: release keystore (CN=Whispr)
SHA-256: 8a325268a912c386a54e05324526b287f1533b3fab1a92090bfbb50d16cd661f
Whispr v1.1.13 — Whispr v1.1.13 — revert v1.1.12 chat sync change
Bug fix — revert v1.1.12
Reverts the chat-screen sync change shipped in v1.1.12.
That change tried to defend against a "phantom empty" race I suspected
on slower devices (Galaxy F23). After a thorough audit it turned out
to be the wrong fix:
-
The race I was guarding against doesn't actually exist in
chat_provider.dart.openConversationresets_messagesto
[]but is gated bymessagesLoading, and_loadMessagesdoes
an atomic reassignment — there's no path that briefly exposes an
empty_messageswhile a conversation is open. -
The guard fired on legitimate empty states: deleting the last
message in a conversation, or clearing the chat while staying on
the screen. The provider correctly emitted "no messages", but the
screen kept showing the deleted bubble until you navigated away.
This release restores the v1.1.11 sync behaviour. Delete-last-message
and clear-chat update the screen immediately again.
Galaxy F23 vanishing-message issue
Still open. The v1.1.12 fix didn't address the actual root cause —
needs a logcat | grep -E "Chat|Flutter" from the F23 while
reproducing so we can tell whether it's a Flutter
ValueListenableBuilder quirk on the Mali GPU, a decryption
hash-mismatch on certain payloads, or something else. Investigation
continues; will not ship another fix until the cause is confirmed.
Verification
- Architecture: arm64-v8a
- Signed: release keystore (CN=Whispr)
SHA-256: 631b254d4eef0f08c1041819f3e4cf19972e2023762aed49c901cbe44d6de45d
Whispr v1.1.12 — Whispr v1.1.12 — chat view stability on slower devices
Bug fix
Messages no longer vanish from the chat view on slower devices.
Reported on Galaxy F23 (Helio G80, 4 GB RAM, slow eMMC): the
recipient sees the message in the chat list with the unread badge,
but as soon as they tap to open the chat, the message blanks out.
Same on the sender's side — the bubble appears, then disappears.
S25 Ultra and S21 FE didn't reproduce.
Root cause
The chat screen's UI sync logic in chat_screen.dart merged the
provider's authoritative message list with any in-flight "temp-"
optimistic-send bubbles, then overwrote the on-screen list with
the result. The merge had a brittle assumption: anything that
isn't temp-prefixed must be in the provider snapshot. If the
provider's _messages field was ever transiently empty between
notifications — which happens during the SQL await inside
_loadMessages if a notifyListeners() from a different code
path (battery banner, contact refresh, network state change)
fires mid-flight — the sync computed merged = [] and the screen
went blank for a frame.
Fast devices skipped past that window before the listener fired.
Slower devices hit it.
What changed
_syncFromProvider now treats an empty providerMessages snapshot
as "not loaded yet" when the screen is already showing real
(non-temp) messages, instead of mirroring it into the UI. The real
"clear chat" / "navigate back" / "lock" paths use direct setter
assignments to reset the screen, not this listener — so this
guard doesn't suppress any legitimate clear.
One small change to one file. No DB schema, no wire format, no
other behaviour touched.
Verification
- Architecture: arm64-v8a
- Signed: release keystore (CN=Whispr)
SHA-256: 4afff51fc3afc5483eef7d46d793b908ef62ecb149e818f649f8637cf384def7
Whispr v1.1.11 — Whispr v1.1.11 — quieter background notification
Quieter notifications
The persistent "Whispr" notification can't be removed entirely —
foreground services on Android 8+ are legally required to show one,
and Whispr's serverless model means we run our own Tor + BLE mesh
daemons (no Google Play Services / FCM piggyback like WhatsApp). But
this release pushes it as close to invisible as the platform allows.
What changed
Both the Tor keepalive and BLE mesh foreground services now emit
notifications with the full minimization stack:
IMPORTANCE_MINchannel — drops out of the status bar icon row,
no heads-up, no peek, no sound, no vibration.VISIBILITY_SECRET— hidden from the lock screen entirely.setSilent(true)+setLocalOnly(true)+setOnlyAlertOnce(true)
— explicit "do not alert, do not mirror to wearables".setShowWhen(false)— no timestamp.- Channel-level
enableLights(false),enableVibration(false),
setSound(null, null),setShowBadge(false). - Bare
Whisprtext — no descriptive subtitle (was "Routing
privately · tap to open" / "Encrypted messaging active"). - Neutral lock icon instead of the share-arrow icon.
Result on stock Android: the notification only appears at the
bottom of the notification shade if the user pulls it down and
scrolls. No status-bar icon, no lock-screen entry, no sound or
buzz. Closer to WhatsApp's UX without giving up serverless privacy.
What this can't fix
- Aggressive OEMs (Xiaomi MIUI, Samsung One UI, Honor MagicOS)
sometimes ignoreIMPORTANCE_MINand force-show foreground
notifications. We can't override this without going server-side
(FCM relay = adds infrastructure + a "who's online when"
metadata leak). - Android 14+ in some configurations explicitly requires
foreground services to show a visible notification. Stock
behaviour on 14+ honoursIMPORTANCE_MIN, but vendor variants
may not.
Verification
- Architecture: arm64-v8a
- Signed: release keystore (CN=Whispr)
SHA-256: d36d8c8f3d6878b4f0af87a788fbc679a85758042ab749d9ff3ad166233d67a0
Whispr v1.1.10 — Whispr v1.1.10 — chat delivery fix (round-trip add)
Bug fix
Chat now actually delivers between contacts added via invite link.
v1.1.9 added the signed pre-key (SPK) to the invite link itself so
the invitee could bootstrap X3DH against the inviter. That fixed one
half. This release fixes the other half — the round-trip add.
What was still broken in v1.1.9
When B taps A's invite link:
- B's side: adds A with SPK (from the link). B → A works.
- B then fires a
contact_requestback to A so A gets an "accepted
your invite" banner. But that envelope carried no SPK. - A taps Accept → A adds B without SPK → A's first chat send
fails to encrypt (X3DH has no pre-key to fingerprint against).
End result: messages never left A's device. Email worked because
ECIES is a one-shot encryption that only needs the identity key.
What changed
The sender's SPK + signature now ride along on every outgoing
envelope (LAN and Tor) — contact_request, contact_accepted,
text, voice, presence, all of it. Two follow-ons:
- The pending-request banner captures the SPK from
contact_requestdirectly, so accept-timeaddContactManual
gets it without waiting for a follow-up message. - Self-healing for already-added contacts. If your contact list
has someone with a null SPK column (added via an older build, or
via the round-trip in v1.1.9), the next single envelope from them
populates it. Stale sessions are deactivated on SPK rotation so
the next send re-runs X3DH against the fresh pre-key.
No re-add required. Open the app, send each other a message — even
a contact_request ping is enough — and chat starts working.
End-to-end test (cross-network)
Two devices on different networks, fresh installs:
- A → Share invite link → send to B
- B taps link → banner → Add (A is added on B's side with SPK)
- A's chat list → "X accepted your invite" banner → Accept
(B is added on A's side with SPK captured from the
contact_requestenvelope) - Either side types a chat message → delivered via Tor or LAN
- Reply from the other side → delivered
Email and chat now have parity for cross-network delivery on
both directions of the invite-link flow.
Wire format
Two new optional inner-body fields on every v1/v2/w3 envelope:
sk=<hex>— sender's signed pre-key public key (~64 chars)ss=<hex>— Ed25519 signature oversk(~128 chars)
Older clients that don't read these still parse the envelope normally
(unrecognised fields are ignored). Newer clients receiving an envelope
without sk/ss fall back to whatever SPK they already had stored
for the contact, or refuse to encrypt if none — same behaviour as
before.
Verification
- Architecture: arm64-v8a
- Signed: release keystore (CN=Whispr)
SHA-256: a77ded14db19cdd848c891705e868f71f4c557d8999a9f921f1bb3e33c7e2bca
Whispr v1.1.9 — Chat messages flow cross-network
Bug fix
Chat messages now flow between contacts added via invite link.
The previous bug: email worked across networks (ECIES — one-shot
encryption with just the public key), but chat messages stayed
queued forever. The root cause was missing data in the invite
link: chat uses X3DH for first-message session establishment,
which requires the recipient's signed pre-key (SPK). The QR code
flow already includes spk + sig. Invite links didn't.
Without SPK, X3DH can't initialise → the encrypt step fails →
message never leaves the device. (You can confirm in logs:
[Chat] E2EE encrypt failed (...) — message will stay queued.)
What changed
The invite link now carries two additional query params:
sk=<hex>— signed pre-key public keyss=<hex>— Ed25519 signature over the SPK
The receiver app reads these, persists them with the contact via
the existing _insertContact path, and the X3DH session
establishes normally on the first chat send. Messages now deliver
across LAN, Tor, and BLE mesh — same routes as email.
Also: if the sender's app doesn't have an SPK bundle yet (older
install that never produced one), _buildInviteLink now generates
one before building the URL. Ensures every freshly-shared invite
is fully usable.
End-to-end test (cross-network)
Two devices on different networks:
- A → Share invite link → send to B
- B taps link → banner → Add
- A's chat list → pending request from B → Accept
- Either side types a chat message → delivered via Tor
- Same as before across LAN
Email and chat should now have parity for cross-network delivery.
URL length
The link grew by ~190 characters (sk + ss). Total URL is ~440
chars — still well within SMS multi-part, iMessage, WhatsApp,
email body limits. No real-world impact.
Verification
- Architecture: arm64-v8a
- Signed: release keystore (CN=Whispr)
SHA-256: c824f29fb4864b19467d02c014b2521d926e9a6dbc3124954cc1d10b4d48afec
Whispr v1.1.8 — Messages flow after round-trip
Bug fix
Messages now flow after invite-link round-trip. v1.1.7 closed
the round-trip so both sides got a "X accepted your invite" banner,
but a follow-on bug stopped them from actually messaging each other:
- When B's
contact_requestarrived at A via Tor, A's app stored
the request but discarded the sender's onion address. So A
knew B was a contact but had no Tor delivery channel for them. - When A tapped Accept on the pending banner, the
contact_acceptedack only went over LAN — never over Tor. So B
often never received it. - The onion never got persisted to the ContactProvider, so even if
it briefly worked in-session, restarting the app dropped it.
All three are fixed:
contact_requestarrival now registers the sender's onion
intorMsgand stores it in the pending-request record.acceptPendingRequestsendscontact_acceptedover both LAN
and Tor, picking whichever transports it has addresses for.- The chat-list Accept handler persists the onion via
ContactProvider.saveOnionAddress, so the contact retains a
Tor delivery channel across app restarts.
The same logic also applies to unknown-sender messages that arrive
before contact_request (rare race but possible) — onion is captured
from the first inbound message that carries one.
End-to-end test
Two devices, same or different network:
- A shares an invite link with B.
- B taps the link → invite banner → Add. (B now has A.)
- A's chat list shows pending-request banner from B → Accept. (A now has B.)
- Either side can now message the other — LAN if same Wi-Fi,
Tor otherwise. Survives app restart.
Verification
- Architecture: arm64-v8a
- Signed: release keystore (CN=Whispr)
SHA-256: 1fe49e1441ff5d7a67a6c7a9938ccaf5ff8785b5c42f0aeab84ea1772d8dc166
Whispr v1.1.7 — Round-trip invite notifications
What's new
Round-trip notification on invite-link accept. Until now: A
shares an invite link with B, B adds A — and A had no idea. Now the
sender (A) gets a banner the moment the receiver (B) taps Add:
"B accepted your invite — add them back?"
A taps Accept on that banner → both sides have each other in their
contact lists, mirroring the Nearby-tab contact-request flow.
How it works
The invite link now carries one extra query param: o=<sender's onion>. When B taps Add, the app:
- Adds A as a contact locally (existing behaviour)
- Registers A's onion in the Tor message-routing table
- Fires a
contact_requestover Tor to A's onion - A's app receives it and surfaces the existing pending-request
banner in the chat list
What changes for users
| You're | What you'll see |
|---|---|
| Sharing an invite link | The link now includes your onion. Auto-omitted if Tor isn't ready when you generate the link — falls back to the previous one-way flow. |
| Receiving an invite link | Same banner-driven UX as v1.1.5/6. After tapping Add, the sender gets a notification on their device. |
| The original sender (A) | A new pending-contact-request banner appears when B accepts. Tap Accept to add B back. |
Privacy posture
The onion address was already shared via QR codes in the existing
add-contact flow — invite-link-based sharing now matches that
disclosure level. Onions are public addresses by design (not
secrets); they let someone attempt to reach you, but Whispr
rejects messages from non-contacts. Time-limited invite expiry
(1h–24h) caps the window during which the link can be used.
Verification
- Architecture: arm64-v8a
- Signed: release keystore (CN=Whispr)
SHA-256: 54e4679a3b2a0dfb160f3ec5f90271b42879d60bf7a17a446e967474607d6410
Whispr v1.1.6 — Canonical invite URL
Polish
Invite-link URLs match the website's canonical form. Previously
the app generated https://pointbreaklab.com/whispr/add?k=… (no
trailing slash) — GitHub Pages would 301-redirect every tap to
/whispr/add/?k=…. Working but wasteful. Now the app emits the
canonical slashed form directly — one less hop on every invite
tap, matches the rest of the site (which is configured with
Astro's trailingSlash: 'always').
No functional change for users — purely a small efficiency win
plus consistency with the website's SEO configuration.
Verification
- Architecture: arm64-v8a
- Signed: release keystore (CN=Whispr)
SHA-256: 7931d8aac6a3bcd4aa6bd5e95b1eb2c70e843b3b7832e18a7f432cda65c7220c