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}