Skip to content

Commit 1bb1448

Browse files
committed
Bug 2051904 - Show disk encryption status in about:support r?#firefox-desktop-core-reviewers r?#webcompat-reviewers
Expose disk-encryption status through Troubleshoot and show it in about:support. Keep inconclusive results visible. Remote troubleshooting and Report Broken Site opt out of the enterprise probes.
1 parent df6a306 commit 1bb1448

8 files changed

Lines changed: 243 additions & 19 deletions

File tree

browser/base/content/test/about/browser_aboutSupport.js

Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,117 @@ add_task(async function () {
7575
);
7676
});
7777

78+
add_task(
79+
{ skip_if: () => !AppConstants.MOZ_ENTERPRISE },
80+
async function test_disk_encryption_row() {
81+
// XPCOM registrations are process-local.
82+
const CASES = [
83+
{
84+
status: "full",
85+
method: "filevault",
86+
text: "Enabled (FileVault)",
87+
},
88+
{
89+
status: "full",
90+
method: "zfs",
91+
text: "Enabled (ZFS)",
92+
},
93+
{
94+
status: "enabled",
95+
method: "dm-crypt",
96+
text: "Enabled (dm-crypt); inspection incomplete",
97+
},
98+
{
99+
status: "partial",
100+
method: "bitlocker",
101+
text: "Partial (BitLocker); some mounted fixed volumes are not encrypted",
102+
},
103+
{
104+
status: "disabled",
105+
method: "dm-crypt",
106+
text: "Disabled",
107+
},
108+
{
109+
status: "in-progress",
110+
method: "bitlocker",
111+
text: "Encryption or decryption in progress",
112+
},
113+
{
114+
// The wrapper normalizes an empty method to null.
115+
status: "unknown",
116+
method: "",
117+
text: "Unknown",
118+
},
119+
];
120+
121+
await BrowserTestUtils.withNewTab(
122+
{ gBrowser, url: "about:support" },
123+
async browser => {
124+
for (const testCase of CASES) {
125+
const [l10nArgs, hidden] = await SpecialPowers.spawn(
126+
browser,
127+
[testCase],
128+
async expected => {
129+
const { MockRegistrar } = ChromeUtils.importESModule(
130+
"resource://testing-common/MockRegistrar.sys.mjs"
131+
);
132+
const { Troubleshoot } = ChromeUtils.importESModule(
133+
"resource://gre/modules/Troubleshoot.sys.mjs"
134+
);
135+
136+
const cid = MockRegistrar.register(
137+
"@mozilla.org/enterprise/disk-encryption-checker;1",
138+
{
139+
QueryInterface: ChromeUtils.generateQI([
140+
Ci.nsIDiskEncryptionChecker,
141+
]),
142+
getDiskEncryption(callback) {
143+
callback.onComplete(expected.status, expected.method);
144+
},
145+
}
146+
);
147+
148+
const doc = content.document;
149+
const id = `security-software-disk-encryption-${expected.status}`;
150+
try {
151+
const snapshot = await Troubleshoot.snapshot();
152+
content.wrappedJSObject.snapshotFormatters.securitySoftware(
153+
Cu.cloneInto(snapshot.securitySoftware, content)
154+
);
155+
156+
const cell = doc.getElementById(
157+
"security-software-disk-encryption"
158+
);
159+
// Wait for Fluent to replace the previous case's text.
160+
await ContentTaskUtils.waitForCondition(
161+
() =>
162+
doc.l10n.getAttributes(cell).id === id &&
163+
cell.textContent.trim() === expected.text,
164+
`${id} rendered as "${expected.text}", got "${cell.textContent.trim()}"`
165+
);
166+
return [
167+
doc.l10n.getAttributes(cell).args,
168+
doc.getElementById("security-software-disk-encryption-row")
169+
.hidden,
170+
];
171+
} finally {
172+
MockRegistrar.unregister(cid);
173+
}
174+
}
175+
);
176+
177+
Assert.equal(
178+
l10nArgs.method,
179+
testCase.method,
180+
"The method reaches Fluent, empty when there is none"
181+
);
182+
Assert.ok(!hidden, "The disk encryption row is shown");
183+
}
184+
}
185+
);
186+
}
187+
);
188+
78189
add_task(async function test_nimbus_experiments() {
79190
await ExperimentAPI.ready();
80191
let doExperimentCleanup = await NimbusTestUtils.enrollWithFeatureConfig({

browser/components/BrowserGlue.sys.mjs

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -816,14 +816,16 @@ BrowserGlue.prototype = {
816816
let { Troubleshoot } = ChromeUtils.importESModule(
817817
"resource://gre/modules/Troubleshoot.sys.mjs"
818818
);
819-
Troubleshoot.snapshot().then(snapshotData => {
820-
// for privacy we remove crash IDs and all preferences (but bug 1091944
821-
// exists to expose prefs once we are confident of privacy implications)
822-
delete snapshotData.crashes;
823-
delete snapshotData.modifiedPreferences;
824-
delete snapshotData.printingPreferences;
825-
channel.send(snapshotData, target);
826-
});
819+
Troubleshoot.snapshot({ includeEnterpriseSecurity: false }).then(
820+
snapshotData => {
821+
// for privacy we remove crash IDs and all preferences (but bug 1091944
822+
// exists to expose prefs once we are confident of privacy implications)
823+
delete snapshotData.crashes;
824+
delete snapshotData.modifiedPreferences;
825+
delete snapshotData.printingPreferences;
826+
channel.send(snapshotData, target);
827+
}
828+
);
827829
}
828830
});
829831

toolkit/components/reportbrokensite/ReportBrokenSiteParent.sys.mjs

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -617,10 +617,14 @@ export class ReportBrokenSiteParent extends JSWindowActorParent {
617617

618618
#getSecurityInfo(troubleshootingInfo) {
619619
const result = {};
620-
for (const [k, v] of Object.entries(troubleshootingInfo.securitySoftware)) {
621-
result[k.replace("registered", "").toLowerCase()] = v
622-
? v.split(";")
623-
: null;
620+
for (const key of [
621+
"registeredAntiVirus",
622+
"registeredAntiSpyware",
623+
"registeredFirewall",
624+
]) {
625+
const value = troubleshootingInfo.securitySoftware[key];
626+
result[key.replace("registered", "").toLowerCase()] =
627+
typeof value === "string" && value ? value.split(";") : null;
624628
}
625629

626630
// Right now, security data is only available for Windows builds, and
@@ -684,7 +688,9 @@ export class ReportBrokenSiteParent extends JSWindowActorParent {
684688
}
685689

686690
async #getBrowserInfo() {
687-
const troubleshootingInfo = await Troubleshoot.snapshot();
691+
const troubleshootingInfo = await Troubleshoot.snapshot({
692+
includeEnterpriseSecurity: false,
693+
});
688694
return {
689695
addons: this.#getActiveAddons(troubleshootingInfo),
690696
app: this.#getAppInfo(troubleshootingInfo),

toolkit/content/aboutSupport.js

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -379,7 +379,17 @@ var snapshotFormatters = {
379379
$("security-software-edr").textContent = data.presentEdrs.join(", ");
380380
}
381381

382-
let hasContent = isWin || hasEdrs;
382+
let diskEncryption = data.diskEncryption;
383+
$("security-software-disk-encryption-row").hidden = !diskEncryption;
384+
if (diskEncryption) {
385+
document.l10n.setAttributes(
386+
$("security-software-disk-encryption"),
387+
`security-software-disk-encryption-${diskEncryption.status}`,
388+
{ method: diskEncryption.method ?? "" }
389+
);
390+
}
391+
392+
let hasContent = isWin || hasEdrs || !!diskEncryption;
383393
$("security-software").hidden = !hasContent;
384394
$("security-software-table").hidden = !hasContent;
385395
},

toolkit/content/aboutSupport.xhtml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -437,6 +437,13 @@
437437
<td id="security-software-edr">
438438
</td>
439439
</tr>
440+
441+
<tr id="security-software-disk-encryption-row">
442+
<th class="column" data-l10n-id="security-software-disk-encryption"/>
443+
444+
<td id="security-software-disk-encryption">
445+
</td>
446+
</tr>
440447
</tbody>
441448
</table>
442449

toolkit/locales/en-US/toolkit/enterprise/enterprise.ftl

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,54 @@ app-basics-device-id = Device ID
1212
# Endpoint Detection and Response is an industry term and must remain in English.
1313
security-software-edr = Endpoint Detection and Response
1414
15+
# Shown in the about:support "Security Software" section on enterprise builds.
16+
security-software-disk-encryption = Disk Encryption
17+
18+
# $method identifies the platform encryption mechanism. FileVault, BitLocker,
19+
# dm-crypt, and ZFS are product names and should not be translated.
20+
# Variables:
21+
# $method (String): "filevault", "bitlocker", "dm-crypt" or "zfs".
22+
security-software-disk-encryption-full =
23+
{ $method ->
24+
[bitlocker] Enabled (BitLocker)
25+
[dm-crypt] Enabled (dm-crypt)
26+
[filevault] Enabled (FileVault)
27+
[zfs] Enabled (ZFS)
28+
*[other] Enabled
29+
}
30+
31+
# No plaintext volume was found, but at least one relevant volume or encryption
32+
# mapping could not be inspected completely.
33+
# Variables:
34+
# $method (String): "filevault", "bitlocker", "dm-crypt" or "zfs".
35+
security-software-disk-encryption-enabled =
36+
{ $method ->
37+
[bitlocker] Enabled (BitLocker); inspection incomplete
38+
[dm-crypt] Enabled (dm-crypt); inspection incomplete
39+
[filevault] Enabled (FileVault); inspection incomplete
40+
[zfs] Enabled (ZFS); inspection incomplete
41+
*[other] Enabled; inspection incomplete
42+
}
43+
44+
# The boot volume is encrypted, but another mounted fixed volume is not.
45+
# Variables:
46+
# $method (String): "filevault", "bitlocker", "dm-crypt" or "zfs".
47+
security-software-disk-encryption-partial =
48+
{ $method ->
49+
[bitlocker] Partial (BitLocker); some mounted fixed volumes are not encrypted
50+
[dm-crypt] Partial (dm-crypt); some mounted fixed volumes are not encrypted
51+
[filevault] Partial (FileVault); some mounted fixed volumes are not encrypted
52+
[zfs] Partial (ZFS); some mounted fixed volumes are not encrypted
53+
*[other] Partial; some mounted fixed volumes are not encrypted
54+
}
55+
56+
security-software-disk-encryption-disabled = Disabled
57+
58+
# A volume is currently being encrypted or decrypted.
59+
security-software-disk-encryption-in-progress = Encryption or decryption in progress
60+
61+
security-software-disk-encryption-unknown = Unknown
62+
1563
enterprise-toolbar-button =
1664
.label = { -brand-short-name }
1765
.tooltiptext = { -brand-short-name }

toolkit/modules/Troubleshoot.sys.mjs

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import { AppConstants } from "resource://gre/modules/AppConstants.sys.mjs";
88
const lazy = {};
99

1010
ChromeUtils.defineESModuleGetters(lazy, {
11+
DiskEncryption: "resource://gre/modules/enterprise/DiskEncryption.sys.mjs",
1112
EdrDetection: "resource://gre/modules/enterprise/EdrDetection.sys.mjs",
1213
MachineId: "resource://gre/modules/enterprise/MachineId.sys.mjs",
1314
PlacesDBUtils: "resource://gre/modules/PlacesDBUtils.sys.mjs",
@@ -175,10 +176,13 @@ export var Troubleshoot = {
175176
* Captures a snapshot of data that may help troubleshooters troubleshoot
176177
* trouble.
177178
*
179+
* @param {object} [options]
180+
* @param {boolean} [options.includeEnterpriseSecurity=true]
181+
* Whether to run and include the enterprise EDR and disk-encryption probes.
178182
* @returns {Promise}
179183
* A promise that is resolved with the snapshot data.
180184
*/
181-
snapshot() {
185+
snapshot({ includeEnterpriseSecurity = true } = {}) {
182186
return new Promise(resolve => {
183187
let snapshot = {};
184188
let numPending = Object.keys(dataProviders).length;
@@ -191,7 +195,9 @@ export var Troubleshoot = {
191195
}
192196
for (let name in dataProviders) {
193197
try {
194-
dataProviders[name](providerDone.bind(null, name));
198+
dataProviders[name](providerDone.bind(null, name), {
199+
includeEnterpriseSecurity,
200+
});
195201
} catch (err) {
196202
let msg = "Troubleshoot data provider failed: " + name + "\n" + err;
197203
console.error(msg);
@@ -388,7 +394,10 @@ var dataProviders = {
388394
);
389395
},
390396

391-
securitySoftware: async function securitySoftware(done) {
397+
securitySoftware: async function securitySoftware(
398+
done,
399+
{ includeEnterpriseSecurity }
400+
) {
392401
let data = {};
393402

394403
const keys = [
@@ -405,8 +414,11 @@ var dataProviders = {
405414
data[key] = prop;
406415
}
407416

408-
if (AppConstants.MOZ_ENTERPRISE) {
409-
data.presentEdrs = await lazy.EdrDetection.getPresentEdrs();
417+
if (AppConstants.MOZ_ENTERPRISE && includeEnterpriseSecurity) {
418+
[data.presentEdrs, data.diskEncryption] = await Promise.all([
419+
lazy.EdrDetection.getPresentEdrs(),
420+
lazy.DiskEncryption.getStatus(),
421+
]);
410422
}
411423

412424
done(data);

toolkit/modules/tests/browser/browser_Troubleshoot.js

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,20 @@ add_task(async function snapshotSchema() {
3838
}
3939
});
4040

41+
add_task(async function enterpriseSecurityCanBeExcluded() {
42+
let snapshot = await Troubleshoot.snapshot({
43+
includeEnterpriseSecurity: false,
44+
});
45+
ok(
46+
!("presentEdrs" in snapshot.securitySoftware),
47+
"EDR products are excluded"
48+
);
49+
ok(
50+
!("diskEncryption" in snapshot.securitySoftware),
51+
"disk encryption is excluded"
52+
);
53+
});
54+
4155
add_task(async function modifiedPreferences() {
4256
let prefs = [
4357
"javascript.troubleshoot",
@@ -453,6 +467,20 @@ const SNAPSHOT_SCHEMA = {
453467
required: false,
454468
type: "array",
455469
},
470+
diskEncryption: {
471+
required: false,
472+
type: "object",
473+
properties: {
474+
status: {
475+
required: true,
476+
type: "string",
477+
},
478+
method: {
479+
required: true,
480+
type: ["string", "null"],
481+
},
482+
},
483+
},
456484
},
457485
},
458486
processes: {

0 commit comments

Comments
 (0)