Skip to main content

wire/privacy/
answer.rs

1// This Source Code Form is subject to the terms of the Mozilla Public
2// License, v. 2.0. If a copy of the MPL was not distributed with this
3// file, You can obtain one at https://mozilla.org/MPL/2.0/.
4// Copyright (c) 2026 2youg1 and the sprawling contributors
5
6//! The answer to `Query::Privacy` (`crates/wire/spec/Privacy.lean` ยง8-88):
7//! the host, every control with its current value, every original item
8//! that is not written, what this app's history discloses, and the
9//! results the host keeps for the operations pages sent.
10
11use kernel::AxError;
12use serde::{Deserialize, Serialize};
13
14use super::operation::PrivacyOutcome;
15use super::{
16    PrivacyBuildEffect, PrivacyCategory, PrivacyControl, PrivacyEdition, PrivacyEditionFit,
17    PrivacyNotWritten, PrivacyOriginal, PrivacyScope,
18};
19
20/// Everything the privacy page shows, read in one pass on the host that
21/// runs the city.
22#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
23#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
24pub struct PrivacyAnswer {
25    pub host: PrivacyHost,
26    /// Every control, in page order.
27    pub controls: Vec<PrivacyControlEntry>,
28    /// Every original item that is not written, in list order.
29    pub not_written: Vec<PrivacyNotWrittenEntry>,
30    pub history: PrivacyHistory,
31    /// The results the host still keeps, oldest first; a page reads the
32    /// ones whose `idem` it minted.
33    pub outcomes: Vec<PrivacyOutcome>,
34}
35
36/// The machine the controls belong to: the one running this city.
37#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
38#[serde(rename_all = "snake_case")]
39#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
40pub enum PrivacyHost {
41    Windows(PrivacyWindows),
42    /// A Windows host whose version record could not be read; every
43    /// control's edition fit is then `not_stated`.
44    Unreadable {
45        error: AxError,
46    },
47    /// The controls exist only on Windows; nothing is read or written.
48    NotWindows,
49}
50
51/// What `HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion` records.
52#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
53#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
54pub struct PrivacyWindows {
55    /// `EditionID` as written, for example `CoreCountrySpecific`.
56    pub edition_id: String,
57    /// The edition `edition_id` names; absent when it names none of the
58    /// editions the controls table lists.
59    pub edition: Option<PrivacyEdition>,
60    /// `CurrentBuild`, then `.UBR` when the update revision is recorded.
61    pub build: String,
62    /// `DisplayVersion`, for example `24H2`; builds before 20H2 have none.
63    pub display_version: Option<String>,
64}
65
66/// One control as the host's table defines it and as the host reads now.
67#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
68#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
69pub struct PrivacyControlEntry {
70    pub control: PrivacyControl,
71    pub category: PrivacyCategory,
72    /// The original items this control writes, in list order; empty for a
73    /// control added beyond the original list.
74    pub originals: Vec<PrivacyOriginalLine>,
75    pub target: PrivacyTarget,
76    /// `machine` is written through administrator approval.
77    pub scope: PrivacyScope,
78    pub editions: PrivacyEditions,
79    /// How `editions` reads for this host's edition.
80    pub host_fit: PrivacyEditionFit,
81    pub build_effect: PrivacyBuildEffect,
82    pub current: PrivacyCurrent,
83    /// What an apply leaves over `current`; absent when `current` was not
84    /// read, or when the host has no task to disable.
85    pub written: Option<PrivacyValue>,
86}
87
88/// Where Microsoft's documentation says a control is honoured and where it
89/// is ignored; an edition in neither list is not stated.
90#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
91#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
92pub struct PrivacyEditions {
93    pub honoured: Vec<PrivacyEdition>,
94    pub ignored: Vec<PrivacyEdition>,
95}
96
97/// One line of the request list, as the person wrote it.
98#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
99#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
100pub struct PrivacyOriginalLine {
101    pub item: PrivacyOriginal,
102    pub text: String,
103}
104
105/// An original item no control writes.
106#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
107#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
108pub struct PrivacyNotWrittenEntry {
109    pub line: PrivacyOriginalLine,
110    pub reason: PrivacyNotWritten,
111    /// The controls that come closest, in page order; possibly none.
112    pub alternatives: Vec<PrivacyControl>,
113}
114
115/// The place on the host a control writes, named by its operation kind.
116#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
117#[serde(tag = "kind", rename_all = "snake_case")]
118#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
119pub enum PrivacyTarget {
120    /// The value `name` under `HKLM\<path>`, in the 64-bit view.
121    RegistryValueHklm { path: String, name: String },
122    /// The value `name` under `HKCU\<path>`.
123    RegistryValueHkcu { path: String, name: String },
124    /// The variable `name` of the user's persistent environment.
125    EnvironmentVariableUser { name: String },
126    /// The task `name` in the task folder `path`.
127    ScheduledTaskEnabled { path: String, name: String },
128}
129
130/// What a read of a control's target gave.
131#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
132#[serde(rename_all = "snake_case")]
133#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
134pub enum PrivacyCurrent {
135    Read {
136        value: PrivacyValue,
137    },
138    /// This account may not read the target.
139    AccessDenied,
140    Failed {
141        error: AxError,
142    },
143    /// The host is not Windows, so nothing was read.
144    NotRead,
145}
146
147/// One value of a target, exactly as the host holds it.
148///
149/// Every value has exactly one spelling: a registry value is `dword` when
150/// it is a `REG_DWORD` of four bytes, `text` when it is a `REG_SZ` whose
151/// bytes are UTF-16 ending in one terminating NUL, and `raw` otherwise. A
152/// page sends a value back as `expected` unchanged, and the host turns it
153/// into the bytes it compares with what it reads, refusing any other
154/// spelling (`crates/wire/spec/Privacy.lean` D50).
155#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
156#[serde(tag = "value", rename_all = "snake_case", deny_unknown_fields)]
157#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
158pub enum PrivacyValue {
159    /// The registry value does not exist.
160    Absent,
161    Dword {
162        number: u32,
163    },
164    Text {
165        text: String,
166    },
167    /// Any other registry value: its type code and its bytes in lowercase
168    /// hex.
169    Raw {
170        kind: u32,
171        hex: String,
172    },
173    /// The host has no such task.
174    TaskAbsent,
175    /// The digest covers the task's definition without its enabled flag,
176    /// in lowercase hex.
177    TaskEnabled {
178        definition_sha256: String,
179    },
180    TaskDisabled {
181        definition_sha256: String,
182    },
183}
184
185/// What this app's history tells the page, which depends on who asks.
186#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
187#[serde(rename_all = "snake_case")]
188#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
189pub enum PrivacyHistory {
190    /// The account running the city is the one the history belongs to,
191    /// or the history is empty and has nobody to belong to.
192    Disclosed {
193        /// For each control this app still owns a change of, the latest
194        /// such change, in page order.
195        owned: Vec<PrivacyIntent>,
196        /// The operation that has no conclusion; every write waits for
197        /// the person's check of it.
198        unresolved: Option<PrivacyIntent>,
199    },
200    /// The identity check refused or could not be made; no recorded
201    /// value is shown.
202    Withheld { error: AxError },
203    /// The history could not be read: another operation holds it, or it
204    /// is damaged.
205    Unreadable { error: AxError },
206}
207
208/// One recorded operation: the value it found and the value it wrote.
209#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
210#[cfg_attr(feature = "schema", derive(schemars::JsonSchema))]
211pub struct PrivacyIntent {
212    /// Never zero.
213    pub operation: u64,
214    pub control: PrivacyControl,
215    pub original: PrivacyValue,
216    pub modified: PrivacyValue,
217    /// The operation a restore undoes; absent for an apply.
218    pub restore_of: Option<u64>,
219}