|
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 http://mozilla.org/MPL/2.0/. */ |
|
4 |
|
5 // Equivalent to 0600 permissions; used for saved Sync Recovery Key. |
|
6 // This constant can be replaced when the equivalent values are available to |
|
7 // chrome JS; see Bug 433295 and Bug 757351. |
|
8 const PERMISSIONS_RWUSR = 0x180; |
|
9 |
|
10 // Weave should always exist before before this file gets included. |
|
11 let gSyncUtils = { |
|
12 get bundle() { |
|
13 delete this.bundle; |
|
14 return this.bundle = Services.strings.createBundle("chrome://browser/locale/syncSetup.properties"); |
|
15 }, |
|
16 |
|
17 get fxAccountsEnabled() { |
|
18 let service = Components.classes["@mozilla.org/weave/service;1"] |
|
19 .getService(Components.interfaces.nsISupports) |
|
20 .wrappedJSObject; |
|
21 return service.fxAccountsEnabled; |
|
22 }, |
|
23 |
|
24 // opens in a new window if we're in a modal prefwindow world, in a new tab otherwise |
|
25 _openLink: function (url) { |
|
26 let thisDocEl = document.documentElement, |
|
27 openerDocEl = window.opener && window.opener.document.documentElement; |
|
28 if (thisDocEl.id == "accountSetup" && window.opener && |
|
29 openerDocEl.id == "BrowserPreferences" && !openerDocEl.instantApply) |
|
30 openUILinkIn(url, "window"); |
|
31 else if (thisDocEl.id == "BrowserPreferences" && !thisDocEl.instantApply) |
|
32 openUILinkIn(url, "window"); |
|
33 else if (document.documentElement.id == "change-dialog") |
|
34 Services.wm.getMostRecentWindow("navigator:browser") |
|
35 .openUILinkIn(url, "tab"); |
|
36 else |
|
37 openUILinkIn(url, "tab"); |
|
38 }, |
|
39 |
|
40 changeName: function changeName(input) { |
|
41 // Make sure to update to a modified name, e.g., empty-string -> default |
|
42 Weave.Service.clientsEngine.localName = input.value; |
|
43 input.value = Weave.Service.clientsEngine.localName; |
|
44 }, |
|
45 |
|
46 openChange: function openChange(type, duringSetup) { |
|
47 // Just re-show the dialog if it's already open |
|
48 let openedDialog = Services.wm.getMostRecentWindow("Sync:" + type); |
|
49 if (openedDialog != null) { |
|
50 openedDialog.focus(); |
|
51 return; |
|
52 } |
|
53 |
|
54 // Open up the change dialog |
|
55 let changeXUL = "chrome://browser/content/sync/genericChange.xul"; |
|
56 let changeOpt = "centerscreen,chrome,resizable=no"; |
|
57 Services.ww.activeWindow.openDialog(changeXUL, "", changeOpt, |
|
58 type, duringSetup); |
|
59 }, |
|
60 |
|
61 changePassword: function () { |
|
62 if (Weave.Utils.ensureMPUnlocked()) |
|
63 this.openChange("ChangePassword"); |
|
64 }, |
|
65 |
|
66 resetPassphrase: function (duringSetup) { |
|
67 if (Weave.Utils.ensureMPUnlocked()) |
|
68 this.openChange("ResetPassphrase", duringSetup); |
|
69 }, |
|
70 |
|
71 updatePassphrase: function () { |
|
72 if (Weave.Utils.ensureMPUnlocked()) |
|
73 this.openChange("UpdatePassphrase"); |
|
74 }, |
|
75 |
|
76 resetPassword: function () { |
|
77 this._openLink(Weave.Service.pwResetURL); |
|
78 }, |
|
79 |
|
80 openToS: function () { |
|
81 let root = this.fxAccountsEnabled ? "fxa." : ""; |
|
82 this._openLink(Weave.Svc.Prefs.get(root + "termsURL")); |
|
83 }, |
|
84 |
|
85 openPrivacyPolicy: function () { |
|
86 let root = this.fxAccountsEnabled ? "fxa." : ""; |
|
87 this._openLink(Weave.Svc.Prefs.get(root + "privacyURL")); |
|
88 }, |
|
89 |
|
90 openMPInfoPage: function (event) { |
|
91 event.stopPropagation(); |
|
92 let baseURL = Services.urlFormatter.formatURLPref("app.support.baseURL"); |
|
93 this._openLink(baseURL + "sync-master-password"); |
|
94 }, |
|
95 |
|
96 openFirstSyncProgressPage: function () { |
|
97 this._openLink("about:sync-progress"); |
|
98 }, |
|
99 |
|
100 /** |
|
101 * Prepare an invisible iframe with the passphrase backup document. |
|
102 * Used by both the print and saving methods. |
|
103 * |
|
104 * @param elid : ID of the form element containing the passphrase. |
|
105 * @param callback : Function called once the iframe has loaded. |
|
106 */ |
|
107 _preparePPiframe: function(elid, callback) { |
|
108 let pp = document.getElementById(elid).value; |
|
109 |
|
110 // Create an invisible iframe whose contents we can print. |
|
111 let iframe = document.createElement("iframe"); |
|
112 iframe.setAttribute("src", "chrome://browser/content/sync/key.xhtml"); |
|
113 iframe.collapsed = true; |
|
114 document.documentElement.appendChild(iframe); |
|
115 iframe.contentWindow.addEventListener("load", function() { |
|
116 iframe.contentWindow.removeEventListener("load", arguments.callee, false); |
|
117 |
|
118 // Insert the Sync Key into the page. |
|
119 let el = iframe.contentDocument.getElementById("synckey"); |
|
120 el.firstChild.nodeValue = pp; |
|
121 |
|
122 // Insert the TOS and Privacy Policy URLs into the page. |
|
123 let termsURL = Weave.Svc.Prefs.get("termsURL"); |
|
124 el = iframe.contentDocument.getElementById("tosLink"); |
|
125 el.setAttribute("href", termsURL); |
|
126 el.firstChild.nodeValue = termsURL; |
|
127 |
|
128 let privacyURL = Weave.Svc.Prefs.get("privacyURL"); |
|
129 el = iframe.contentDocument.getElementById("ppLink"); |
|
130 el.setAttribute("href", privacyURL); |
|
131 el.firstChild.nodeValue = privacyURL; |
|
132 |
|
133 callback(iframe); |
|
134 }, false); |
|
135 }, |
|
136 |
|
137 /** |
|
138 * Print passphrase backup document. |
|
139 * |
|
140 * @param elid : ID of the form element containing the passphrase. |
|
141 */ |
|
142 passphrasePrint: function(elid) { |
|
143 this._preparePPiframe(elid, function(iframe) { |
|
144 let webBrowserPrint = iframe.contentWindow |
|
145 .QueryInterface(Ci.nsIInterfaceRequestor) |
|
146 .getInterface(Ci.nsIWebBrowserPrint); |
|
147 let printSettings = PrintUtils.getPrintSettings(); |
|
148 |
|
149 // Display no header/footer decoration except for the date. |
|
150 printSettings.headerStrLeft |
|
151 = printSettings.headerStrCenter |
|
152 = printSettings.headerStrRight |
|
153 = printSettings.footerStrLeft |
|
154 = printSettings.footerStrCenter = ""; |
|
155 printSettings.footerStrRight = "&D"; |
|
156 |
|
157 try { |
|
158 webBrowserPrint.print(printSettings, null); |
|
159 } catch (ex) { |
|
160 // print()'s return codes are expressed as exceptions. Ignore. |
|
161 } |
|
162 }); |
|
163 }, |
|
164 |
|
165 /** |
|
166 * Save passphrase backup document to disk as HTML file. |
|
167 * |
|
168 * @param elid : ID of the form element containing the passphrase. |
|
169 */ |
|
170 passphraseSave: function(elid) { |
|
171 let dialogTitle = this.bundle.GetStringFromName("save.recoverykey.title"); |
|
172 let defaultSaveName = this.bundle.GetStringFromName("save.recoverykey.defaultfilename"); |
|
173 this._preparePPiframe(elid, function(iframe) { |
|
174 let fp = Cc["@mozilla.org/filepicker;1"].createInstance(Ci.nsIFilePicker); |
|
175 let fpCallback = function fpCallback_done(aResult) { |
|
176 if (aResult == Ci.nsIFilePicker.returnOK || |
|
177 aResult == Ci.nsIFilePicker.returnReplace) { |
|
178 let stream = Cc["@mozilla.org/network/file-output-stream;1"]. |
|
179 createInstance(Ci.nsIFileOutputStream); |
|
180 stream.init(fp.file, -1, PERMISSIONS_RWUSR, 0); |
|
181 |
|
182 let serializer = new XMLSerializer(); |
|
183 let output = serializer.serializeToString(iframe.contentDocument); |
|
184 output = output.replace(/<!DOCTYPE (.|\n)*?]>/, |
|
185 '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" ' + |
|
186 '"DTD/xhtml1-strict.dtd">'); |
|
187 output = Weave.Utils.encodeUTF8(output); |
|
188 stream.write(output, output.length); |
|
189 } |
|
190 }; |
|
191 |
|
192 fp.init(window, dialogTitle, Ci.nsIFilePicker.modeSave); |
|
193 fp.appendFilters(Ci.nsIFilePicker.filterHTML); |
|
194 fp.defaultString = defaultSaveName; |
|
195 fp.open(fpCallback); |
|
196 return false; |
|
197 }); |
|
198 }, |
|
199 |
|
200 /** |
|
201 * validatePassword |
|
202 * |
|
203 * @param el1 : the first textbox element in the form |
|
204 * @param el2 : the second textbox element, if omitted it's an update form |
|
205 * |
|
206 * returns [valid, errorString] |
|
207 */ |
|
208 validatePassword: function (el1, el2) { |
|
209 let valid = false; |
|
210 let val1 = el1.value; |
|
211 let val2 = el2 ? el2.value : ""; |
|
212 let error = ""; |
|
213 |
|
214 if (!el2) |
|
215 valid = val1.length >= Weave.MIN_PASS_LENGTH; |
|
216 else if (val1 && val1 == Weave.Service.identity.username) |
|
217 error = "change.password.pwSameAsUsername"; |
|
218 else if (val1 && val1 == Weave.Service.identity.account) |
|
219 error = "change.password.pwSameAsEmail"; |
|
220 else if (val1 && val1 == Weave.Service.identity.basicPassword) |
|
221 error = "change.password.pwSameAsPassword"; |
|
222 else if (val1 && val2) { |
|
223 if (val1 == val2 && val1.length >= Weave.MIN_PASS_LENGTH) |
|
224 valid = true; |
|
225 else if (val1.length < Weave.MIN_PASS_LENGTH) |
|
226 error = "change.password.tooShort"; |
|
227 else if (val1 != val2) |
|
228 error = "change.password.mismatch"; |
|
229 } |
|
230 let errorString = error ? Weave.Utils.getErrorString(error) : ""; |
|
231 return [valid, errorString]; |
|
232 } |
|
233 }; |