summaryrefslogtreecommitdiffstats
path: root/browser/base/content/test/general/browser_ssl_error_reports.js
blob: b1b1c8b84f5cd3bf006677f88f55152c733fddac (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
"use strict";

const URL_REPORTS = "https://example.com/browser/browser/base/content/test/general/ssl_error_reports.sjs?";
const URL_BAD_CHAIN = "https://badchain.include-subdomains.pinning.example.com/";
const URL_NO_CERT = "https://fail-handshake.example.com/";
const URL_BAD_CERT = "https://expired.example.com/";
const URL_BAD_STS_CERT = "https://badchain.include-subdomains.pinning.example.com:443/";
const ROOT = getRootDirectory(gTestPath);
const PREF_REPORT_ENABLED = "security.ssl.errorReporting.enabled";
const PREF_REPORT_AUTOMATIC = "security.ssl.errorReporting.automatic";
const PREF_REPORT_URL = "security.ssl.errorReporting.url";

SimpleTest.requestCompleteLog();

Services.prefs.setIntPref("security.cert_pinning.enforcement_level", 2);

function cleanup() {
  Services.prefs.clearUserPref(PREF_REPORT_ENABLED);
  Services.prefs.clearUserPref(PREF_REPORT_AUTOMATIC);
  Services.prefs.clearUserPref(PREF_REPORT_URL);
}

registerCleanupFunction(() => {
  Services.prefs.clearUserPref("security.cert_pinning.enforcement_level");
  cleanup();
});

add_task(function* test_send_report_neterror() {
  yield testSendReportAutomatically(URL_BAD_CHAIN, "succeed", "neterror");
  yield testSendReportAutomatically(URL_NO_CERT, "nocert", "neterror");
  yield testSetAutomatic(URL_NO_CERT, "nocert", "neterror");
});


add_task(function* test_send_report_certerror() {
  yield testSendReportAutomatically(URL_BAD_CERT, "badcert", "certerror");
  yield testSetAutomatic(URL_BAD_CERT, "badcert", "certerror");
});

add_task(function* test_send_disabled() {
  Services.prefs.setBoolPref(PREF_REPORT_ENABLED, false);
  Services.prefs.setBoolPref(PREF_REPORT_AUTOMATIC, true);
  Services.prefs.setCharPref(PREF_REPORT_URL, "https://example.com/invalid");

  // Check with enabled=false but automatic=true.
  yield testSendReportDisabled(URL_NO_CERT, "neterror");
  yield testSendReportDisabled(URL_BAD_CERT, "certerror");

  Services.prefs.setBoolPref(PREF_REPORT_AUTOMATIC, false);

  // Check again with both prefs false.
  yield testSendReportDisabled(URL_NO_CERT, "neterror");
  yield testSendReportDisabled(URL_BAD_CERT, "certerror");
  cleanup();
});

function* testSendReportAutomatically(testURL, suffix, errorURISuffix) {
  Services.prefs.setBoolPref(PREF_REPORT_ENABLED, true);
  Services.prefs.setBoolPref(PREF_REPORT_AUTOMATIC, true);
  Services.prefs.setCharPref(PREF_REPORT_URL, URL_REPORTS + suffix);

  // Add a tab and wait until it's loaded.
  let tab = yield BrowserTestUtils.openNewForegroundTab(gBrowser, "about:blank");
  let browser = tab.linkedBrowser;

  // Load the page and wait for the error report submission.
  let promiseStatus = createReportResponseStatusPromise(URL_REPORTS + suffix);
  browser.loadURI(testURL);
  yield promiseErrorPageLoaded(browser);

  ok(!isErrorStatus(yield promiseStatus),
     "SSL error report submitted successfully");

  // Check that we loaded the right error page.
  yield checkErrorPage(browser, errorURISuffix);

  // Cleanup.
  gBrowser.removeTab(tab);
  cleanup();
}

function* testSetAutomatic(testURL, suffix, errorURISuffix) {
  Services.prefs.setBoolPref(PREF_REPORT_ENABLED, true);
  Services.prefs.setBoolPref(PREF_REPORT_AUTOMATIC, false);
  Services.prefs.setCharPref(PREF_REPORT_URL, URL_REPORTS + suffix);

  // Add a tab and wait until it's loaded.
  let tab = yield BrowserTestUtils.openNewForegroundTab(gBrowser, "about:blank");
  let browser = tab.linkedBrowser;

  // Load the page.
  browser.loadURI(testURL);
  yield promiseErrorPageLoaded(browser);

  // Check that we loaded the right error page.
  yield checkErrorPage(browser, errorURISuffix);

  let statusPromise = createReportResponseStatusPromise(URL_REPORTS + suffix);

  // Click the checkbox, enable automatic error reports.
  yield ContentTask.spawn(browser, null, function* () {
    content.document.getElementById("automaticallyReportInFuture").click();
  });

  // Wait for the error report submission.
  yield statusPromise;

  let isAutomaticReportingEnabled = () =>
    Services.prefs.getBoolPref(PREF_REPORT_AUTOMATIC);

  // Check that the pref was flipped.
  ok(isAutomaticReportingEnabled(), "automatic SSL report submission enabled");

  // Disable automatic error reports.
  yield ContentTask.spawn(browser, null, function* () {
    content.document.getElementById("automaticallyReportInFuture").click();
  });

  // Check that the pref was flipped.
  ok(!isAutomaticReportingEnabled(), "automatic SSL report submission disabled");

  // Cleanup.
  gBrowser.removeTab(tab);
  cleanup();
}

function* testSendReportDisabled(testURL, errorURISuffix) {
  // Add a tab and wait until it's loaded.
  let tab = yield BrowserTestUtils.openNewForegroundTab(gBrowser, "about:blank");
  let browser = tab.linkedBrowser;

  // Load the page.
  browser.loadURI(testURL);
  yield promiseErrorPageLoaded(browser);

  // Check that we loaded the right error page.
  yield checkErrorPage(browser, errorURISuffix);

  // Check that the error reporting section is hidden.
  yield ContentTask.spawn(browser, null, function* () {
    let section = content.document.getElementById("certificateErrorReporting");
    Assert.equal(content.getComputedStyle(section).display, "none",
      "error reporting section should be hidden");
  });

  // Cleanup.
  gBrowser.removeTab(tab);
}

function isErrorStatus(status) {
  return status < 200 || status >= 300;
}

// use the observer service to see when a report is sent
function createReportResponseStatusPromise(expectedURI) {
  return new Promise(resolve => {
    let observer = (subject, topic, data) => {
      subject.QueryInterface(Ci.nsIHttpChannel);
      let requestURI = subject.URI.spec;
      if (requestURI == expectedURI) {
        Services.obs.removeObserver(observer, "http-on-examine-response");
        resolve(subject.responseStatus);
      }
    };
    Services.obs.addObserver(observer, "http-on-examine-response", false);
  });
}

function checkErrorPage(browser, suffix) {
  return ContentTask.spawn(browser, { suffix }, function* (args) {
    let uri = content.document.documentURI;
    Assert.ok(uri.startsWith(`about:${args.suffix}`), "correct error page loaded");
  });
}