1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072 |
- /* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
- var Ci = Components.interfaces;
- var Cc = Components.classes;
- var Cr = Components.results;
- var Cu = Components.utils;
- // page consts
- const PAIR_PAGE = 0;
- const INTRO_PAGE = 1;
- const NEW_ACCOUNT_START_PAGE = 2;
- const EXISTING_ACCOUNT_CONNECT_PAGE = 3;
- const EXISTING_ACCOUNT_LOGIN_PAGE = 4;
- const OPTIONS_PAGE = 5;
- const OPTIONS_CONFIRM_PAGE = 6;
- // Broader than we'd like, but after this changed from api-secure.recaptcha.net
- // we had no choice. At least we only do this for the duration of setup.
- // See discussion in Bugs 508112 and 653307.
- const RECAPTCHA_DOMAIN = "https://www.google.com";
- const PIN_PART_LENGTH = 4;
- Cu.import("resource://services-sync/main.js");
- Cu.import("resource://gre/modules/XPCOMUtils.jsm");
- Cu.import("resource://gre/modules/Services.jsm");
- Cu.import("resource://gre/modules/PlacesUtils.jsm");
- Cu.import("resource://gre/modules/PluralForm.jsm");
- function setVisibility(element, visible) {
- element.style.visibility = visible ? "visible" : "hidden";
- }
- var gSyncSetup = {
- QueryInterface: XPCOMUtils.generateQI([Ci.nsISupports,
- Ci.nsIWebProgressListener,
- Ci.nsISupportsWeakReference]),
- captchaBrowser: null,
- wizard: null,
- _disabledSites: [],
- status: {
- password: false,
- email: false,
- server: false
- },
- get _remoteSites() [Weave.Service.serverURL, RECAPTCHA_DOMAIN],
- get _usingMainServers() {
- if (this._settingUpNew)
- return document.getElementById("server").selectedIndex == 0;
- return document.getElementById("existingServer").selectedIndex == 0;
- },
- init: function() {
- let obs = [
- ["weave:service:change-passphrase", "onResetPassphrase"],
- ["weave:service:login:start", "onLoginStart"],
- ["weave:service:login:error", "onLoginEnd"],
- ["weave:service:login:finish", "onLoginEnd"]];
- // Add the observers now and remove them on unload
- let self = this;
- let addRem = function(add) {
- obs.forEach(function([topic, func]) {
- //XXXzpao This should use Services.obs.* but Weave's Obs does nice handling
- // of `this`. Fix in a followup. (bug 583347)
- if (add)
- Weave.Svc.Obs.add(topic, self[func], self);
- else
- Weave.Svc.Obs.remove(topic, self[func], self);
- });
- };
- addRem(true);
- window.addEventListener("unload", function() addRem(false), false);
- window.setTimeout(function() {
- // Force Service to be loaded so that engines are registered.
- // See Bug 670082.
- Weave.Service;
- }, 0);
- this.captchaBrowser = document.getElementById("captcha");
- this.wizardType = null;
- if (window.arguments && window.arguments[0]) {
- this.wizardType = window.arguments[0];
- }
- switch (this.wizardType) {
- case null:
- this.wizard.pageIndex = INTRO_PAGE;
- // Fall through!
- case "pair":
- this.captchaBrowser.addProgressListener(this);
- Weave.Svc.Prefs.set("firstSync", "notReady");
- break;
- case "reset":
- this._resettingSync = true;
- this.wizard.pageIndex = OPTIONS_PAGE;
- break;
- }
- this.wizard.getButton("extra1").label =
- this._stringBundle.GetStringFromName("button.syncOptions.label");
- // Remember these values because the options pages change them temporarily.
- this._nextButtonLabel = this.wizard.getButton("next").label;
- this._nextButtonAccesskey = this.wizard.getButton("next")
- .getAttribute("accesskey");
- this._backButtonLabel = this.wizard.getButton("back").label;
- this._backButtonAccesskey = this.wizard.getButton("back")
- .getAttribute("accesskey");
- },
- startNewAccountSetup: function() {
- if (!Weave.Utils.ensureMPUnlocked())
- return false;
- this._settingUpNew = true;
- this.wizard.pageIndex = NEW_ACCOUNT_START_PAGE;
- },
- useExistingAccount: function() {
- if (!Weave.Utils.ensureMPUnlocked())
- return false;
- this._settingUpNew = false;
- if (this.wizardType == "pair") {
- // We're already pairing, so there's no point in pairing again.
- // Go straight to the manual login page.
- this.wizard.pageIndex = EXISTING_ACCOUNT_LOGIN_PAGE;
- } else {
- this.wizard.pageIndex = EXISTING_ACCOUNT_CONNECT_PAGE;
- }
- },
- resetPassphrase: function() {
- // Apply the existing form fields so that
- // Weave.Service.changePassphrase() has the necessary credentials.
- Weave.Service.identity.account = document.getElementById("existingAccountName").value;
- Weave.Service.identity.basicPassword = document.getElementById("existingPassword").value;
- // Generate a new passphrase so that Weave.Service.login() will
- // actually do something.
- let passphrase = Weave.Utils.generatePassphrase();
- Weave.Service.identity.syncKey = passphrase;
- // Only open the dialog if username + password are actually correct.
- Weave.Service.login();
- if ([Weave.LOGIN_FAILED_INVALID_PASSPHRASE,
- Weave.LOGIN_FAILED_NO_PASSPHRASE,
- Weave.LOGIN_SUCCEEDED].indexOf(Weave.Status.login) == -1) {
- return;
- }
- // Hide any errors about the passphrase, we know it's not right.
- let feedback = document.getElementById("existingPassphraseFeedbackRow");
- feedback.hidden = true;
- let el = document.getElementById("existingPassphrase");
- el.value = Weave.Utils.hyphenatePassphrase(passphrase);
- // changePassphrase() will sync, make sure we set the "firstSync" pref
- // according to the user's pref.
- Weave.Svc.Prefs.reset("firstSync");
- this.setupInitialSync();
- gSyncUtils.resetPassphrase(true);
- },
- onResetPassphrase: function() {
- document.getElementById("existingPassphrase").value =
- Weave.Utils.hyphenatePassphrase(Weave.Service.identity.syncKey);
- this.checkFields();
- this.wizard.advance();
- },
- onLoginStart: function() {
- this.toggleLoginFeedback(false);
- },
- onLoginEnd: function() {
- this.toggleLoginFeedback(true);
- },
- sendCredentialsAfterSync: function() {
- let send = function() {
- Services.obs.removeObserver("weave:service:sync:finish", send);
- Services.obs.removeObserver("weave:service:sync:error", send);
- let credentials = {account: Weave.Service.identity.account,
- password: Weave.Service.identity.basicPassword,
- synckey: Weave.Service.identity.syncKey,
- serverURL: Weave.Service.serverURL};
- this._jpakeclient.sendAndComplete(credentials);
- }.bind(this);
- Services.obs.addObserver("weave:service:sync:finish", send, false);
- Services.obs.addObserver("weave:service:sync:error", send, false);
- },
- toggleLoginFeedback: function(stop) {
- document.getElementById("login-throbber").hidden = stop;
- let password = document.getElementById("existingPasswordFeedbackRow");
- let server = document.getElementById("existingServerFeedbackRow");
- let passphrase = document.getElementById("existingPassphraseFeedbackRow");
- if (!stop || (Weave.Status.login == Weave.LOGIN_SUCCEEDED)) {
- password.hidden = server.hidden = passphrase.hidden = true;
- return;
- }
- let feedback;
- switch (Weave.Status.login) {
- case Weave.LOGIN_FAILED_NETWORK_ERROR:
- case Weave.LOGIN_FAILED_SERVER_ERROR:
- feedback = server;
- break;
- case Weave.LOGIN_FAILED_LOGIN_REJECTED:
- case Weave.LOGIN_FAILED_NO_USERNAME:
- case Weave.LOGIN_FAILED_NO_PASSWORD:
- feedback = password;
- break;
- case Weave.LOGIN_FAILED_INVALID_PASSPHRASE:
- feedback = passphrase;
- break;
- }
- this._setFeedbackMessage(feedback, false, Weave.Status.login);
- },
- setupInitialSync: function() {
- let action = document.getElementById("mergeChoiceRadio").selectedItem.id;
- switch (action) {
- case "resetClient":
- // if we're not resetting sync, we don't need to explicitly
- // call resetClient
- if (!this._resettingSync)
- return;
- // otherwise, fall through
- case "wipeClient":
- case "wipeRemote":
- Weave.Svc.Prefs.set("firstSync", action);
- break;
- }
- },
- // fun with validation!
- checkFields: function() {
- this.wizard.canAdvance = this.readyToAdvance();
- },
- readyToAdvance: function() {
- switch (this.wizard.pageIndex) {
- case INTRO_PAGE:
- return false;
- case NEW_ACCOUNT_START_PAGE:
- for (let i in this.status) {
- if (!this.status[i])
- return false;
- }
- if (this._usingMainServers)
- return document.getElementById("tos").checked;
- return true;
- case EXISTING_ACCOUNT_LOGIN_PAGE:
- let hasUser = document.getElementById("existingAccountName").value != "";
- let hasPass = document.getElementById("existingPassword").value != "";
- let hasKey = document.getElementById("existingPassphrase").value != "";
- if (hasUser && hasPass && hasKey) {
- if (this._usingMainServers)
- return true;
- if (this._validateServer(document.getElementById("existingServer"))) {
- return true;
- }
- }
- return false;
- }
- // Default, e.g. wizard's special page -1 etc.
- return true;
- },
- onPINInput: function onPINInput(textbox) {
- if (textbox && textbox.value.length == PIN_PART_LENGTH) {
- this.nextFocusEl[textbox.id].focus();
- }
- this.wizard.canAdvance = (this.pin1.value.length == PIN_PART_LENGTH &&
- this.pin2.value.length == PIN_PART_LENGTH &&
- this.pin3.value.length == PIN_PART_LENGTH);
- },
- onEmailInput: function() {
- // Check account validity when the user stops typing for 1 second.
- if (this._checkAccountTimer)
- window.clearTimeout(this._checkAccountTimer);
- this._checkAccountTimer = window.setTimeout(function() {
- gSyncSetup.checkAccount();
- }, 1000);
- },
- checkAccount: function() {
- delete this._checkAccountTimer;
- let value = Weave.Utils.normalizeAccount(
- document.getElementById("weaveEmail").value);
- if (!value) {
- this.status.email = false;
- this.checkFields();
- return;
- }
- let re = /^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
- let feedback = document.getElementById("emailFeedbackRow");
- let valid = re.test(value);
- let str = "";
- if (!valid) {
- str = "invalidEmail.label";
- } else {
- let availCheck = Weave.Service.checkAccount(value);
- valid = availCheck == "available";
- if (!valid) {
- if (availCheck == "notAvailable")
- str = "usernameNotAvailable.label";
- else
- str = availCheck;
- }
- }
- this._setFeedbackMessage(feedback, valid, str);
- this.status.email = valid;
- if (valid)
- Weave.Service.identity.account = value;
- this.checkFields();
- },
- onPasswordChange: function() {
- let password = document.getElementById("weavePassword");
- let pwconfirm = document.getElementById("weavePasswordConfirm");
- let [valid, errorString] = gSyncUtils.validatePassword(password, pwconfirm);
- let feedback = document.getElementById("passwordFeedbackRow");
- this._setFeedback(feedback, valid, errorString);
- this.status.password = valid;
- this.checkFields();
- },
- onPageShow: function() {
- switch (this.wizard.pageIndex) {
- case PAIR_PAGE:
- this.wizard.getButton("back").hidden = true;
- this.wizard.getButton("extra1").hidden = true;
- this.onPINInput();
- this.pin1.focus();
- break;
- case INTRO_PAGE:
- // We may not need the captcha in the Existing Account branch of the
- // wizard. However, we want to preload it to avoid any flickering while
- // the Create Account page is shown.
- this.loadCaptcha();
- this.wizard.getButton("next").hidden = true;
- this.wizard.getButton("back").hidden = true;
- this.wizard.getButton("extra1").hidden = true;
- this.checkFields();
- break;
- case NEW_ACCOUNT_START_PAGE:
- this.wizard.getButton("extra1").hidden = false;
- this.wizard.getButton("next").hidden = false;
- this.wizard.getButton("back").hidden = false;
- this.onServerCommand();
- this.wizard.canRewind = true;
- this.checkFields();
- break;
- case EXISTING_ACCOUNT_CONNECT_PAGE:
- Weave.Svc.Prefs.set("firstSync", "existingAccount");
- this.wizard.getButton("next").hidden = false;
- this.wizard.getButton("back").hidden = false;
- this.wizard.getButton("extra1").hidden = false;
- this.wizard.canAdvance = false;
- this.wizard.canRewind = true;
- this.startEasySetup();
- break;
- case EXISTING_ACCOUNT_LOGIN_PAGE:
- this.wizard.getButton("next").hidden = false;
- this.wizard.getButton("back").hidden = false;
- this.wizard.getButton("extra1").hidden = false;
- this.wizard.canRewind = true;
- this.checkFields();
- break;
- case OPTIONS_PAGE:
- this.wizard.canRewind = false;
- this.wizard.canAdvance = true;
- if (!this._resettingSync) {
- this.wizard.getButton("next").label =
- this._stringBundle.GetStringFromName("button.syncOptionsDone.label");
- this.wizard.getButton("next").removeAttribute("accesskey");
- }
- this.wizard.getButton("next").hidden = false;
- this.wizard.getButton("back").hidden = true;
- this.wizard.getButton("cancel").hidden = !this._resettingSync;
- this.wizard.getButton("extra1").hidden = true;
- document.getElementById("syncComputerName").value = Weave.Service.clientsEngine.localName;
- document.getElementById("syncOptions").collapsed = this._resettingSync;
- document.getElementById("mergeOptions").collapsed = this._settingUpNew;
- break;
- case OPTIONS_CONFIRM_PAGE:
- this.wizard.canRewind = true;
- this.wizard.canAdvance = true;
- this.wizard.getButton("back").label =
- this._stringBundle.GetStringFromName("button.syncOptionsCancel.label");
- this.wizard.getButton("back").removeAttribute("accesskey");
- this.wizard.getButton("back").hidden = this._resettingSync;
- this.wizard.getButton("next").hidden = false;
- this.wizard.getButton("finish").hidden = true;
- break;
- }
- },
- onWizardAdvance: function() {
- // Check pageIndex so we don't prompt before the Sync setup wizard appears.
- // This is a fallback in case the Master Password gets locked mid-wizard.
- if ((this.wizard.pageIndex >= 0) &&
- !Weave.Utils.ensureMPUnlocked()) {
- return false;
- }
- switch (this.wizard.pageIndex) {
- case PAIR_PAGE:
- this.startPairing();
- return false;
- case NEW_ACCOUNT_START_PAGE:
- // If the user selects Next (e.g. by hitting enter) when we haven't
- // executed the delayed checks yet, execute them immediately.
- if (this._checkAccountTimer) {
- this.checkAccount();
- }
- if (this._checkServerTimer) {
- this.checkServer();
- }
- if (!this.wizard.canAdvance) {
- return false;
- }
- let doc = this.captchaBrowser.contentDocument;
- let getField = function getField(field) {
- let node = doc.getElementById("recaptcha_" + field + "_field");
- return node && node.value;
- };
- // Display throbber
- let feedback = document.getElementById("captchaFeedback");
- let image = feedback.firstChild;
- let label = image.nextSibling;
- image.setAttribute("status", "active");
- label.value = this._stringBundle.GetStringFromName("verifying.label");
- setVisibility(feedback, true);
- let password = document.getElementById("weavePassword").value;
- let email = Weave.Utils.normalizeAccount(
- document.getElementById("weaveEmail").value);
- let challenge = getField("challenge");
- let response = getField("response");
- let error = Weave.Service.createAccount(email, password,
- challenge, response);
- if (error == null) {
- Weave.Service.identity.account = email;
- Weave.Service.identity.basicPassword = password;
- Weave.Service.identity.syncKey = Weave.Utils.generatePassphrase();
- this._handleNoScript(false);
- Weave.Svc.Prefs.set("firstSync", "newAccount");
- this.wizardFinish();
- return false;
- }
- image.setAttribute("status", "error");
- label.value = Weave.Utils.getErrorString(error);
- return false;
- case EXISTING_ACCOUNT_LOGIN_PAGE:
- Weave.Service.identity.account = Weave.Utils.normalizeAccount(
- document.getElementById("existingAccountName").value);
- Weave.Service.identity.basicPassword =
- document.getElementById("existingPassword").value;
- let pp = document.getElementById("existingPassphrase").value;
- Weave.Service.identity.syncKey = Weave.Utils.normalizePassphrase(pp);
- if (Weave.Service.login()) {
- this.wizardFinish();
- }
- return false;
- case OPTIONS_PAGE:
- let desc = document.getElementById("mergeChoiceRadio").selectedIndex;
- // No confirmation needed on new account setup or merge option
- // with existing account.
- if (this._settingUpNew || (!this._resettingSync && desc == 0))
- return this.returnFromOptions();
- return this._handleChoice();
- case OPTIONS_CONFIRM_PAGE:
- if (this._resettingSync) {
- this.wizardFinish();
- return false;
- }
- return this.returnFromOptions();
- }
- return true;
- },
- onWizardBack: function() {
- switch (this.wizard.pageIndex) {
- case NEW_ACCOUNT_START_PAGE:
- case EXISTING_ACCOUNT_LOGIN_PAGE:
- this.wizard.pageIndex = INTRO_PAGE;
- return false;
- case EXISTING_ACCOUNT_CONNECT_PAGE:
- this.abortEasySetup();
- this.wizard.pageIndex = INTRO_PAGE;
- return false;
- case EXISTING_ACCOUNT_LOGIN_PAGE:
- // If we were already pairing on entry, we went straight to the manual
- // login page. If subsequently we go back, return to the page that lets
- // us choose whether we already have an account.
- if (this.wizardType == "pair") {
- this.wizard.pageIndex = INTRO_PAGE;
- return false;
- }
- return true;
- case OPTIONS_CONFIRM_PAGE:
- // Backing up from the confirmation page = resetting first sync to merge.
- document.getElementById("mergeChoiceRadio").selectedIndex = 0;
- return this.returnFromOptions();
- }
- return true;
- },
- wizardFinish: function() {
- this.setupInitialSync();
- if (this.wizardType == "pair") {
- this.completePairing();
- }
- if (!this._resettingSync) {
- function isChecked(element) {
- return document.getElementById(element).hasAttribute("checked");
- }
- let prefs = ["engine.bookmarks", "engine.passwords", "engine.history",
- "engine.tabs", "engine.prefs", "engine.addons"];
- for (let i = 0;i < prefs.length;i++) {
- Weave.Svc.Prefs.set(prefs[i], isChecked(prefs[i]));
- }
-
- // XXX: Addons syncing is currently not operational;
- // Make doubly-sure to always disable addons syncing pref
- Weave.Svc.Prefs.set("engine.addons", false);
-
- this._handleNoScript(false);
- if (Weave.Svc.Prefs.get("firstSync", "") == "notReady")
- Weave.Svc.Prefs.reset("firstSync");
- Weave.Service.persistLogin();
- Weave.Svc.Obs.notify("weave:service:setup-complete");
- gSyncUtils.openFirstSyncProgressPage();
- }
- Weave.Utils.nextTick(Weave.Service.sync, Weave.Service);
- window.close();
- },
- onWizardCancel: function() {
- if (this._resettingSync)
- return;
- this.abortEasySetup();
- this._handleNoScript(false);
- Weave.Service.startOver();
- },
- onSyncOptions: function() {
- this._beforeOptionsPage = this.wizard.pageIndex;
- this.wizard.pageIndex = OPTIONS_PAGE;
- },
- returnFromOptions: function() {
- this.wizard.getButton("next").label = this._nextButtonLabel;
- this.wizard.getButton("next").setAttribute("accesskey",
- this._nextButtonAccesskey);
- this.wizard.getButton("back").label = this._backButtonLabel;
- this.wizard.getButton("back").setAttribute("accesskey",
- this._backButtonAccesskey);
- this.wizard.getButton("cancel").hidden = false;
- this.wizard.getButton("extra1").hidden = false;
- this.wizard.pageIndex = this._beforeOptionsPage;
- return false;
- },
- startPairing: function() {
- this.pairDeviceErrorRow.hidden = true;
- // When onAbort is called, Weave may already be gone.
- const JPAKE_ERROR_USERABORT = Weave.JPAKE_ERROR_USERABORT;
- let self = this;
- let jpakeclient = this._jpakeclient = new Weave.JPAKEClient({
- onPaired: function onPaired() {
- self.wizard.pageIndex = INTRO_PAGE;
- },
- onComplete: function() {
- // This method will never be called since SendCredentialsController
- // will take over after the wizard completes.
- },
- onAbort: function(error) {
- delete self._jpakeclient;
- // Aborted by user, ignore. The window is almost certainly going to close
- // or is already closed.
- if (error == JPAKE_ERROR_USERABORT) {
- return;
- }
- self.pairDeviceErrorRow.hidden = false;
- self.pairDeviceThrobber.hidden = true;
- self.pin1.value = self.pin2.value = self.pin3.value = "";
- self.pin1.disabled = self.pin2.disabled = self.pin3.disabled = false;
- if (self.wizard.pageIndex == PAIR_PAGE) {
- self.pin1.focus();
- }
- }
- });
- this.pairDeviceThrobber.hidden = false;
- this.pin1.disabled = this.pin2.disabled = this.pin3.disabled = true;
- this.wizard.canAdvance = false;
- let pin = this.pin1.value + this.pin2.value + this.pin3.value;
- let expectDelay = true;
- jpakeclient.pairWithPIN(pin, expectDelay);
- },
- completePairing: function() {
- if (!this._jpakeclient) {
- // The channel was aborted while we were setting up the account
- // locally. XXX TODO should we do anything here, e.g. tell
- // the user on the last wizard page that it's ok, they just
- // have to pair again?
- return;
- }
- let controller = new Weave.SendCredentialsController(this._jpakeclient,
- Weave.Service);
- this._jpakeclient.controller = controller;
- },
- startEasySetup: function() {
- // Don't do anything if we have a client already (e.g. we went to
- // Sync Options and just came back).
- if (this._jpakeclient)
- return;
- // When onAbort is called, Weave may already be gone
- const JPAKE_ERROR_USERABORT = Weave.JPAKE_ERROR_USERABORT;
- let self = this;
- this._jpakeclient = new Weave.JPAKEClient({
- displayPIN: function(pin) {
- document.getElementById("easySetupPIN1").value = pin.slice(0, 4);
- document.getElementById("easySetupPIN2").value = pin.slice(4, 8);
- document.getElementById("easySetupPIN3").value = pin.slice(8);
- },
- onPairingStart: function() {},
- onComplete: function(credentials) {
- Weave.Service.identity.account = credentials.account;
- Weave.Service.identity.basicPassword = credentials.password;
- Weave.Service.identity.syncKey = credentials.synckey;
- Weave.Service.serverURL = credentials.serverURL;
- gSyncSetup.wizardFinish();
- },
- onAbort: function(error) {
- delete self._jpakeclient;
- // Ignore if wizard is aborted.
- if (error == JPAKE_ERROR_USERABORT)
- return;
- // Automatically go to manual setup if we couldn't acquire a channel.
- if (error == Weave.JPAKE_ERROR_CHANNEL) {
- self.wizard.pageIndex = EXISTING_ACCOUNT_LOGIN_PAGE;
- return;
- }
- // Restart on all other errors.
- self.startEasySetup();
- }
- });
- this._jpakeclient.receiveNoPIN();
- },
- abortEasySetup: function() {
- document.getElementById("easySetupPIN1").value = "";
- document.getElementById("easySetupPIN2").value = "";
- document.getElementById("easySetupPIN3").value = "";
- if (!this._jpakeclient)
- return;
- this._jpakeclient.abort();
- delete this._jpakeclient;
- },
- manualSetup: function() {
- this.abortEasySetup();
- this.wizard.pageIndex = EXISTING_ACCOUNT_LOGIN_PAGE;
- },
- // _handleNoScript is needed because it blocks the captcha. So we temporarily
- // allow the necessary sites so that we can verify the user is in fact a human.
- // This was done with the help of Giorgio (NoScript author). See bug 508112.
- _handleNoScript: function(addExceptions) {
- // if NoScript isn't installed, or is disabled, bail out.
- let ns = Cc["@maone.net/noscript-service;1"];
- if (ns == null)
- return;
- ns = ns.getService().wrappedJSObject;
- if (addExceptions) {
- this._remoteSites.forEach(function(site) {
- site = ns.getSite(site);
- if (!ns.isJSEnabled(site)) {
- this._disabledSites.push(site); // save status
- ns.setJSEnabled(site, true); // allow site
- }
- }, this);
- }
- else {
- this._disabledSites.forEach(function(site) {
- ns.setJSEnabled(site, false);
- });
- this._disabledSites = [];
- }
- },
- onExistingServerCommand: function() {
- let control = document.getElementById("existingServer");
- if (control.selectedIndex == 0) {
- control.removeAttribute("editable");
- Weave.Svc.Prefs.reset("serverURL");
- } else {
- control.setAttribute("editable", "true");
- // Force a style flush to ensure that the binding is attached.
- control.clientTop;
- control.value = "";
- control.inputField.focus();
- }
- document.getElementById("existingServerFeedbackRow").hidden = true;
- this.checkFields();
- },
- onExistingServerInput: function() {
- // Check custom server validity when the user stops typing for 1 second.
- if (this._existingServerTimer)
- window.clearTimeout(this._existingServerTimer);
- this._existingServerTimer = window.setTimeout(function() {
- gSyncSetup.checkFields();
- }, 1000);
- },
- onServerCommand: function() {
- setVisibility(document.getElementById("TOSRow"), this._usingMainServers);
- let control = document.getElementById("server");
- if (!this._usingMainServers) {
- control.setAttribute("editable", "true");
- // Force a style flush to ensure that the binding is attached.
- control.clientTop;
- control.value = "";
- control.inputField.focus();
- // checkServer() will call checkAccount() and checkFields().
- this.checkServer();
- return;
- }
- control.removeAttribute("editable");
- Weave.Svc.Prefs.reset("serverURL");
- if (this._settingUpNew) {
- this.loadCaptcha();
- }
- this.checkAccount();
- this.status.server = true;
- document.getElementById("serverFeedbackRow").hidden = true;
- this.checkFields();
- },
- onServerInput: function() {
- // Check custom server validity when the user stops typing for 1 second.
- if (this._checkServerTimer)
- window.clearTimeout(this._checkServerTimer);
- this._checkServerTimer = window.setTimeout(function() {
- gSyncSetup.checkServer();
- }, 1000);
- },
- checkServer: function() {
- delete this._checkServerTimer;
- let el = document.getElementById("server");
- let valid = false;
- let feedback = document.getElementById("serverFeedbackRow");
- let str = "";
- if (el.value) {
- valid = this._validateServer(el);
- let str = valid ? "" : "serverInvalid.label";
- this._setFeedbackMessage(feedback, valid, str);
- }
- else
- this._setFeedbackMessage(feedback, true);
- // Recheck account against the new server.
- if (valid)
- this.checkAccount();
- this.status.server = valid;
- this.checkFields();
- },
- _validateServer: function(element) {
- let valid = false;
- let val = element.value;
- if (!val)
- return false;
- let uri = Weave.Utils.makeURI(val);
- if (!uri)
- uri = Weave.Utils.makeURI("https://" + val);
- if (uri && this._settingUpNew) {
- function isValid(uri) {
- Weave.Service.serverURL = uri.spec;
- let check = Weave.Service.checkAccount("a");
- return (check == "available" || check == "notAvailable");
- }
- if (uri.schemeIs("http")) {
- uri.scheme = "https";
- if (isValid(uri))
- valid = true;
- else
- // setting the scheme back to http
- uri.scheme = "http";
- }
- if (!valid)
- valid = isValid(uri);
- if (valid) {
- this.loadCaptcha();
- }
- }
- else if (uri) {
- valid = true;
- Weave.Service.serverURL = uri.spec;
- }
- if (valid)
- element.value = Weave.Service.serverURL;
- else
- Weave.Svc.Prefs.reset("serverURL");
- return valid;
- },
- _handleChoice: function() {
- let desc = document.getElementById("mergeChoiceRadio").selectedIndex;
- document.getElementById("chosenActionDeck").selectedIndex = desc;
- switch (desc) {
- case 1:
- if (this._case1Setup)
- break;
- let places_db = PlacesUtils.history
- .QueryInterface(Ci.nsPIPlacesDatabase)
- .DBConnection;
- if (Weave.Service.engineManager.get("history").enabled) {
- let daysOfHistory = 0;
- let stm = places_db.createStatement(
- "SELECT ROUND(( " +
- "strftime('%s','now','localtime','utc') - " +
- "( " +
- "SELECT visit_date FROM moz_historyvisits " +
- "ORDER BY visit_date ASC LIMIT 1 " +
- ")/1000000 " +
- ")/86400) AS daysOfHistory ");
- if (stm.step())
- daysOfHistory = stm.getInt32(0);
- // Support %S for historical reasons (see bug 600141)
- document.getElementById("historyCount").value =
- PluralForm.get(daysOfHistory,
- this._stringBundle.GetStringFromName("historyDaysCount.label"))
- .replace("%S", daysOfHistory)
- .replace("#1", daysOfHistory);
- } else {
- document.getElementById("historyCount").hidden = true;
- }
- if (Weave.Service.engineManager.get("bookmarks").enabled) {
- let bookmarks = 0;
- let stm = places_db.createStatement(
- "SELECT count(*) AS bookmarks " +
- "FROM moz_bookmarks b " +
- "LEFT JOIN moz_bookmarks t ON " +
- "b.parent = t.id WHERE b.type = 1 AND t.parent <> :tag");
- stm.params.tag = PlacesUtils.tagsFolderId;
- if (stm.executeStep())
- bookmarks = stm.row.bookmarks;
- // Support %S for historical reasons (see bug 600141)
- document.getElementById("bookmarkCount").value =
- PluralForm.get(bookmarks,
- this._stringBundle.GetStringFromName("bookmarksCount.label"))
- .replace("%S", bookmarks)
- .replace("#1", bookmarks);
- } else {
- document.getElementById("bookmarkCount").hidden = true;
- }
- if (Weave.Service.engineManager.get("passwords").enabled) {
- let logins = Services.logins.getAllLogins({});
- // Support %S for historical reasons (see bug 600141)
- document.getElementById("passwordCount").value =
- PluralForm.get(logins.length,
- this._stringBundle.GetStringFromName("passwordsCount.label"))
- .replace("%S", logins.length)
- .replace("#1", logins.length);
- } else {
- document.getElementById("passwordCount").hidden = true;
- }
- if (!Weave.Service.engineManager.get("prefs").enabled) {
- document.getElementById("prefsWipe").hidden = true;
- }
- let addonsEngine = Weave.Service.engineManager.get("addons");
- if (addonsEngine.enabled) {
- let ids = addonsEngine._store.getAllIDs();
- let blessedcount = 0;
- for each (let i in ids) {
- if (i) {
- blessedcount++;
- }
- }
- // bug 600141 does not apply, as this does not have to support existing strings
- document.getElementById("addonCount").value =
- PluralForm.get(blessedcount,
- this._stringBundle.GetStringFromName("addonsCount.label"))
- .replace("#1", blessedcount);
- } else {
- document.getElementById("addonCount").hidden = true;
- }
- this._case1Setup = true;
- break;
- case 2:
- if (this._case2Setup)
- break;
- let count = 0;
- function appendNode(label) {
- let box = document.getElementById("clientList");
- let node = document.createElement("label");
- node.setAttribute("value", label);
- node.setAttribute("class", "data indent");
- box.appendChild(node);
- }
- for each (let name in Weave.Service.clientsEngine.stats.names) {
- // Don't list the current client
- if (name == Weave.Service.clientsEngine.localName)
- continue;
- // Only show the first several client names
- if (++count <= 5)
- appendNode(name);
- }
- if (count > 5) {
- // Support %S for historical reasons (see bug 600141)
- let label =
- PluralForm.get(count - 5,
- this._stringBundle.GetStringFromName("additionalClientCount.label"))
- .replace("%S", count - 5)
- .replace("#1", count - 5);
- appendNode(label);
- }
- this._case2Setup = true;
- break;
- }
- return true;
- },
- // sets class and string on a feedback element
- // if no property string is passed in, we clear label/style
- _setFeedback: function(element, success, string) {
- element.hidden = success || !string;
- let classname = success ? "success" : "error";
- let image = element.getElementsByAttribute("class", "statusIcon")[0];
- image.setAttribute("status", classname);
- let label = element.getElementsByAttribute("class", "status")[0];
- label.value = string;
- },
- // shim
- _setFeedbackMessage: function(element, success, string) {
- let str = "";
- if (string) {
- try {
- str = this._stringBundle.GetStringFromName(string);
- } catch(e) {}
- if (!str)
- str = Weave.Utils.getErrorString(string);
- }
- this._setFeedback(element, success, str);
- },
- loadCaptcha: function() {
- let captchaURI = Weave.Service.miscAPI + "captcha_html";
- // First check for NoScript and whitelist the right sites.
- this._handleNoScript(true);
- if (this.captchaBrowser.currentURI.spec != captchaURI) {
- this.captchaBrowser.loadURI(captchaURI);
- }
- },
- onStateChange: function(webProgress, request, stateFlags, status) {
- // We're only looking for the end of the frame load
- if ((stateFlags & Ci.nsIWebProgressListener.STATE_STOP) == 0)
- return;
- if ((stateFlags & Ci.nsIWebProgressListener.STATE_IS_NETWORK) == 0)
- return;
- if ((stateFlags & Ci.nsIWebProgressListener.STATE_IS_WINDOW) == 0)
- return;
- // If we didn't find a captcha, assume it's not needed and don't show it.
- let responseStatus = request.QueryInterface(Ci.nsIHttpChannel).responseStatus;
- setVisibility(this.captchaBrowser, responseStatus != 404);
- //XXX TODO we should really log any responseStatus other than 200
- },
- onProgressChange: function() {},
- onStatusChange: function() {},
- onSecurityChange: function() {},
- onLocationChange: function() {}
- };
- // Define lazy getters for various XUL elements.
- //
- // onWizardAdvance() and onPageShow() are run before init(), so we'll even
- // define things that will almost certainly be used (like 'wizard') as a lazy
- // getter here.
- ["wizard",
- "pin1",
- "pin2",
- "pin3",
- "pairDeviceErrorRow",
- "pairDeviceThrobber"].forEach(function(id) {
- XPCOMUtils.defineLazyGetter(gSyncSetup, id, function() {
- return document.getElementById(id);
- });
- });
- XPCOMUtils.defineLazyGetter(gSyncSetup, "nextFocusEl", function() {
- return {pin1: this.pin2,
- pin2: this.pin3,
- pin3: this.wizard.getButton("next")};
- });
- XPCOMUtils.defineLazyGetter(gSyncSetup, "_stringBundle", function() {
- return Services.strings.createBundle("chrome://browser/locale/syncSetup.properties");
- });
|