/* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is Weave. * * The Initial Developer of the Original Code is * Mozilla Foundation. * Portions created by the Initial Developer are Copyright (C) 2009 * the Initial Developer. All Rights Reserved. * * Contributor(s): * Edward Lee * Mike Connor * Paul O’Shannessy * Philipp von Weitershausen * * Alternatively, the contents of this file may be used under the terms of * either the GNU General Public License Version 2 or later (the "GPL"), or * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), * in which case the provisions of the GPL or the LGPL are applicable instead * of those above. If you wish to allow use of your version of this file only * under the terms of either the GPL or the LGPL, and not to allow others to * use your version of this file under the terms of the MPL, indicate your * decision by deleting the provisions above and replace them with the notice * and other provisions required by the GPL or the LGPL. If you do not delete * the provisions above, a recipient may use your version of this file under * the terms of any one of the MPL, the GPL or the LGPL. * * ***** END LICENSE BLOCK ***** */ // Weave should always exist before before this file gets included. let gSyncUtils = { get bundle() { delete this.bundle; return this.bundle = Services.strings.createBundle("chrome://browser/locale/syncSetup.properties"); }, // opens in a new window if we're in a modal prefwindow world, in a new tab otherwise _openLink: function (url) { let thisDocEl = document.documentElement, openerDocEl = window.opener && window.opener.document.documentElement; if (thisDocEl.id == "accountSetup" && window.opener && openerDocEl.id == "BrowserPreferences" && !openerDocEl.instantApply) openUILinkIn(url, "window"); else if (thisDocEl.id == "BrowserPreferences" && !thisDocEl.instantApply) openUILinkIn(url, "window"); else openUILinkIn(url, "tab"); }, changeName: function changeName(input) { // Make sure to update to a modified name, e.g., empty-string -> default Weave.Clients.localName = input.value; input.value = Weave.Clients.localName; }, openChange: function openChange(type) { // Just re-show the dialog if it's already open let openedDialog = Weave.Svc.WinMediator.getMostRecentWindow("Sync:" + type); if (openedDialog != null) { openedDialog.focus(); return; } // Open up the change dialog let changeXUL = "chrome://browser/content/syncGenericChange.xul"; let changeOpt = "centerscreen,chrome,dialog,modal,resizable=no"; Weave.Svc.WinWatcher.activeWindow.openDialog(changeXUL, "", changeOpt, type); }, changePassword: function () { this.openChange("ChangePassword"); }, resetPassphrase: function () { this.openChange("ResetPassphrase"); }, updatePassphrase: function () { this.openChange("UpdatePassphrase"); }, resetPassword: function () { this._openLink(Weave.Service.pwResetURL); }, openToS: function () { this._openLink(Weave.Svc.Prefs.get("termsURL")); }, openPrivacyPolicy: function () { this._openLink(Weave.Svc.Prefs.get("privacyURL")); }, // xxxmpc - fix domain before 1.3 final (bug 583652) _baseURL: "http://www.mozilla.com/firefox/sync/", openFirstClientFirstrun: function () { let url = this._baseURL + "firstrun.html"; this._openLink(url); }, openAddedClientFirstrun: function () { let url = this._baseURL + "secondrun.html"; this._openLink(url); }, /** * Generate 20 random characters a-z */ generatePassphrase: function() { let rng = Cc["@mozilla.org/security/random-generator;1"] .createInstance(Ci.nsIRandomGenerator); let bytes = rng.generateRandomBytes(20); return [String.fromCharCode(97 + Math.floor(byte * 26 / 256)) for each (byte in bytes)].join(""); }, /** * Hyphenate a 20 character passphrase in 4 groups of 5. */ hyphenatePassphrase: function(passphrase) { return passphrase.slice(0, 5) + '-' + passphrase.slice(5, 10) + '-' + passphrase.slice(10, 15) + '-' + passphrase.slice(15, 20); }, /** * Remove hyphens as inserted by hyphenatePassphrase(). */ normalizePassphrase: function(pp) { if (pp.length == 23 && pp[5] == '-' && pp[11] == '-' && pp[17] == '-') return pp.slice(0, 5) + pp.slice(6, 11) + pp.slice(12, 17) + pp.slice(18, 23); return pp; }, /** * Trigger the mailto protocol handler to send a passphrase backup email. * * @param elid : ID of the form element containing the passphrase. */ passphraseEmail: function(elid) { let pp = document.getElementById(elid).value; let subject = this.bundle.GetStringFromName("email.syncKey.subject"); let label = this.bundle.formatStringFromName("email.syncKey.label", [pp], 1); let body = "&body=" + label + "%0A%0A" + this.bundle.GetStringFromName("email.syncKey.description") + "%0A%0A" + this.bundle.GetStringFromName("email.keepItSecret.label") + this.bundle.GetStringFromName("email.keepItSecret.description") + "%0A%0A" + this.bundle.GetStringFromName("email.keepItSafe.label") + this.bundle.GetStringFromName("email.keepItSafe.description") + "%0A%0A" + this.bundle.GetStringFromName("email.findOutMore.label"); let uri = Weave.Utils.makeURI("mailto:?subject=" + subject + body); let protoSvc = Cc["@mozilla.org/uriloader/external-protocol-service;1"] .getService(Ci.nsIExternalProtocolService); protoSvc.loadURI(uri); }, /** * Prepare an invisible iframe with the passphrase backup document. * Used by both the print and saving methods. * * @param elid : ID of the form element containing the passphrase. * @param callback : Function called once the iframe has loaded. */ _preparePPiframe: function(elid, callback) { let pp = document.getElementById(elid).value; // Create an invisible iframe whose contents we can print. let iframe = document.createElement("iframe"); iframe.setAttribute("src", "chrome://browser/content/syncKey.xhtml"); iframe.collapsed = true; document.documentElement.appendChild(iframe); iframe.contentWindow.addEventListener("load", function() { iframe.contentWindow.removeEventListener("load", arguments.callee, false); // Insert the Sync Key into the page. let el = iframe.contentDocument.getElementById("synckey"); el.firstChild.nodeValue = pp; // Insert the TOS and Privacy Policy URLs into the page. let termsURL = Weave.Svc.Prefs.get("termsURL"); el = iframe.contentDocument.getElementById("tosLink"); el.setAttribute("href", termsURL); el.firstChild.nodeValue = termsURL; let privacyURL = Weave.Svc.Prefs.get("privacyURL"); el = iframe.contentDocument.getElementById("ppLink"); el.setAttribute("href", privacyURL); el.firstChild.nodeValue = privacyURL; callback(iframe); }, false); }, /** * Print passphrase backup document. * * @param elid : ID of the form element containing the passphrase. */ passphrasePrint: function(elid) { this._preparePPiframe(elid, function(iframe) { let webBrowserPrint = iframe.contentWindow .QueryInterface(Ci.nsIInterfaceRequestor) .getInterface(Ci.nsIWebBrowserPrint); let printSettings = PrintUtils.getPrintSettings(); // Display no header/footer decoration except for the date. printSettings.headerStrLeft = printSettings.headerStrCenter = printSettings.headerStrRight = printSettings.footerStrLeft = printSettings.footerStrCenter = ""; printSettings.footerStrRight = "&D"; try { webBrowserPrint.print(printSettings, null); } catch (ex) { // print()'s return codes are expressed as exceptions. Ignore. } }); }, /** * Save passphrase backup document to disk as HTML file. * * @param elid : ID of the form element containing the passphrase. */ passphraseSave: function(elid) { let dialogTitle = this.bundle.GetStringFromName("save.synckey.title"); this._preparePPiframe(elid, function(iframe) { let filepicker = Cc["@mozilla.org/filepicker;1"] .createInstance(Ci.nsIFilePicker); filepicker.init(window, dialogTitle, Ci.nsIFilePicker.modeSave); filepicker.appendFilters(Ci.nsIFilePicker.filterHTML); filepicker.defaultString = "Firefox Sync Key.html"; let rv = filepicker.show(); if (rv == Ci.nsIFilePicker.returnOK || rv == Ci.nsIFilePicker.returnReplace) { let stream = Cc["@mozilla.org/network/file-output-stream;1"] .createInstance(Ci.nsIFileOutputStream); stream.init(filepicker.file, -1, -1, 0); let serializer = new XMLSerializer(); let output = serializer.serializeToString(iframe.contentDocument); output = output.replace(//, ''); output = Weave.Utils.encodeUTF8(output); stream.write(output, output.length); } return false; }); }, /** * validatePassword * * @param el1 : the first textbox element in the form * @param el2 : the second textbox element, if omitted it's an update form * * returns [valid, errorString] */ validatePassword: function (el1, el2) { let valid = false; let val1 = el1.value; let val2 = el2 ? el2.value : ""; let error = ""; if (!el2) valid = val1.length >= Weave.MIN_PASS_LENGTH; else if (val1 && val1 == Weave.Service.username) error = "change.password.pwSameAsUsername"; else if (val1 && val1 == Weave.Service.account) error = "change.password.pwSameAsEmail"; else if (val1 && val1 == Weave.Service.password) error = "change.password.pwSameAsPassword"; else if (val1 && val1 == Weave.Service.passphrase) error = "change.password.pwSameAsSyncKey"; else if (val1 && val2) { if (val1 == val2 && val1.length >= Weave.MIN_PASS_LENGTH) valid = true; else if (val1.length < Weave.MIN_PASS_LENGTH) error = "change.password.tooShort"; else if (val1 != val2) error = "change.password.mismatch"; } let errorString = error ? Weave.Utils.getErrorString(error) : ""; return [valid, errorString]; }, /** * validatePassphrase * * @param el : the textbox element * @param change : indicate whether this signifies a passphrase change * * returns [valid, errorString] */ validatePassphrase: function (el, change) { let valid = false; let val = el.value; let error = ""; if (val == Weave.Service.username) error = "change.synckey.sameAsUsername"; else if (val == Weave.Service.account) error = "change.synckey.sameAsEmail"; else if (val == Weave.Service.password) error = "change.synckey.sameAsPassword"; else if (change && val == Weave.Service.passphrase) error = "change.synckey.sameAsSyncKey"; else if (val.length < Weave.MIN_PP_LENGTH) error = "change.synckey.tooShort"; else valid = true; let errorString = error ? Weave.Utils.getErrorString(error) : ""; return [valid, errorString]; } }