1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/browser/base/content/sync/utils.js Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,233 @@ 1.4 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.5 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.6 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.7 + 1.8 +// Equivalent to 0600 permissions; used for saved Sync Recovery Key. 1.9 +// This constant can be replaced when the equivalent values are available to 1.10 +// chrome JS; see Bug 433295 and Bug 757351. 1.11 +const PERMISSIONS_RWUSR = 0x180; 1.12 + 1.13 +// Weave should always exist before before this file gets included. 1.14 +let gSyncUtils = { 1.15 + get bundle() { 1.16 + delete this.bundle; 1.17 + return this.bundle = Services.strings.createBundle("chrome://browser/locale/syncSetup.properties"); 1.18 + }, 1.19 + 1.20 + get fxAccountsEnabled() { 1.21 + let service = Components.classes["@mozilla.org/weave/service;1"] 1.22 + .getService(Components.interfaces.nsISupports) 1.23 + .wrappedJSObject; 1.24 + return service.fxAccountsEnabled; 1.25 + }, 1.26 + 1.27 + // opens in a new window if we're in a modal prefwindow world, in a new tab otherwise 1.28 + _openLink: function (url) { 1.29 + let thisDocEl = document.documentElement, 1.30 + openerDocEl = window.opener && window.opener.document.documentElement; 1.31 + if (thisDocEl.id == "accountSetup" && window.opener && 1.32 + openerDocEl.id == "BrowserPreferences" && !openerDocEl.instantApply) 1.33 + openUILinkIn(url, "window"); 1.34 + else if (thisDocEl.id == "BrowserPreferences" && !thisDocEl.instantApply) 1.35 + openUILinkIn(url, "window"); 1.36 + else if (document.documentElement.id == "change-dialog") 1.37 + Services.wm.getMostRecentWindow("navigator:browser") 1.38 + .openUILinkIn(url, "tab"); 1.39 + else 1.40 + openUILinkIn(url, "tab"); 1.41 + }, 1.42 + 1.43 + changeName: function changeName(input) { 1.44 + // Make sure to update to a modified name, e.g., empty-string -> default 1.45 + Weave.Service.clientsEngine.localName = input.value; 1.46 + input.value = Weave.Service.clientsEngine.localName; 1.47 + }, 1.48 + 1.49 + openChange: function openChange(type, duringSetup) { 1.50 + // Just re-show the dialog if it's already open 1.51 + let openedDialog = Services.wm.getMostRecentWindow("Sync:" + type); 1.52 + if (openedDialog != null) { 1.53 + openedDialog.focus(); 1.54 + return; 1.55 + } 1.56 + 1.57 + // Open up the change dialog 1.58 + let changeXUL = "chrome://browser/content/sync/genericChange.xul"; 1.59 + let changeOpt = "centerscreen,chrome,resizable=no"; 1.60 + Services.ww.activeWindow.openDialog(changeXUL, "", changeOpt, 1.61 + type, duringSetup); 1.62 + }, 1.63 + 1.64 + changePassword: function () { 1.65 + if (Weave.Utils.ensureMPUnlocked()) 1.66 + this.openChange("ChangePassword"); 1.67 + }, 1.68 + 1.69 + resetPassphrase: function (duringSetup) { 1.70 + if (Weave.Utils.ensureMPUnlocked()) 1.71 + this.openChange("ResetPassphrase", duringSetup); 1.72 + }, 1.73 + 1.74 + updatePassphrase: function () { 1.75 + if (Weave.Utils.ensureMPUnlocked()) 1.76 + this.openChange("UpdatePassphrase"); 1.77 + }, 1.78 + 1.79 + resetPassword: function () { 1.80 + this._openLink(Weave.Service.pwResetURL); 1.81 + }, 1.82 + 1.83 + openToS: function () { 1.84 + let root = this.fxAccountsEnabled ? "fxa." : ""; 1.85 + this._openLink(Weave.Svc.Prefs.get(root + "termsURL")); 1.86 + }, 1.87 + 1.88 + openPrivacyPolicy: function () { 1.89 + let root = this.fxAccountsEnabled ? "fxa." : ""; 1.90 + this._openLink(Weave.Svc.Prefs.get(root + "privacyURL")); 1.91 + }, 1.92 + 1.93 + openMPInfoPage: function (event) { 1.94 + event.stopPropagation(); 1.95 + let baseURL = Services.urlFormatter.formatURLPref("app.support.baseURL"); 1.96 + this._openLink(baseURL + "sync-master-password"); 1.97 + }, 1.98 + 1.99 + openFirstSyncProgressPage: function () { 1.100 + this._openLink("about:sync-progress"); 1.101 + }, 1.102 + 1.103 + /** 1.104 + * Prepare an invisible iframe with the passphrase backup document. 1.105 + * Used by both the print and saving methods. 1.106 + * 1.107 + * @param elid : ID of the form element containing the passphrase. 1.108 + * @param callback : Function called once the iframe has loaded. 1.109 + */ 1.110 + _preparePPiframe: function(elid, callback) { 1.111 + let pp = document.getElementById(elid).value; 1.112 + 1.113 + // Create an invisible iframe whose contents we can print. 1.114 + let iframe = document.createElement("iframe"); 1.115 + iframe.setAttribute("src", "chrome://browser/content/sync/key.xhtml"); 1.116 + iframe.collapsed = true; 1.117 + document.documentElement.appendChild(iframe); 1.118 + iframe.contentWindow.addEventListener("load", function() { 1.119 + iframe.contentWindow.removeEventListener("load", arguments.callee, false); 1.120 + 1.121 + // Insert the Sync Key into the page. 1.122 + let el = iframe.contentDocument.getElementById("synckey"); 1.123 + el.firstChild.nodeValue = pp; 1.124 + 1.125 + // Insert the TOS and Privacy Policy URLs into the page. 1.126 + let termsURL = Weave.Svc.Prefs.get("termsURL"); 1.127 + el = iframe.contentDocument.getElementById("tosLink"); 1.128 + el.setAttribute("href", termsURL); 1.129 + el.firstChild.nodeValue = termsURL; 1.130 + 1.131 + let privacyURL = Weave.Svc.Prefs.get("privacyURL"); 1.132 + el = iframe.contentDocument.getElementById("ppLink"); 1.133 + el.setAttribute("href", privacyURL); 1.134 + el.firstChild.nodeValue = privacyURL; 1.135 + 1.136 + callback(iframe); 1.137 + }, false); 1.138 + }, 1.139 + 1.140 + /** 1.141 + * Print passphrase backup document. 1.142 + * 1.143 + * @param elid : ID of the form element containing the passphrase. 1.144 + */ 1.145 + passphrasePrint: function(elid) { 1.146 + this._preparePPiframe(elid, function(iframe) { 1.147 + let webBrowserPrint = iframe.contentWindow 1.148 + .QueryInterface(Ci.nsIInterfaceRequestor) 1.149 + .getInterface(Ci.nsIWebBrowserPrint); 1.150 + let printSettings = PrintUtils.getPrintSettings(); 1.151 + 1.152 + // Display no header/footer decoration except for the date. 1.153 + printSettings.headerStrLeft 1.154 + = printSettings.headerStrCenter 1.155 + = printSettings.headerStrRight 1.156 + = printSettings.footerStrLeft 1.157 + = printSettings.footerStrCenter = ""; 1.158 + printSettings.footerStrRight = "&D"; 1.159 + 1.160 + try { 1.161 + webBrowserPrint.print(printSettings, null); 1.162 + } catch (ex) { 1.163 + // print()'s return codes are expressed as exceptions. Ignore. 1.164 + } 1.165 + }); 1.166 + }, 1.167 + 1.168 + /** 1.169 + * Save passphrase backup document to disk as HTML file. 1.170 + * 1.171 + * @param elid : ID of the form element containing the passphrase. 1.172 + */ 1.173 + passphraseSave: function(elid) { 1.174 + let dialogTitle = this.bundle.GetStringFromName("save.recoverykey.title"); 1.175 + let defaultSaveName = this.bundle.GetStringFromName("save.recoverykey.defaultfilename"); 1.176 + this._preparePPiframe(elid, function(iframe) { 1.177 + let fp = Cc["@mozilla.org/filepicker;1"].createInstance(Ci.nsIFilePicker); 1.178 + let fpCallback = function fpCallback_done(aResult) { 1.179 + if (aResult == Ci.nsIFilePicker.returnOK || 1.180 + aResult == Ci.nsIFilePicker.returnReplace) { 1.181 + let stream = Cc["@mozilla.org/network/file-output-stream;1"]. 1.182 + createInstance(Ci.nsIFileOutputStream); 1.183 + stream.init(fp.file, -1, PERMISSIONS_RWUSR, 0); 1.184 + 1.185 + let serializer = new XMLSerializer(); 1.186 + let output = serializer.serializeToString(iframe.contentDocument); 1.187 + output = output.replace(/<!DOCTYPE (.|\n)*?]>/, 1.188 + '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" ' + 1.189 + '"DTD/xhtml1-strict.dtd">'); 1.190 + output = Weave.Utils.encodeUTF8(output); 1.191 + stream.write(output, output.length); 1.192 + } 1.193 + }; 1.194 + 1.195 + fp.init(window, dialogTitle, Ci.nsIFilePicker.modeSave); 1.196 + fp.appendFilters(Ci.nsIFilePicker.filterHTML); 1.197 + fp.defaultString = defaultSaveName; 1.198 + fp.open(fpCallback); 1.199 + return false; 1.200 + }); 1.201 + }, 1.202 + 1.203 + /** 1.204 + * validatePassword 1.205 + * 1.206 + * @param el1 : the first textbox element in the form 1.207 + * @param el2 : the second textbox element, if omitted it's an update form 1.208 + * 1.209 + * returns [valid, errorString] 1.210 + */ 1.211 + validatePassword: function (el1, el2) { 1.212 + let valid = false; 1.213 + let val1 = el1.value; 1.214 + let val2 = el2 ? el2.value : ""; 1.215 + let error = ""; 1.216 + 1.217 + if (!el2) 1.218 + valid = val1.length >= Weave.MIN_PASS_LENGTH; 1.219 + else if (val1 && val1 == Weave.Service.identity.username) 1.220 + error = "change.password.pwSameAsUsername"; 1.221 + else if (val1 && val1 == Weave.Service.identity.account) 1.222 + error = "change.password.pwSameAsEmail"; 1.223 + else if (val1 && val1 == Weave.Service.identity.basicPassword) 1.224 + error = "change.password.pwSameAsPassword"; 1.225 + else if (val1 && val2) { 1.226 + if (val1 == val2 && val1.length >= Weave.MIN_PASS_LENGTH) 1.227 + valid = true; 1.228 + else if (val1.length < Weave.MIN_PASS_LENGTH) 1.229 + error = "change.password.tooShort"; 1.230 + else if (val1 != val2) 1.231 + error = "change.password.mismatch"; 1.232 + } 1.233 + let errorString = error ? Weave.Utils.getErrorString(error) : ""; 1.234 + return [valid, errorString]; 1.235 + } 1.236 +};