mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-12-06 21:05:37 +00:00
b093fa4215
Part 3: Autoconnect now triggers sync, not just login.
547 lines
20 KiB
JavaScript
547 lines
20 KiB
JavaScript
/* ***** 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 Bookmarks sync code.
|
|
*
|
|
* The Initial Developer of the Original Code is Mozilla.
|
|
* Portions created by the Initial Developer are Copyright (C) 2007
|
|
* the Initial Developer. All Rights Reserved.
|
|
*
|
|
* Contributor(s):
|
|
* Mark Finkle <mfinkle@mozila.com>
|
|
* Matt Brubeck <mbrubeck@mozila.com>
|
|
* Jono DiCarlo <jdicarlo@mozilla.com>
|
|
*
|
|
* 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 ***** */
|
|
|
|
let WeaveGlue = {
|
|
setupData: null,
|
|
jpake: null,
|
|
|
|
init: function init() {
|
|
this._bundle = Services.strings.createBundle("chrome://browser/locale/sync.properties");
|
|
this._msg = document.getElementById("prefs-messages");
|
|
|
|
this._addListeners();
|
|
|
|
this.setupData = { account: "", password: "" , synckey: "", serverURL: "" };
|
|
|
|
let enableSync = Services.prefs.getBoolPref("browser.sync.enabled");
|
|
if (enableSync)
|
|
this._elements.connect.collapsed = false;
|
|
|
|
// Generating keypairs is expensive on mobile, so disable it
|
|
if (Weave.Status.checkSetup() != Weave.CLIENT_NOT_CONFIGURED) {
|
|
if (enableSync) {
|
|
// Put the settings UI into a state of "connecting..." if we are going to auto-connect
|
|
this._elements.connect.firstChild.disabled = true;
|
|
this._elements.connect.setAttribute("title", this._bundle.GetStringFromName("connecting.label"));
|
|
|
|
try {
|
|
this._elements.device.value = Services.prefs.getCharPref("services.sync.client.name");
|
|
} catch(e) {}
|
|
}
|
|
} else if (Weave.Status.login != Weave.LOGIN_FAILED_NO_USERNAME) {
|
|
this.loadSetupData();
|
|
}
|
|
},
|
|
|
|
abortEasySetup: function abortEasySetup() {
|
|
document.getElementById("syncsetup-code1").value = "....";
|
|
document.getElementById("syncsetup-code2").value = "....";
|
|
document.getElementById("syncsetup-code3").value = "....";
|
|
if (!this.jpake)
|
|
return;
|
|
|
|
this.jpake.abort();
|
|
this.jpake = null;
|
|
},
|
|
|
|
_resetScrollPosition: function _resetScrollPosition() {
|
|
let scrollboxes = document.getElementsByClassName("syncsetup-scrollbox");
|
|
for (let i = 0; i < scrollboxes.length; i++) {
|
|
let sbo = scrollboxes[i].boxObject.QueryInterface(Ci.nsIScrollBoxObject);
|
|
try {
|
|
sbo.scrollTo(0, 0);
|
|
} catch(e) {}
|
|
}
|
|
},
|
|
|
|
open: function open() {
|
|
let container = document.getElementById("syncsetup-container");
|
|
if (!container.hidden)
|
|
return;
|
|
|
|
// Services.io.offline is lying to us, so we use the NetworkLinkService instead
|
|
let nls = Cc["@mozilla.org/network/network-link-service;1"].getService(Ci.nsINetworkLinkService);
|
|
if (!nls.isLinkUp) {
|
|
Services.prompt.alert(window,
|
|
this._bundle.GetStringFromName("sync.setup.error.title"),
|
|
this._bundle.GetStringFromName("sync.setup.error.network"));
|
|
return;
|
|
}
|
|
|
|
// Clear up any previous JPAKE codes
|
|
this.abortEasySetup();
|
|
|
|
// Show the connect UI
|
|
container.hidden = false;
|
|
document.getElementById("syncsetup-simple").hidden = false;
|
|
document.getElementById("syncsetup-fallback").hidden = true;
|
|
|
|
BrowserUI.pushDialog(this);
|
|
|
|
let self = this;
|
|
this.jpake = new Weave.JPAKEClient({
|
|
displayPIN: function displayPIN(aPin) {
|
|
document.getElementById("syncsetup-code1").value = aPin.slice(0, 4);
|
|
document.getElementById("syncsetup-code2").value = aPin.slice(4, 8);
|
|
document.getElementById("syncsetup-code3").value = aPin.slice(8);
|
|
},
|
|
|
|
onComplete: function onComplete(aCredentials) {
|
|
self.jpake = null;
|
|
self.close();
|
|
self.setupData = aCredentials;
|
|
self.connect();
|
|
},
|
|
|
|
onAbort: function onAbort(aError) {
|
|
self.jpake = null;
|
|
|
|
if (aError == "jpake.error.userabort" || container.hidden) {
|
|
Services.obs.notifyObservers(null, "browser:sync:setup:userabort", "");
|
|
return;
|
|
}
|
|
|
|
// Automatically go to manual setup if we couldn't acquire a channel.
|
|
let brandShortName = Strings.brand.GetStringFromName("brandShortName");
|
|
let tryAgain = self._bundle.GetStringFromName("sync.setup.tryagain");
|
|
let manualSetup = self._bundle.GetStringFromName("sync.setup.manual");
|
|
let buttonFlags = Ci.nsIPrompt.BUTTON_POS_1_DEFAULT +
|
|
(Ci.nsIPrompt.BUTTON_TITLE_IS_STRING * Ci.nsIPrompt.BUTTON_POS_0) +
|
|
(Ci.nsIPrompt.BUTTON_TITLE_IS_STRING * Ci.nsIPrompt.BUTTON_POS_1) +
|
|
(Ci.nsIPrompt.BUTTON_TITLE_CANCEL * Ci.nsIPrompt.BUTTON_POS_2);
|
|
|
|
let button = Services.prompt.confirmEx(window,
|
|
self._bundle.GetStringFromName("sync.setup.error.title"),
|
|
self._bundle.formatStringFromName("sync.setup.error.nodata", [brandShortName], 1),
|
|
buttonFlags, tryAgain, manualSetup, null, "", {});
|
|
switch (button) {
|
|
case 0:
|
|
// we have to build a new JPAKEClient here rather than reuse the old one
|
|
container.hidden = true;
|
|
self.open();
|
|
break;
|
|
case 1:
|
|
self.openManual();
|
|
break;
|
|
case 2:
|
|
default:
|
|
self.close();
|
|
break;
|
|
}
|
|
}
|
|
});
|
|
this.jpake.receiveNoPIN();
|
|
},
|
|
|
|
openManual: function openManual() {
|
|
this.abortEasySetup();
|
|
|
|
// Reset the scroll since the previous page might have been scrolled
|
|
this._resetScrollPosition();
|
|
|
|
document.getElementById("syncsetup-simple").hidden = true;
|
|
document.getElementById("syncsetup-fallback").hidden = false;
|
|
|
|
// Push the current setup data into the UI
|
|
if (this.setupData && "account" in this.setupData) {
|
|
this._elements.account.value = this.setupData.account;
|
|
this._elements.password.value = this.setupData.password;
|
|
let pp = this.setupData.synckey;
|
|
if (Weave.Utils.isPassphrase(pp))
|
|
pp = Weave.Utils.hyphenatePassphrase(pp);
|
|
this._elements.synckey.value = pp;
|
|
if (this.setupData.serverURL && this.setupData.serverURL.length) {
|
|
this._elements.usecustomserver.checked = true;
|
|
this._elements.customserver.disabled = false;
|
|
this._elements.customserver.value = this.setupData.serverURL;
|
|
} else {
|
|
this._elements.usecustomserver.checked = false;
|
|
this._elements.customserver.disabled = true;
|
|
this._elements.customserver.value = "";
|
|
}
|
|
}
|
|
|
|
this.canConnect();
|
|
},
|
|
|
|
close: function close() {
|
|
if (this.jpake)
|
|
this.abortEasySetup();
|
|
|
|
// Reset the scroll since the previous page might have been scrolled
|
|
this._resetScrollPosition();
|
|
|
|
// Save current setup data
|
|
this.setupData = {
|
|
account: this._elements.account.value.trim(),
|
|
password: this._elements.password.value.trim(),
|
|
synckey: Weave.Utils.normalizePassphrase(this._elements.synckey.value.trim()),
|
|
serverURL: this._validateServer(this._elements.customserver.value.trim())
|
|
};
|
|
|
|
// Clear the UI so it's ready for next time
|
|
this._elements.account.value = "";
|
|
this._elements.password.value = "";
|
|
this._elements.synckey.value = "";
|
|
this._elements.usecustomserver.checked = false;
|
|
this._elements.customserver.disabled = true;
|
|
this._elements.customserver.value = "";
|
|
|
|
// Close the connect UI
|
|
document.getElementById("syncsetup-container").hidden = true;
|
|
BrowserUI.popDialog();
|
|
},
|
|
|
|
toggleCustomServer: function toggleCustomServer() {
|
|
let useCustomServer = this._elements.usecustomserver.checked;
|
|
this._elements.customserver.disabled = !useCustomServer;
|
|
if (!useCustomServer)
|
|
this._elements.customserver.value = "";
|
|
},
|
|
|
|
canConnect: function canConnect() {
|
|
let account = this._elements.account.value;
|
|
let password = this._elements.password.value;
|
|
let synckey = this._elements.synckey.value;
|
|
|
|
let disabled = !(account && password && synckey);
|
|
document.getElementById("syncsetup-button-connect").disabled = disabled;
|
|
},
|
|
|
|
showDetails: function showDetails() {
|
|
// Show the connect UI detail settings
|
|
let show = this._elements.sync.collapsed;
|
|
this._elements.details.checked = show;
|
|
this._elements.sync.collapsed = !show;
|
|
this._elements.device.collapsed = !show;
|
|
this._elements.disconnect.collapsed = !show;
|
|
},
|
|
|
|
toggleSyncEnabled: function toggleSyncEnabled() {
|
|
let enabled = this._elements.autosync.value;
|
|
if (enabled) {
|
|
// Attempt to go back online
|
|
if (this.setupData) {
|
|
if (this.setupData.serverURL && this.setupData.serverURL.length)
|
|
Weave.Service.serverURL = this.setupData.serverURL;
|
|
|
|
// We might still be in the middle of a sync from before Sync was disabled, so
|
|
// let's force the UI into a state that the Sync code feels comfortable
|
|
this.observe(null, "", "");
|
|
|
|
// Now try to re-connect. If successful, this will reset the UI into the
|
|
// correct state automatically.
|
|
Weave.Service.login(Weave.Service.username, this.setupData.password, this.setupData.synckey);
|
|
} else {
|
|
// We can't just go back online. We need to be setup again.
|
|
this._elements.connected.collapsed = true;
|
|
this._elements.connect.collapsed = false;
|
|
}
|
|
} else {
|
|
this._elements.connect.collapsed = true;
|
|
this._elements.connected.collapsed = true;
|
|
Weave.Service.logout();
|
|
}
|
|
|
|
// Close any 'Undo' notification, if one is present
|
|
let notification = this._msg.getNotificationWithValue("undo-disconnect");
|
|
if (notification)
|
|
notification.close();
|
|
},
|
|
|
|
connect: function connect(aSetupData) {
|
|
// Use setup data to pre-configure manual fields
|
|
if (aSetupData)
|
|
this.setupData = aSetupData;
|
|
|
|
// Cause the Sync system to reset internals if we seem to be switching accounts
|
|
if (this.setupData.account != Weave.Service.account)
|
|
Weave.Service.startOver();
|
|
|
|
// Remove any leftover connection error string
|
|
this._elements.connect.removeAttribute("desc");
|
|
|
|
// Reset the custom server URL, if we have one
|
|
if (this.setupData.serverURL && this.setupData.serverURL.length)
|
|
Weave.Service.serverURL = this.setupData.serverURL;
|
|
|
|
// Sync will use the account value and munge it into a username, as needed
|
|
Weave.Service.account = this.setupData.account;
|
|
Weave.Service.login(Weave.Service.username, this.setupData.password, this.setupData.synckey);
|
|
Weave.Service.persistLogin();
|
|
},
|
|
|
|
disconnect: function disconnect() {
|
|
// Save credentials for undo
|
|
let undoData = this.setupData;
|
|
|
|
// Remove all credentials
|
|
this.setupData = null;
|
|
Weave.Service.startOver();
|
|
|
|
let message = this._bundle.GetStringFromName("notificationDisconnect.label");
|
|
let button = this._bundle.GetStringFromName("notificationDisconnect.button");
|
|
let buttons = [ {
|
|
label: button,
|
|
accessKey: "",
|
|
callback: function() { WeaveGlue.connect(undoData); }
|
|
} ];
|
|
this.showMessage(message, "undo-disconnect", buttons);
|
|
|
|
// Hide the notification when the panel is changed or closed.
|
|
let panel = document.getElementById("prefs-container");
|
|
panel.addEventListener("ToolPanelHidden", function onHide(aEvent) {
|
|
panel.removeEventListener(aEvent.type, onHide, false);
|
|
let notification = WeaveGlue._msg.getNotificationWithValue("undo-disconnect");
|
|
if (notification)
|
|
notification.close();
|
|
}, false);
|
|
|
|
Weave.Service.logout();
|
|
},
|
|
|
|
sync: function sync() {
|
|
Weave.Service.sync();
|
|
},
|
|
|
|
_addListeners: function _addListeners() {
|
|
let topics = ["weave:service:sync:start", "weave:service:sync:finish",
|
|
"weave:service:sync:error", "weave:service:login:start",
|
|
"weave:service:login:finish", "weave:service:login:error",
|
|
"weave:service:logout:finish"];
|
|
|
|
// For each topic, add WeaveGlue the observer
|
|
topics.forEach(function(topic) {
|
|
Services.obs.addObserver(WeaveGlue, topic, false);
|
|
});
|
|
|
|
// Remove them on unload
|
|
addEventListener("unload", function() {
|
|
topics.forEach(function(topic) {
|
|
Services.obs.removeObserver(WeaveGlue, topic, false);
|
|
});
|
|
}, false);
|
|
},
|
|
|
|
get _elements() {
|
|
// Do a quick test to see if the options exist yet
|
|
let syncButton = document.getElementById("sync-syncButton");
|
|
if (syncButton == null)
|
|
return null;
|
|
|
|
// Get all the setting nodes from the add-ons display
|
|
let elements = {};
|
|
let setupids = ["account", "password", "synckey", "usecustomserver", "customserver"];
|
|
setupids.forEach(function(id) {
|
|
elements[id] = document.getElementById("syncsetup-" + id);
|
|
});
|
|
|
|
let settingids = ["device", "connect", "connected", "disconnect", "sync", "autosync", "details"];
|
|
settingids.forEach(function(id) {
|
|
elements[id] = document.getElementById("sync-" + id);
|
|
});
|
|
|
|
// Replace the getter with the collection of settings
|
|
delete this._elements;
|
|
return this._elements = elements;
|
|
},
|
|
|
|
observe: function observe(aSubject, aTopic, aData) {
|
|
let loggedIn = Weave.Service.isLoggedIn;
|
|
|
|
// Make sure we're online when connecting/syncing
|
|
Util.forceOnline();
|
|
|
|
// Can't do anything before settings are loaded
|
|
if (this._elements == null)
|
|
return;
|
|
|
|
// Make some aliases
|
|
let connect = this._elements.connect;
|
|
let connected = this._elements.connected;
|
|
let autosync = this._elements.autosync;
|
|
let details = this._elements.details;
|
|
let device = this._elements.device;
|
|
let disconnect = this._elements.disconnect;
|
|
let sync = this._elements.sync;
|
|
|
|
let syncEnabled = this._elements.autosync.value;
|
|
|
|
// If Sync is not enabled, hide the connection row visibility
|
|
if (syncEnabled) {
|
|
connect.collapsed = loggedIn;
|
|
connected.collapsed = !loggedIn;
|
|
} else {
|
|
connect.collapsed = true;
|
|
connected.collapsed = true;
|
|
}
|
|
|
|
if (!loggedIn) {
|
|
connect.setAttribute("title", this._bundle.GetStringFromName("notconnected.label"));
|
|
connect.firstChild.disabled = false;
|
|
details.checked = false;
|
|
sync.collapsed = true;
|
|
device.collapsed = true;
|
|
disconnect.collapsed = true;
|
|
}
|
|
|
|
// Check the lock on a timeout because it's set just after notifying
|
|
setTimeout(function(self) {
|
|
// Prevent certain actions when the service is locked
|
|
if (Weave.Service.locked) {
|
|
connect.firstChild.disabled = true;
|
|
sync.firstChild.disabled = true;
|
|
|
|
if (aTopic == "weave:service:login:start")
|
|
connect.setAttribute("title", self._bundle.GetStringFromName("connecting.label"));
|
|
|
|
if (aTopic == "weave:service:sync:start")
|
|
sync.setAttribute("title", self._bundle.GetStringFromName("lastSyncInProgress2.label"));
|
|
} else {
|
|
connect.firstChild.disabled = false;
|
|
sync.firstChild.disabled = false;
|
|
}
|
|
}, 0, this);
|
|
|
|
// Dynamically generate some strings
|
|
let accountStr = this._bundle.formatStringFromName("account.label", [Weave.Service.account], 1);
|
|
disconnect.setAttribute("title", accountStr);
|
|
|
|
// Show the day-of-week and time (HH:MM) of last sync
|
|
let lastSync = Weave.Svc.Prefs.get("lastSync");
|
|
if (lastSync != null) {
|
|
let syncDate = new Date(lastSync).toLocaleFormat("%a %R");
|
|
let dateStr = this._bundle.formatStringFromName("lastSync2.label", [syncDate], 1);
|
|
sync.setAttribute("title", dateStr);
|
|
}
|
|
|
|
// Show what went wrong with login if necessary
|
|
if (aTopic == "weave:service:login:error")
|
|
connect.setAttribute("desc", Weave.Utils.getErrorString(Weave.Status.login));
|
|
else
|
|
connect.removeAttribute("desc");
|
|
|
|
// Init the setup data if we just logged in
|
|
if (!this.setupData && aTopic == "weave:service:login:finish")
|
|
this.loadSetupData();
|
|
|
|
// Check for a storage format update, update the user and load the Sync update page
|
|
if (aTopic =="weave:service:sync:error") {
|
|
let clientOutdated = false, remoteOutdated = false;
|
|
if (Weave.Status.sync == Weave.VERSION_OUT_OF_DATE) {
|
|
clientOutdated = true;
|
|
} else if (Weave.Status.sync == Weave.DESKTOP_VERSION_OUT_OF_DATE) {
|
|
remoteOutdated = true;
|
|
} else if (Weave.Status.service == Weave.SYNC_FAILED_PARTIAL) {
|
|
// Some engines failed, check for per-engine compat
|
|
for (let [engine, reason] in Iterator(Weave.Status.engines)) {
|
|
clientOutdated = clientOutdated || reason == Weave.VERSION_OUT_OF_DATE;
|
|
remoteOutdated = remoteOutdated || reason == Weave.DESKTOP_VERSION_OUT_OF_DATE;
|
|
}
|
|
}
|
|
|
|
if (clientOutdated || remoteOutdated) {
|
|
let brand = Services.strings.createBundle("chrome://branding/locale/brand.properties");
|
|
let brandName = brand.GetStringFromName("brandShortName");
|
|
|
|
let type = clientOutdated ? "client" : "remote";
|
|
let message = this._bundle.GetStringFromName("sync.update." + type);
|
|
message = message.replace("#1", brandName);
|
|
message = message.replace("#2", Services.appinfo.version);
|
|
let title = this._bundle.GetStringFromName("sync.update.title")
|
|
let button = this._bundle.GetStringFromName("sync.update.button")
|
|
let close = this._bundle.GetStringFromName("sync.update.close")
|
|
|
|
let flags = Services.prompt.BUTTON_POS_0 * Services.prompt.BUTTON_TITLE_IS_STRING +
|
|
Services.prompt.BUTTON_POS_1 * Services.prompt.BUTTON_TITLE_IS_STRING;
|
|
let choice = Services.prompt.confirmEx(window, title, message, flags, button, close, null, null, {});
|
|
if (choice == 0)
|
|
Browser.addTab("https://services.mozilla.com/update/", true, Browser.selectedTab);
|
|
}
|
|
}
|
|
|
|
device.value = Weave.Clients.localName || "";
|
|
},
|
|
|
|
changeName: function changeName(aInput) {
|
|
// Make sure to update to a modified name, e.g., empty-string -> default
|
|
Weave.Clients.localName = aInput.value;
|
|
aInput.value = Weave.Clients.localName;
|
|
},
|
|
|
|
showMessage: function showMessage(aMsg, aValue, aButtons) {
|
|
let notification = this._msg.getNotificationWithValue(aValue);
|
|
if (notification)
|
|
return;
|
|
|
|
this._msg.appendNotification(aMsg, aValue, "", this._msg.PRIORITY_WARNING_LOW, aButtons);
|
|
},
|
|
|
|
_validateServer: function _validateServer(aURL) {
|
|
let uri = Weave.Utils.makeURI(aURL);
|
|
|
|
if (!uri && aURL)
|
|
uri = Weave.Utils.makeURI("https://" + aURL);
|
|
|
|
if (!uri)
|
|
return "";
|
|
return uri.spec;
|
|
},
|
|
|
|
openTutorial: function _openTutorial() {
|
|
WeaveGlue.close();
|
|
|
|
let formatter = Cc["@mozilla.org/toolkit/URLFormatterService;1"].getService(Ci.nsIURLFormatter);
|
|
let url = formatter.formatURLPref("app.sync.tutorialURL");
|
|
BrowserUI.newTab(url, Browser.selectedTab);
|
|
},
|
|
|
|
loadSetupData: function _loadSetupData() {
|
|
this.setupData = {};
|
|
this.setupData.account = Weave.Service.account || "";
|
|
this.setupData.password = Weave.Service.password || "";
|
|
this.setupData.synckey = Weave.Service.passphrase || "";
|
|
|
|
let serverURL = Weave.Service.serverURL;
|
|
let defaultPrefs = Services.prefs.getDefaultBranch(null);
|
|
if (serverURL == defaultPrefs.getCharPref("services.sync.serverURL"))
|
|
serverURL = "";
|
|
this.setupData.serverURL = serverURL;
|
|
}
|
|
};
|