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: const Ci = Components.interfaces; michael@0: const Cc = Components.classes; michael@0: const Cu = Components.utils; michael@0: michael@0: Cu.import("resource://services-sync/main.js"); michael@0: Cu.import("resource://gre/modules/XPCOMUtils.jsm"); michael@0: michael@0: const PIN_PART_LENGTH = 4; michael@0: michael@0: const ADD_DEVICE_PAGE = 0; michael@0: const SYNC_KEY_PAGE = 1; michael@0: const DEVICE_CONNECTED_PAGE = 2; michael@0: michael@0: let gSyncAddDevice = { michael@0: michael@0: init: function init() { michael@0: this.pin1.setAttribute("maxlength", PIN_PART_LENGTH); michael@0: this.pin2.setAttribute("maxlength", PIN_PART_LENGTH); michael@0: this.pin3.setAttribute("maxlength", PIN_PART_LENGTH); michael@0: michael@0: this.nextFocusEl = {pin1: this.pin2, michael@0: pin2: this.pin3, michael@0: pin3: this.wizard.getButton("next")}; michael@0: michael@0: this.throbber = document.getElementById("pairDeviceThrobber"); michael@0: this.errorRow = document.getElementById("errorRow"); michael@0: michael@0: // Kick off a sync. That way the server will have the most recent data from michael@0: // this computer and it will show up immediately on the new device. michael@0: Weave.Service.scheduler.scheduleNextSync(0); michael@0: }, michael@0: michael@0: onPageShow: function onPageShow() { michael@0: this.wizard.getButton("back").hidden = true; michael@0: michael@0: switch (this.wizard.pageIndex) { michael@0: case ADD_DEVICE_PAGE: michael@0: this.onTextBoxInput(); michael@0: this.wizard.canRewind = false; michael@0: this.wizard.getButton("next").hidden = false; michael@0: this.pin1.focus(); michael@0: break; michael@0: case SYNC_KEY_PAGE: michael@0: this.wizard.canAdvance = false; michael@0: this.wizard.canRewind = true; michael@0: this.wizard.getButton("back").hidden = false; michael@0: this.wizard.getButton("next").hidden = true; michael@0: document.getElementById("weavePassphrase").value = michael@0: Weave.Utils.hyphenatePassphrase(Weave.Service.identity.syncKey); michael@0: break; michael@0: case DEVICE_CONNECTED_PAGE: michael@0: this.wizard.canAdvance = true; michael@0: this.wizard.canRewind = false; michael@0: this.wizard.getButton("cancel").hidden = true; michael@0: break; michael@0: } michael@0: }, michael@0: michael@0: onWizardAdvance: function onWizardAdvance() { michael@0: switch (this.wizard.pageIndex) { michael@0: case ADD_DEVICE_PAGE: michael@0: this.startTransfer(); michael@0: return false; michael@0: case DEVICE_CONNECTED_PAGE: michael@0: window.close(); michael@0: return false; michael@0: } michael@0: return true; michael@0: }, michael@0: michael@0: startTransfer: function startTransfer() { michael@0: this.errorRow.hidden = true; michael@0: // When onAbort is called, Weave may already be gone. michael@0: const JPAKE_ERROR_USERABORT = Weave.JPAKE_ERROR_USERABORT; michael@0: michael@0: let self = this; michael@0: let jpakeclient = this._jpakeclient = new Weave.JPAKEClient({ michael@0: onPaired: function onPaired() { michael@0: let credentials = {account: Weave.Service.identity.account, michael@0: password: Weave.Service.identity.basicPassword, michael@0: synckey: Weave.Service.identity.syncKey, michael@0: serverURL: Weave.Service.serverURL}; michael@0: jpakeclient.sendAndComplete(credentials); michael@0: }, michael@0: onComplete: function onComplete() { michael@0: delete self._jpakeclient; michael@0: self.wizard.pageIndex = DEVICE_CONNECTED_PAGE; michael@0: michael@0: // Schedule a Sync for soonish to fetch the data uploaded by the michael@0: // device with which we just paired. michael@0: Weave.Service.scheduler.scheduleNextSync(Weave.Service.scheduler.activeInterval); michael@0: }, michael@0: onAbort: function onAbort(error) { michael@0: delete self._jpakeclient; michael@0: michael@0: // Aborted by user, ignore. michael@0: if (error == JPAKE_ERROR_USERABORT) { michael@0: return; michael@0: } michael@0: michael@0: self.errorRow.hidden = false; michael@0: self.throbber.hidden = true; michael@0: self.pin1.value = self.pin2.value = self.pin3.value = ""; michael@0: self.pin1.disabled = self.pin2.disabled = self.pin3.disabled = false; michael@0: self.pin1.focus(); michael@0: } michael@0: }); michael@0: this.throbber.hidden = false; michael@0: this.pin1.disabled = this.pin2.disabled = this.pin3.disabled = true; michael@0: this.wizard.canAdvance = false; michael@0: michael@0: let pin = this.pin1.value + this.pin2.value + this.pin3.value; michael@0: let expectDelay = false; michael@0: jpakeclient.pairWithPIN(pin, expectDelay); michael@0: }, michael@0: michael@0: onWizardBack: function onWizardBack() { michael@0: if (this.wizard.pageIndex != SYNC_KEY_PAGE) michael@0: return true; michael@0: michael@0: this.wizard.pageIndex = ADD_DEVICE_PAGE; michael@0: return false; michael@0: }, michael@0: michael@0: onWizardCancel: function onWizardCancel() { michael@0: if (this._jpakeclient) { michael@0: this._jpakeclient.abort(); michael@0: delete this._jpakeclient; michael@0: } michael@0: return true; michael@0: }, michael@0: michael@0: onTextBoxInput: function onTextBoxInput(textbox) { michael@0: if (textbox && textbox.value.length == PIN_PART_LENGTH) michael@0: this.nextFocusEl[textbox.id].focus(); michael@0: michael@0: this.wizard.canAdvance = (this.pin1.value.length == PIN_PART_LENGTH michael@0: && this.pin2.value.length == PIN_PART_LENGTH michael@0: && this.pin3.value.length == PIN_PART_LENGTH); michael@0: }, michael@0: michael@0: goToSyncKeyPage: function goToSyncKeyPage() { michael@0: this.wizard.pageIndex = SYNC_KEY_PAGE; michael@0: } michael@0: michael@0: }; michael@0: // onWizardAdvance() and onPageShow() are run before init() so we'll set michael@0: // these up as lazy getters. michael@0: ["wizard", "pin1", "pin2", "pin3"].forEach(function (id) { michael@0: XPCOMUtils.defineLazyGetter(gSyncAddDevice, id, function() { michael@0: return document.getElementById(id); michael@0: }); michael@0: });