crates/veilvoice-gui/src/avnotice.rs
veilvoice-gui · 298 lines · read the source here · or on GitHub
Noticing when antivirus software has closed VeilVoice, and saying so kindly.
The problem this is for
A newly released application that few people have run yet has, in the language of Windows antivirus, "low reputation". A low-reputation program that reads the microphone and writes encrypted files is exactly the shape a heuristic scanner is tuned to be suspicious of, and some of them will close it -- a false positive, but indistinguishable from a crash to the person sitting in front of it.
VeilVoice is offline, reproducible and signed, so a user can establish that it is what it says it is. But that is cold comfort if the window just vanished and they have no idea why.
What this does, and what it does not
It does not try to evade anything, hide from anything, or stop an antivirus doing its job. That would be both wrong and futile. It does the opposite: it helps the user understand what happened so they can make their own decision.
On a clean exit VeilVoice removes a small marker file. So on the next launch, a marker still present means the previous run ended without getting to its own shutdown -- and if VeilVoice had crashed, it would have written a crash report on the way down (see crate::crashlog). A marker present with no crash report is the signature of the process being terminated from outside.
When that has happened and a known antivirus product is on the machine, the next launch shows a plain notice: which product was found, that a low-reputation app is sometimes stopped by mistake, that they would normally have seen an alert from that product, and that adding an exclusion is worth doing only if they are actually seeing the problem. Nothing is changed on the system and nothing is suppressed; it is one paragraph of context.
Why the decision is a pure function
Whether to show the notice depends on three facts -- was the last exit unclean, was there a crash report, is an antivirus present -- and getting that logic wrong means either crying wolf or staying silent when it would have helped. diagnose takes those three as arguments so every branch is tested from any machine, and the platform probing that gathers them is kept separate and thin.
WHAT THIS FILE CONTAINS
298 lines defining 8 functions (7 public), 3 types and 1 constant. Everything below is read out of the source, so it cannot disagree with the code.
The types it owns.
struct Productline 51 · An antivirus product recognised on this machine.struct Noticeline 58 · The notice to put in front of the user, once.struct Sessionline 123 · A session's clean-shutdown marker.
What happens when it runs. These are the ways in: public, and nothing else in this file calls them, so they are what an outside caller reaches first.
Notice::messageline 69 · The message, assembled from the products found.diagnoseline 99 · Decide whether to show the notice.Session::beginline 132 · Begin a session: note whether the last one ended cleanly, then claim the marker for this one.
reachesmarker_pathSession::prior_was_uncleanline 151 · Whether the previous session ended without a clean shutdown.Session::endline 160 · End the session cleanly, removing the marker.detectline 174 · Look for antivirus products on this machine.
reachesdetect_windows
WHAT CALLS WHAT
The functions this file defines, and the calls between them. An edge means the callee's name appears, called, inside the caller's body. This is a syntactic reading, not a type-resolved one.
The same graph as Mermaid source
%%{init: {"theme":"base","themeVariables":{"background":"#1a1b26","primaryColor":"#1f2335","primaryTextColor":"#c0caf5","primaryBorderColor":"#7aa2f7","secondaryColor":"#16161e","tertiaryColor":"#16161e","lineColor":"#737aa2","textColor":"#c0caf5","mainBkg":"#1f2335","nodeBorder":"#7aa2f7","clusterBkg":"#16161e","clusterBorder":"#2f3549","fontFamily":"ui-monospace, SFMono-Regular, Consolas, monospace","fontSize":"14px"}}}%%
flowchart TD
n_message(["Notice::message<br/>line 69"])
n_diagnose(["diagnose<br/>line 99"])
n_marker_path["marker_path<br/>line 114"]
n_begin(["Session::begin<br/>line 132"])
n_prior_was_unclean(["Session::prior_was_unclean<br/>line 151"])
n_end(["Session::end<br/>line 160"])
n_detect(["detect<br/>line 174"])
n_detect_windows["detect_windows<br/>line 212"]
n_begin --> n_marker_path
n_detect --> n_detect_windows
click n_message href "https://github.com/tilas01/veilvoice/blob/main/crates/veilvoice-gui/src/avnotice.rs#L69" "open the source"
click n_diagnose href "https://github.com/tilas01/veilvoice/blob/main/crates/veilvoice-gui/src/avnotice.rs#L99" "open the source"
click n_marker_path href "https://github.com/tilas01/veilvoice/blob/main/crates/veilvoice-gui/src/avnotice.rs#L114" "open the source"
click n_begin href "https://github.com/tilas01/veilvoice/blob/main/crates/veilvoice-gui/src/avnotice.rs#L132" "open the source"
click n_prior_was_unclean href "https://github.com/tilas01/veilvoice/blob/main/crates/veilvoice-gui/src/avnotice.rs#L151" "open the source"
click n_end href "https://github.com/tilas01/veilvoice/blob/main/crates/veilvoice-gui/src/avnotice.rs#L160" "open the source"
click n_detect href "https://github.com/tilas01/veilvoice/blob/main/crates/veilvoice-gui/src/avnotice.rs#L174" "open the source"
click n_detect_windows href "https://github.com/tilas01/veilvoice/blob/main/crates/veilvoice-gui/src/avnotice.rs#L212" "open the source"
classDef entry fill:#1f2335,stroke:#7aa2f7,color:#c0caf5
class n_message,n_diagnose,n_begin,n_prior_was_unclean,n_end,n_detect entry
classDef api fill:#1f2335,stroke:#7dcfff,color:#c0caf5
class n_marker_path api
classDef helper fill:#1f2335,stroke:#bb9af7,color:#c0caf5
class n_detect_windows helper
This site loads no third-party script, so it cannot run Mermaid; the diagram above is the same nodes and edges drawn by the generator instead. GitHub renders the source below directly.
ITEMS
| Item | Line | Documentation |
|---|---|---|
Product pub struct | 51 | An antivirus product recognised on this machine. |
Notice pub struct | 58 | The notice to put in front of the user, once. |
Notice::message pub fn | 69 | The message, assembled from the products found. |
diagnose pub fn | 99 | Decide whether to show the notice. |
marker_path pub fn | 114 | The marker whose presence on startup means the last run did not exit cleanly. |
Session pub struct | 123 | A session's clean-shutdown marker. |
Session::begin pub fn | 132 | Begin a session: note whether the last one ended cleanly, then claim the marker for this one. |
Session::prior_was_unclean pub fn | 151 | Whether the previous session ended without a clean shutdown. |
Session::end pub fn | 160 | End the session cleanly, removing the marker. |
detect pub fn | 174 | Look for antivirus products on this machine. |
WINDOWS_PRODUCTS const | 192 | Known products, and a path whose presence is good evidence of them. |
detect_windows fn | 212 |