Skip to content

Releases: pointbreaklab-hub/Webiste

Whispr v1.1.15 — Whispr v1.1.15 — in-app bridges guide

07 May 16:42

Choose a tag to compare

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)

07 May 16:23

Choose a tag to compare

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

  1. Get bridge lines from
    bridges.torproject.org or the
    Tor @GetBridgesBot on Telegram.
  2. Settings → Network → toggle Bridges on.
  3. Paste one bridge per line into the text field.
  4. 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.prepareTorConfig reads those keys directly when
    building torrc and emits UseBridges 1 + one Bridge <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

07 May 14:07

Choose a tag to compare

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:

  1. The race I was guarding against doesn't actually exist in
    chat_provider.dart. openConversation resets _messages to
    [] but is gated by messagesLoading, and _loadMessages does
    an atomic reassignment — there's no path that briefly exposes an
    empty _messages while a conversation is open.

  2. 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

07 May 11:59

Choose a tag to compare

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

07 May 11:27

Choose a tag to compare

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_MIN channel — 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 Whispr text — 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 ignore IMPORTANCE_MIN and 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+ honours IMPORTANCE_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)

07 May 10:44

Choose a tag to compare

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_request back 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:

  1. The pending-request banner captures the SPK from
    contact_request directly, so accept-time addContactManual
    gets it without waiting for a follow-up message.
  2. 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:

  1. A → Share invite link → send to B
  2. B taps link → banner → Add (A is added on B's side with SPK)
  3. A's chat list → "X accepted your invite" banner → Accept
    (B is added on A's side with SPK captured from the
    contact_request envelope)
  4. Either side types a chat message → delivered via Tor or LAN
  5. 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 over sk (~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

07 May 07:13

Choose a tag to compare

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 key
  • ss=<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:

  1. A → Share invite link → send to B
  2. B taps link → banner → Add
  3. A's chat list → pending request from B → Accept
  4. Either side types a chat message → delivered via Tor
  5. 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

07 May 05:57

Choose a tag to compare

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_request arrived 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_accepted ack 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:

  1. contact_request arrival now registers the sender's onion
    in torMsg and stores it in the pending-request record.
  2. acceptPendingRequest sends contact_accepted over both LAN
    and Tor
    , picking whichever transports it has addresses for.
  3. 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:

  1. A shares an invite link with B.
  2. B taps the link → invite banner → Add. (B now has A.)
  3. A's chat list shows pending-request banner from B → Accept. (A now has B.)
  4. 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

07 May 05:31

Choose a tag to compare

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:

  1. Adds A as a contact locally (existing behaviour)
  2. Registers A's onion in the Tor message-routing table
  3. Fires a contact_request over Tor to A's onion
  4. 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

07 May 05:01

Choose a tag to compare

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