michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: // Equivalent to 0600 permissions; used for saved Sync Recovery Key. michael@0: // This constant can be replaced when the equivalent values are available to michael@0: // chrome JS; see Bug 433295 and Bug 757351. michael@0: const PERMISSIONS_RWUSR = 0x180; michael@0: michael@0: // Weave should always exist before before this file gets included. michael@0: let gSyncUtils = { michael@0: get bundle() { michael@0: delete this.bundle; michael@0: return this.bundle = Services.strings.createBundle("chrome://browser/locale/syncSetup.properties"); michael@0: }, michael@0: michael@0: get fxAccountsEnabled() { michael@0: let service = Components.classes["@mozilla.org/weave/service;1"] michael@0: .getService(Components.interfaces.nsISupports) michael@0: .wrappedJSObject; michael@0: return service.fxAccountsEnabled; michael@0: }, michael@0: michael@0: // opens in a new window if we're in a modal prefwindow world, in a new tab otherwise michael@0: _openLink: function (url) { michael@0: let thisDocEl = document.documentElement, michael@0: openerDocEl = window.opener && window.opener.document.documentElement; michael@0: if (thisDocEl.id == "accountSetup" && window.opener && michael@0: openerDocEl.id == "BrowserPreferences" && !openerDocEl.instantApply) michael@0: openUILinkIn(url, "window"); michael@0: else if (thisDocEl.id == "BrowserPreferences" && !thisDocEl.instantApply) michael@0: openUILinkIn(url, "window"); michael@0: else if (document.documentElement.id == "change-dialog") michael@0: Services.wm.getMostRecentWindow("navigator:browser") michael@0: .openUILinkIn(url, "tab"); michael@0: else michael@0: openUILinkIn(url, "tab"); michael@0: }, michael@0: michael@0: changeName: function changeName(input) { michael@0: // Make sure to update to a modified name, e.g., empty-string -> default michael@0: Weave.Service.clientsEngine.localName = input.value; michael@0: input.value = Weave.Service.clientsEngine.localName; michael@0: }, michael@0: michael@0: openChange: function openChange(type, duringSetup) { michael@0: // Just re-show the dialog if it's already open michael@0: let openedDialog = Services.wm.getMostRecentWindow("Sync:" + type); michael@0: if (openedDialog != null) { michael@0: openedDialog.focus(); michael@0: return; michael@0: } michael@0: michael@0: // Open up the change dialog michael@0: let changeXUL = "chrome://browser/content/sync/genericChange.xul"; michael@0: let changeOpt = "centerscreen,chrome,resizable=no"; michael@0: Services.ww.activeWindow.openDialog(changeXUL, "", changeOpt, michael@0: type, duringSetup); michael@0: }, michael@0: michael@0: changePassword: function () { michael@0: if (Weave.Utils.ensureMPUnlocked()) michael@0: this.openChange("ChangePassword"); michael@0: }, michael@0: michael@0: resetPassphrase: function (duringSetup) { michael@0: if (Weave.Utils.ensureMPUnlocked()) michael@0: this.openChange("ResetPassphrase", duringSetup); michael@0: }, michael@0: michael@0: updatePassphrase: function () { michael@0: if (Weave.Utils.ensureMPUnlocked()) michael@0: this.openChange("UpdatePassphrase"); michael@0: }, michael@0: michael@0: resetPassword: function () { michael@0: this._openLink(Weave.Service.pwResetURL); michael@0: }, michael@0: michael@0: openToS: function () { michael@0: let root = this.fxAccountsEnabled ? "fxa." : ""; michael@0: this._openLink(Weave.Svc.Prefs.get(root + "termsURL")); michael@0: }, michael@0: michael@0: openPrivacyPolicy: function () { michael@0: let root = this.fxAccountsEnabled ? "fxa." : ""; michael@0: this._openLink(Weave.Svc.Prefs.get(root + "privacyURL")); michael@0: }, michael@0: michael@0: openMPInfoPage: function (event) { michael@0: event.stopPropagation(); michael@0: let baseURL = Services.urlFormatter.formatURLPref("app.support.baseURL"); michael@0: this._openLink(baseURL + "sync-master-password"); michael@0: }, michael@0: michael@0: openFirstSyncProgressPage: function () { michael@0: this._openLink("about:sync-progress"); michael@0: }, michael@0: michael@0: /** michael@0: * Prepare an invisible iframe with the passphrase backup document. michael@0: * Used by both the print and saving methods. michael@0: * michael@0: * @param elid : ID of the form element containing the passphrase. michael@0: * @param callback : Function called once the iframe has loaded. michael@0: */ michael@0: _preparePPiframe: function(elid, callback) { michael@0: let pp = document.getElementById(elid).value; michael@0: michael@0: // Create an invisible iframe whose contents we can print. michael@0: let iframe = document.createElement("iframe"); michael@0: iframe.setAttribute("src", "chrome://browser/content/sync/key.xhtml"); michael@0: iframe.collapsed = true; michael@0: document.documentElement.appendChild(iframe); michael@0: iframe.contentWindow.addEventListener("load", function() { michael@0: iframe.contentWindow.removeEventListener("load", arguments.callee, false); michael@0: michael@0: // Insert the Sync Key into the page. michael@0: let el = iframe.contentDocument.getElementById("synckey"); michael@0: el.firstChild.nodeValue = pp; michael@0: michael@0: // Insert the TOS and Privacy Policy URLs into the page. michael@0: let termsURL = Weave.Svc.Prefs.get("termsURL"); michael@0: el = iframe.contentDocument.getElementById("tosLink"); michael@0: el.setAttribute("href", termsURL); michael@0: el.firstChild.nodeValue = termsURL; michael@0: michael@0: let privacyURL = Weave.Svc.Prefs.get("privacyURL"); michael@0: el = iframe.contentDocument.getElementById("ppLink"); michael@0: el.setAttribute("href", privacyURL); michael@0: el.firstChild.nodeValue = privacyURL; michael@0: michael@0: callback(iframe); michael@0: }, false); michael@0: }, michael@0: michael@0: /** michael@0: * Print passphrase backup document. michael@0: * michael@0: * @param elid : ID of the form element containing the passphrase. michael@0: */ michael@0: passphrasePrint: function(elid) { michael@0: this._preparePPiframe(elid, function(iframe) { michael@0: let webBrowserPrint = iframe.contentWindow michael@0: .QueryInterface(Ci.nsIInterfaceRequestor) michael@0: .getInterface(Ci.nsIWebBrowserPrint); michael@0: let printSettings = PrintUtils.getPrintSettings(); michael@0: michael@0: // Display no header/footer decoration except for the date. michael@0: printSettings.headerStrLeft michael@0: = printSettings.headerStrCenter michael@0: = printSettings.headerStrRight michael@0: = printSettings.footerStrLeft michael@0: = printSettings.footerStrCenter = ""; michael@0: printSettings.footerStrRight = "&D"; michael@0: michael@0: try { michael@0: webBrowserPrint.print(printSettings, null); michael@0: } catch (ex) { michael@0: // print()'s return codes are expressed as exceptions. Ignore. michael@0: } michael@0: }); michael@0: }, michael@0: michael@0: /** michael@0: * Save passphrase backup document to disk as HTML file. michael@0: * michael@0: * @param elid : ID of the form element containing the passphrase. michael@0: */ michael@0: passphraseSave: function(elid) { michael@0: let dialogTitle = this.bundle.GetStringFromName("save.recoverykey.title"); michael@0: let defaultSaveName = this.bundle.GetStringFromName("save.recoverykey.defaultfilename"); michael@0: this._preparePPiframe(elid, function(iframe) { michael@0: let fp = Cc["@mozilla.org/filepicker;1"].createInstance(Ci.nsIFilePicker); michael@0: let fpCallback = function fpCallback_done(aResult) { michael@0: if (aResult == Ci.nsIFilePicker.returnOK || michael@0: aResult == Ci.nsIFilePicker.returnReplace) { michael@0: let stream = Cc["@mozilla.org/network/file-output-stream;1"]. michael@0: createInstance(Ci.nsIFileOutputStream); michael@0: stream.init(fp.file, -1, PERMISSIONS_RWUSR, 0); michael@0: michael@0: let serializer = new XMLSerializer(); michael@0: let output = serializer.serializeToString(iframe.contentDocument); michael@0: output = output.replace(//, michael@0: ''); michael@0: output = Weave.Utils.encodeUTF8(output); michael@0: stream.write(output, output.length); michael@0: } michael@0: }; michael@0: michael@0: fp.init(window, dialogTitle, Ci.nsIFilePicker.modeSave); michael@0: fp.appendFilters(Ci.nsIFilePicker.filterHTML); michael@0: fp.defaultString = defaultSaveName; michael@0: fp.open(fpCallback); michael@0: return false; michael@0: }); michael@0: }, michael@0: michael@0: /** michael@0: * validatePassword michael@0: * michael@0: * @param el1 : the first textbox element in the form michael@0: * @param el2 : the second textbox element, if omitted it's an update form michael@0: * michael@0: * returns [valid, errorString] michael@0: */ michael@0: validatePassword: function (el1, el2) { michael@0: let valid = false; michael@0: let val1 = el1.value; michael@0: let val2 = el2 ? el2.value : ""; michael@0: let error = ""; michael@0: michael@0: if (!el2) michael@0: valid = val1.length >= Weave.MIN_PASS_LENGTH; michael@0: else if (val1 && val1 == Weave.Service.identity.username) michael@0: error = "change.password.pwSameAsUsername"; michael@0: else if (val1 && val1 == Weave.Service.identity.account) michael@0: error = "change.password.pwSameAsEmail"; michael@0: else if (val1 && val1 == Weave.Service.identity.basicPassword) michael@0: error = "change.password.pwSameAsPassword"; michael@0: else if (val1 && val2) { michael@0: if (val1 == val2 && val1.length >= Weave.MIN_PASS_LENGTH) michael@0: valid = true; michael@0: else if (val1.length < Weave.MIN_PASS_LENGTH) michael@0: error = "change.password.tooShort"; michael@0: else if (val1 != val2) michael@0: error = "change.password.mismatch"; michael@0: } michael@0: let errorString = error ? Weave.Utils.getErrorString(error) : ""; michael@0: return [valid, errorString]; michael@0: } michael@0: };