|
1 /* Any copyright is dedicated to the Public Domain. |
|
2 * http://creativecommons.org/publicdomain/zero/1.0/ */ |
|
3 |
|
4 "use strict"; |
|
5 |
|
6 /** |
|
7 * This test ensures that form data collection respects the privacy level as |
|
8 * set by the user. |
|
9 */ |
|
10 add_task(function test_formdata() { |
|
11 const URL = "http://mochi.test:8888/browser/browser/components/" + |
|
12 "sessionstore/test/browser_formdata_sample.html"; |
|
13 |
|
14 const OUTER_VALUE = "browser_formdata_" + Math.random(); |
|
15 const INNER_VALUE = "browser_formdata_" + Math.random(); |
|
16 |
|
17 // Creates a tab, loads a page with some form fields, |
|
18 // modifies their values and closes the tab. |
|
19 function createAndRemoveTab() { |
|
20 return Task.spawn(function () { |
|
21 // Create a new tab. |
|
22 let tab = gBrowser.addTab(URL); |
|
23 let browser = tab.linkedBrowser; |
|
24 yield promiseBrowserLoaded(browser); |
|
25 |
|
26 // Modify form data. |
|
27 yield setInputValue(browser, {id: "txt", value: OUTER_VALUE}); |
|
28 yield setInputValue(browser, {id: "txt", value: INNER_VALUE, frame: 0}); |
|
29 |
|
30 // Remove the tab. |
|
31 gBrowser.removeTab(tab); |
|
32 }); |
|
33 } |
|
34 |
|
35 yield createAndRemoveTab(); |
|
36 let [{state: {formdata}}] = JSON.parse(ss.getClosedTabData(window)); |
|
37 is(formdata.id.txt, OUTER_VALUE, "outer value is correct"); |
|
38 is(formdata.children[0].id.txt, INNER_VALUE, "inner value is correct"); |
|
39 |
|
40 // Disable saving data for encrypted sites. |
|
41 Services.prefs.setIntPref("browser.sessionstore.privacy_level", 1); |
|
42 |
|
43 yield createAndRemoveTab(); |
|
44 let [{state: {formdata}}] = JSON.parse(ss.getClosedTabData(window)); |
|
45 is(formdata.id.txt, OUTER_VALUE, "outer value is correct"); |
|
46 ok(!formdata.children, "inner value was *not* stored"); |
|
47 |
|
48 // Disable saving data for any site. |
|
49 Services.prefs.setIntPref("browser.sessionstore.privacy_level", 2); |
|
50 |
|
51 yield createAndRemoveTab(); |
|
52 let [{state: {formdata}}] = JSON.parse(ss.getClosedTabData(window)); |
|
53 ok(!formdata, "form data has *not* been stored"); |
|
54 |
|
55 // Restore the default privacy level. |
|
56 Services.prefs.clearUserPref("browser.sessionstore.privacy_level"); |
|
57 }); |
|
58 |
|
59 /** |
|
60 * This test ensures that we maintain backwards compatibility with the form |
|
61 * data format used pre Fx 29. |
|
62 */ |
|
63 add_task(function test_old_format() { |
|
64 const URL = "data:text/html;charset=utf-8,<input%20id=input>"; |
|
65 const VALUE = "value-" + Math.random(); |
|
66 |
|
67 // Create a tab with an iframe containing an input field. |
|
68 let tab = gBrowser.addTab(URL); |
|
69 let browser = tab.linkedBrowser; |
|
70 yield promiseBrowserLoaded(browser); |
|
71 |
|
72 // Check that the form value is restored. |
|
73 let state = {entries: [{url: URL, formdata: {id: {input: VALUE}}}]}; |
|
74 ss.setTabState(tab, JSON.stringify(state)); |
|
75 yield promiseTabRestored(tab); |
|
76 is((yield getInputValue(browser, "input")), VALUE, "form data restored"); |
|
77 |
|
78 // Cleanup. |
|
79 gBrowser.removeTab(tab); |
|
80 }); |
|
81 |
|
82 /** |
|
83 * This test ensures that we maintain backwards compatibility with the form |
|
84 * data form used pre Fx 29, esp. the .innerHTML property for editable docs. |
|
85 */ |
|
86 add_task(function test_old_format_inner_html() { |
|
87 const URL = "data:text/html;charset=utf-8,<h1>mozilla</h1>" + |
|
88 "<script>document.designMode='on'</script>"; |
|
89 const VALUE = "<h1>value-" + Math.random() + "</h1>"; |
|
90 |
|
91 // Create a tab with an iframe containing an input field. |
|
92 let tab = gBrowser.addTab(URL); |
|
93 let browser = tab.linkedBrowser; |
|
94 yield promiseBrowserLoaded(browser); |
|
95 |
|
96 // Restore the tab state. |
|
97 let state = {entries: [{url: URL, innerHTML: VALUE}]}; |
|
98 ss.setTabState(tab, JSON.stringify(state)); |
|
99 yield promiseTabRestored(tab); |
|
100 |
|
101 // Check that the innerHTML value was restored. |
|
102 let html = yield getInnerHTML(browser); |
|
103 is(html, VALUE, "editable document has been restored correctly"); |
|
104 |
|
105 // Cleanup. |
|
106 gBrowser.removeTab(tab); |
|
107 }); |
|
108 |
|
109 /** |
|
110 * This test ensures that a malicious website can't trick us into restoring |
|
111 * form data into a wrong website and that we always check the stored URL |
|
112 * before doing so. |
|
113 */ |
|
114 add_task(function test_url_check() { |
|
115 const URL = "data:text/html;charset=utf-8,<input%20id=input>"; |
|
116 const VALUE = "value-" + Math.random(); |
|
117 |
|
118 // Create a tab with an iframe containing an input field. |
|
119 let tab = gBrowser.addTab(URL); |
|
120 let browser = tab.linkedBrowser; |
|
121 yield promiseBrowserLoaded(browser); |
|
122 |
|
123 // Restore a tab state with a given form data url. |
|
124 function restoreStateWithURL(url) { |
|
125 let state = {entries: [{url: URL}], formdata: {id: {input: VALUE}}}; |
|
126 |
|
127 if (url) { |
|
128 state.formdata.url = url; |
|
129 } |
|
130 |
|
131 ss.setTabState(tab, JSON.stringify(state)); |
|
132 return promiseTabRestored(tab).then(() => getInputValue(browser, "input")); |
|
133 } |
|
134 |
|
135 // Check that the form value is restored with the correct URL. |
|
136 is((yield restoreStateWithURL(URL)), VALUE, "form data restored"); |
|
137 |
|
138 // Check that the form value is *not* restored with the wrong URL. |
|
139 is((yield restoreStateWithURL(URL + "?")), "", "form data not restored"); |
|
140 is((yield restoreStateWithURL()), "", "form data not restored"); |
|
141 |
|
142 // Cleanup. |
|
143 gBrowser.removeTab(tab); |
|
144 }); |
|
145 |
|
146 /** |
|
147 * This test ensures that collecting form data works as expected when having |
|
148 * nested frame sets. |
|
149 */ |
|
150 add_task(function test_nested() { |
|
151 const URL = "data:text/html;charset=utf-8," + |
|
152 "<iframe src='data:text/html;charset=utf-8," + |
|
153 "<input autofocus=true>'/>"; |
|
154 |
|
155 const FORM_DATA = { |
|
156 children: [{ |
|
157 xpath: {"/xhtml:html/xhtml:body/xhtml:input": "M"}, |
|
158 url: "data:text/html;charset=utf-8,<input%20autofocus=true>" |
|
159 }] |
|
160 }; |
|
161 |
|
162 // Create a tab with an iframe containing an input field. |
|
163 let tab = gBrowser.selectedTab = gBrowser.addTab(URL); |
|
164 let browser = tab.linkedBrowser; |
|
165 yield promiseBrowserLoaded(browser); |
|
166 |
|
167 // Modify the input field's value. |
|
168 yield sendMessage(browser, "ss-test:sendKeyEvent", {key: "m", frame: 0}); |
|
169 |
|
170 // Remove the tab and check that we stored form data correctly. |
|
171 gBrowser.removeTab(tab); |
|
172 let [{state: {formdata}}] = JSON.parse(ss.getClosedTabData(window)); |
|
173 is(JSON.stringify(formdata), JSON.stringify(FORM_DATA), |
|
174 "formdata for iframe stored correctly"); |
|
175 |
|
176 // Restore the closed tab. |
|
177 let tab = ss.undoCloseTab(window, 0); |
|
178 let browser = tab.linkedBrowser; |
|
179 yield promiseTabRestored(tab); |
|
180 |
|
181 // Check that the input field has the right value. |
|
182 SyncHandlers.get(browser).flush(); |
|
183 let {formdata} = JSON.parse(ss.getTabState(tab)); |
|
184 is(JSON.stringify(formdata), JSON.stringify(FORM_DATA), |
|
185 "formdata for iframe restored correctly"); |
|
186 |
|
187 // Cleanup. |
|
188 gBrowser.removeTab(tab); |
|
189 }); |
|
190 |
|
191 /** |
|
192 * This test ensures that collecting form data for documents with |
|
193 * designMode=on works as expected. |
|
194 */ |
|
195 add_task(function test_design_mode() { |
|
196 const URL = "data:text/html;charset=utf-8,<h1>mozilla</h1>" + |
|
197 "<script>document.designMode='on'</script>"; |
|
198 |
|
199 // Load a tab with an editable document. |
|
200 let tab = gBrowser.selectedTab = gBrowser.addTab(URL); |
|
201 let browser = tab.linkedBrowser; |
|
202 yield promiseBrowserLoaded(browser); |
|
203 |
|
204 // Modify the document content. |
|
205 yield sendMessage(browser, "ss-test:sendKeyEvent", {key: "m"}); |
|
206 |
|
207 // Duplicate the modified tab. |
|
208 let tab2 = gBrowser.duplicateTab(tab); |
|
209 yield promiseTabRestored(tab2); |
|
210 |
|
211 // Check that the innerHTML value was restored. |
|
212 let html = yield getInnerHTML(browser); |
|
213 let expected = "<h1>Mmozilla</h1><script>document.designMode='on'</script>"; |
|
214 is(html, expected, "editable document has been restored correctly"); |
|
215 |
|
216 // Cleanup. |
|
217 gBrowser.removeTab(tab2); |
|
218 gBrowser.removeTab(tab); |
|
219 }); |
|
220 |
|
221 function getInputValue(browser, id) { |
|
222 return sendMessage(browser, "ss-test:getInputValue", {id: id}); |
|
223 } |
|
224 |
|
225 function setInputValue(browser, data) { |
|
226 return sendMessage(browser, "ss-test:setInputValue", data); |
|
227 } |
|
228 |
|
229 function getInnerHTML(browser) { |
|
230 return sendMessage(browser, "ss-test:getInnerHTML", {selector: "body"}); |
|
231 } |