Skip to content

Releases: veilnetwork/xVeil

xVeil v0.13.41

Choose a tag to compare

@github-actions github-actions released this 03 Sep 23:06

[0.13.41] — 2026-09-04

Fixed

  • Refusing the bundled seeds left the node nowhere to look. Two questions
    shared one answer: builtin_seed_policy says whether the node may dial the
    compiled-in seed list, and the meeting-point checkboxes say where it may look
    for a first peer. The composition took the seed answer for both, so a refusal
    wrote meeting_points = "off" — no DHT, no Nostr, no LAN. That cost little
    while a seed list existed; it ships empty on every network now, so the refusal
    removed the only way left to find anyone while removing nothing that existed.
    Measured on a user's machine: the app's node up with zero peers, zero sessions
    and zero outbound connections, while a peerless node beside it met all three
    seeds through Nostr in thirty seconds. The opt-out stays and still forbids the
    compiled-in list; only the coupling goes.
  • The switch said the shared seeds were on while the node had refused them.
    An open space that will not answer resolves to false for the node — fail
    closed, so an unreadable setting cannot undo a refusal — while the control's
    read returned "no answer" and left the switch on its boot default. The person
    had a control saying the seeds were in use, a node told the opposite, and no
    warning, because the re-offer card keys off that same value. Both reads answer
    the same way now.
  • Quitting crashed the app, and Error Reporting held it for 150 seconds.
    windowManager.destroy() is PostQuitMessage(0) on Windows, so the window
    outlives the message loop, OnDestroy never runs, and the controller dies in
    ~FlutterWindow — whose DestroyWindow dispatches messages back into a
    half-gone controller. unique_ptr does not clear its pointer before running
    the deleter, so the guard in MessageHandler passed. The access violation
    escaped a kernel callback, which Windows turns into
    STATUS_FATAL_USER_CALLBACK_EXCEPTION, and Error Reporting then kept the
    process alive for two and a half minutes with the window and tray icon
    already gone. Now 2 seconds, no dump, no event.
  • Close-to-tray answered with its default on the launch that mattered.
    Riverpod builds a notifier on its first read and build() is synchronous, and
    the only read that decides anything — the window-close handler — is on a cold
    start also the first. A user who turned close-to-tray off had it honoured
    until they restarted.
  • A dialog opened under one identity applied its answer to another. In
    all-online mode a switch unmounts nothing, so mounted stays true while
    ref.read already returns the new identity's services. Clearing a chat wrote
    its tombstones into the wrong identity and queued a frame for the old peer in
    the new outbox; the file policy was replaced wholesale; one Nostr toggle could
    store a meeting-point set neither identity asked for. Guarded as a rule over
    the file, not a list of known helpers.
  • An SSH secret and a picked folder crossed to the wrong identity. The
    managed-node editor showed one identity's SSH password and private key under
    another and saved them there; a folder chosen from one identity's picker
    became a sync pair of another, whose scheduler then uploaded those files.
  • A notification for one identity was posted and attributed to another.
    Re-subscribing is what an identity switch does in the notification binder, and
    it left the generation alone. An alert posted after the switch is now taken
    back down by its exact id.
  • A captured device or cloud service kept working for the identity it left.
    prepareDeviceAdoption had no dispose fence at all and its admission lasts
    seven days across restarts; CloudCapabilityService.close knew nothing about
    the transient endpoints a listing or download holds, so a stale download wrote
    verified pieces and a manifest into a storage the app had stopped showing.
  • Auto-signing followed the user from one identity to the next. The policy
    provider never watched the active identity, so an auto chosen by one made
    the next produce non-repudiable proof of authorship its owner never agreed to.
  • A delete during the directory restore left the share serving. The public
    directory service set _started before its first await, so a delete arriving
    in that window saw an empty status, skipped the withdraw and dropped the
    folder — and the late restore republished the pointer. The bearer share lives
    seven days.
  • A captured nullable was passed where a non-nullable was wanted. Accepted
    by the pinned Flutter, rejected by current stable.
  • A Windows or iOS stand could never have a control plane. builder.py did
    not pass the debug-hook define on either, so those builds had no hook and no
    way to gain one — which reads from outside as a node that never bootstrapped.

Changed

  • veil 0.11.19.

xVeil v0.13.40

Choose a tag to compare

@github-actions github-actions released this 03 Sep 11:54
6a4432d

[0.13.40] — 2026-09-03

Fixed

  • A native build on an ARM64 Windows machine now works without being told a
    secret. BoringSSL has no assembly route for Windows on ARM64, and the crate
    that knows the answer cannot reach it on a native build; the release
    workflow has handed over the toolchain file that says so since v0.13.11, but
    nothing handed it to a person running the builder by hand. The build died
    deep inside cmake with a message naming no cause. The builder sets it itself
    on an ARM64 Windows host, and refuses loudly if the file is missing.

Changed

  • veil 0.11.18: two Windows CI test steps were running zero tests, and audio
    playout now reports whether it actually started.

xVeil v0.13.39

Choose a tag to compare

@github-actions github-actions released this 03 Sep 09:38
48069e9

[0.13.39] — 2026-09-03

Fixed

  • Revoking a shared folder now stays revoked. The withdrawal was recorded by
    removing the share and saving the list afterwards, so a save that failed —
    a full container is enough — left the folder on disk with nothing saying it
    had been withdrawn, and the next launch served the link again for the rest
    of its seven days. The runtime state was already gone by then, so there was
    nothing left to retry. The withdrawal is now written down first, and a
    launch reads that record before it hosts anything. File shares have worked
    this way all along; folders did not.

xVeil v0.13.38

Choose a tag to compare

@github-actions github-actions released this 03 Sep 09:18
9ac0ad7

[0.13.38] — 2026-09-03

Fixed

  • One bad mailbox relay can no longer destroy a message's honest copies. A
    message is filed under an id that names the message, not its contents, so a
    relay could answer first with a genuine id and a substituted body. Every
    layer then treated the id as the message: the drain kept one body per id, a
    body that would not open condemned the id, and the app told every relay to
    delete it — including the ones holding the real thing, and including the
    real thing itself if it arrived later. Bodies are now told apart by their
    contents as well as their id, every one filed under an id is tried, and an
    id is given up only when nothing filed under it opened. Replies are also
    accepted only from a relay this drain asked and only when the daemon
    verified who sent it; one relay's malformed answer no longer discards what
    the others sent.

  • The rollback anchor now follows the container instead of naming the moment
    it was opened. Written once at boot, it protected only the boot: the device
    ran past that commit, and restoring any later snapshot still read as a clean
    continuation while the send positions that snapshot did not carry were
    derived a second time. It advances with each durable reservation, which is
    the point where new ciphertext becomes publishable.

    Three companions to that. The record now says WHICH container it is about,
    so a fresh container after a wipe is a different container rather than one
    that went backwards — it used to burn keys and raise an alarm at every
    launch. A container whose history is not ours is no longer quietly adopted
    at the next launch, which destroyed the only evidence it was ever a
    different one. And an anchor write that does not reach the disk says so
    instead of reporting success.

Changed

  • hidden-volume 2.2.2: the Argon2 working matrix — the password's expansion,
    64 MiB and up — is wiped when the derivation returns. It was freed as it
    stood while the security notes said otherwise.

xVeil v0.13.37

Choose a tag to compare

@github-actions github-actions released this 03 Sep 06:58
5c362b5

[0.13.37] — 2026-09-03

Changed

  • veil 0.11.17: repairs a test that stopped compiling in 0.11.12 and was only
    caught by the project's own automated checks, not by anything run before the
    tag. No behaviour change for the app.

xVeil v0.13.36

Choose a tag to compare

@github-actions github-actions released this 03 Sep 03:47
6927c92

[0.13.36] — 2026-09-03

Changed

  • veil 0.11.16: a node now limits how much route-discovery traffic it will
    relay in total, not just how much each peer may ask it to. Forwarding one
    request costs a message to every peer the node is connected to, and the old
    limit was per sender — so enough senders, each behaving, still added up to
    the node flooding its own neighbours.

xVeil v0.13.35

Choose a tag to compare

@github-actions github-actions released this 03 Sep 03:32
a222b45

[0.13.35] — 2026-09-03

Changed

  • veil 0.11.15: a node with value persistence enabled no longer pauses
    everything else it is doing while it writes its periodic snapshot. The
    snapshot was built on the same thread that runs the rest of the node, and on
    a full store that is a large copy taken every two minutes. Affects operators
    who run a seed with that setting; the app never enables it.

xVeil v0.13.34

Choose a tag to compare

@github-actions github-actions released this 03 Sep 03:03
20c3010

[0.13.34] — 2026-09-03

Fixed

  • Downloading a file from a shared folder no longer holds all of it in memory.
    Each piece is written out as its hash checks, so what the app holds at once
    is one piece rather than the whole file — which, on that path, is whatever
    size the sharer says it is. Tapping Download on a large or hostile entry
    could take the app out on a phone before a single byte was persisted. The
    two sibling download paths had been streaming for a while; this was the one
    left assembling.

Changed

  • veil 0.11.14: a gossiped contact can no longer move where this node dials a
    peer it was told about another way. The peer table is searched by node id to
    answer "do we know this one", and that search returned whichever row held
    the id — so a peer on the exchange path could rewrite the address of a peer
    from the operator's own configuration, and the rewrite survived a restart. A
    rumour may now refresh only the rows the exchange itself created.

xVeil v0.13.33

Choose a tag to compare

@github-actions github-actions released this 03 Sep 02:36
87ce58f

[0.13.33] — 2026-09-03

Changed

  • veil 0.11.13: two ways a stranger could aim this node's routing are closed.
    A proof-of-work challenge and its answer are relayed frames, and every fault
    they could carry was charged against whoever delivered them — five of those
    ban a peer, so a stranger could choose which of your relays your own node
    would cut off. And an announcement claiming to be one hop from a node was
    trusted over a route this device had confirmed itself, which let any peer
    with a session pull that node's traffic through itself. The payload stays
    sealed either way; what was at stake is who can see whom you talk to, and
    who can quietly drop it.

xVeil v0.13.32

Choose a tag to compare

@github-actions github-actions released this 03 Sep 02:03
5d71c57

[0.13.32] — 2026-09-03

Fixed

  • A container put back to an older copy no longer re-uses a key that has
    already been on the wire. Every conversation's send-position reservation
    lives inside the container, beside the ratchet state it guards, so restoring
    an older copy restored both: the next send re-derived a key and nonce this
    device had already published, and two plaintexts under one key is not a lost
    message. Nothing outside the container remembered where it had got to.

    The app now records the container's commit counter outside it, on the
    acknowledged space only, and judges the container against that record at
    every unlock. A container that is behind burns every send position the
    missing commits could have reserved before a single message goes out; one
    whose history is not the one this device wrote is reported as such. The
    bound is deliberately generous — burning too many positions costs a peer
    some skipped keys, burning too few cannot be taken back.

    What this stops, and what it does not. It stops a container that was
    restored from a backup, synced backwards, or copied back by hand, which is
    how this actually happens. It does not stop somebody who puts the whole disk
    back at once, because that returns the record too. Going further needs a
    counter that cannot be rewritten, which this device does not have.

    Decoy identities are never anchored. An anchor for a hidden space announces
    that the space exists, so only the acknowledged space keeps one, and the
    identities opened through the multi-space handle cannot answer the question
    at all rather than being trusted not to.