Bug 528278 - Remove remote commands and wait for user on wipeRemote/changePassphrase

Store the reason for starting fresh (new syncId) in meta/global and fail remoteSetup on certain reasons to let the UI show a notification to the user for a response (pick merge or change passphrase). Code paths (sync, prep, etc.) related to remote commands are removed.
This commit is contained in:
Edward Lee 2009-11-12 11:54:21 -08:00
parent 9c4d31f028
commit 3be71460fc
3 changed files with 28 additions and 190 deletions

View File

@ -15,12 +15,13 @@ status.privateBrowsing = Disabled (Private Browsing)
error.login.title = Error While Signing In
error.login.description = Weave encountered an error while signing you in: %1$S. Please try again.
# should decide if we're going to show this
error.logout.title = Error While Signing Out
error.logout.description = Weave encountered an error while signing you out. It's probably ok, and you don't have to do anything about it.
error.sync.title = Error While Syncing
error.sync.description = Weave encountered an error while syncing: %1$S. Weave will automatically retry this action.
error.sync.no_node_found = The Weave server is a little busy right now, but you don't need to do anything about it. We'll start syncing your data as soon as we can!
error.sync.wipe_remote = You requested to replace the data here with your other client. Please choose how you want to merge your data for this client.
error.sync.wipe_remote.label = Choose Merge
error.sync.wipe_remote.accesskey = C
error.sync.reset_passphrase = You changed the passphrase on another client, so please re-connect with the new passphrase.
error.sync.no_node_found.title = Sync Delay
error.sync.tryAgainButton.label = Sync Now
error.sync.tryAgainButton.accesskey = S

View File

@ -106,7 +106,6 @@ KEYS_DOWNLOAD_FAIL: "error.sync.reason.keys_download_fail",
NO_KEYS_NO_KEYGEN: "error.sync.reason.no_keys_no_keygen",
KEYS_UPLOAD_FAIL: "error.sync.reason.keys_upload_fail",
SETUP_FAILED_NO_PASSPHRASE: "error.sync.reason.setup_failed_no_passphrase",
ABORT_SYNC_COMMAND: "aborting sync, process commands said so",
NO_SYNC_NODE_FOUND: "error.sync.reason.no_node_found",
// engine failure status codes
@ -115,6 +114,10 @@ ENGINE_DOWNLOAD_FAIL: "error.engine.reason.record_download_fail
ENGINE_UNKNOWN_FAIL: "error.engine.reason.unknown_fail",
ENGINE_METARECORD_UPLOAD_FAIL: "error.engine.reason.metarecord_upload_fail",
// reasons for changing the sync ID
SYNCID_WIPE_REMOTE: "error.sync.wipe_remote",
SYNCID_RESET_PASSPHRASE: "error.sync.reset_passphrase",
// Ways that a sync can be disabled (messages only to be printed in debug log)
kSyncWeaveDisabled: "Weave is disabled",
kSyncNotLoggedIn: "User is not logged in",

View File

@ -443,7 +443,7 @@ WeaveSvc.prototype = {
this.syncOnIdle();
}
else if (!this._syncTimer) // start the clock if it isn't already
this._scheduleNextSync();
this._checkSyncStatus();
},
// These are global (for all engines)
@ -616,26 +616,13 @@ WeaveSvc.prototype = {
resetPassphrase: function WeaveSvc_resetPassphrase(newphrase)
this._catch(this._notify("resetpph", "", function() {
/* Make remote commands ready so we have a list of clients beforehand */
this.prepCommand("logout", []);
let clientsBackup = Clients._store.clients;
/* Wipe */
this.wipeServer();
PubKeys.clearCache();
PrivKeys.clearCache();
/* Set remote commands before syncing */
Clients._store.clients = clientsBackup;
let username = this.username;
let password = this.password;
this.logout();
/* Set this so UI is updated on next run */
// Save the new passphrase
this.passphrase = newphrase;
this.persistLogin();
/* Login in sync: this also generates new keys */
this.login(username, password, newphrase);
// Start over by wiping the server and reuploading
this.login();
this._freshStart(SYNCID_RESET_PASSPHRASE);
this.sync(true);
return true;
}))(),
@ -806,8 +793,6 @@ WeaveSvc.prototype = {
// stuff we need to to after login, before we can really do
// anything (e.g. key setup)
_remoteSetup: function WeaveSvc__remoteSetup() {
let reset = false;
this._log.debug("Fetching global metadata record");
let meta = Records.import(this.metaURL);
@ -843,7 +828,6 @@ WeaveSvc.prototype = {
Status.sync = DESKTOP_VERSION_OUT_OF_DATE;
return false;
}
reset = true;
this._log.info("Wiping server data");
this._freshStart();
@ -861,13 +845,19 @@ WeaveSvc.prototype = {
return false;
} else if (meta.payload.syncID != Clients.syncID) {
this._log.warn("Meta.payload.syncID is " + meta.payload.syncID +
", Clients.syncID is " + Clients.syncID);
let reason = meta.payload.reason;
this.resetClient();
this._log.info("Reset client because of syncID mismatch.");
this._log.debug("Reset client on syncID mismatch: " + reason);
Clients.syncID = meta.payload.syncID;
this._log.info("Reset the client after a server/client sync ID mismatch");
this._updateRemoteVersion(meta);
// For some syncID changes, we might want to wait for the user
switch (reason) {
case SYNCID_WIPE_REMOTE:
case SYNCID_RESET_PASSPHRASE:
Status.sync = reason;
return false;
}
}
// We didn't wipe the server and we're not out of date, so update remote
else
@ -908,12 +898,6 @@ WeaveSvc.prototype = {
return false;
}
if (!reset) {
this._log.warn("Calling freshStart from !reset case.");
this._freshStart();
this._log.info("Server data wiped to ensure consistency due to missing keys");
}
let passphrase = ID.get("WeaveCryptoID");
if (passphrase.password) {
let keys = PubKeys.createKeypair(passphrase, PubKeys.defaultKeyUri,
@ -1109,24 +1093,6 @@ WeaveSvc.prototype = {
this._log.trace("Refreshing client list");
Clients.sync();
// Process the incoming commands if we have any
if (Clients.getClients()[Clients.clientID].commands) {
try {
if (!(this.processCommands())) {
Status.sync = ABORT_SYNC_COMMAND;
throw "aborting sync, process commands said so";
}
// Repeat remoteSetup in-case the commands forced us to reset
if (!(this._remoteSetup()))
throw "aborting sync, remote setup failed after processing commands";
}
finally {
// Always immediately push back the local client (now without commands)
Clients.sync();
}
}
// Update the client mode now because it might change what we sync
this._updateClientMode();
@ -1217,18 +1183,17 @@ WeaveSvc.prototype = {
}
},
_freshStart: function WeaveSvc__freshStart() {
_freshStart: function WeaveSvc__freshStart(reason) {
this.resetClient();
this._log.info("Reset client data from freshStart.");
this._log.info("Client metadata wiped, deleting server data");
this._log.info("Resetting client and wiping server: " + reason);
this.wipeServer();
// XXX Bug 504125 Wait a while after wiping so that the DELETEs replicate
Sync.sleep(2000);
this._log.debug("Uploading new metadata record");
let meta = new WBORecord(this.metaURL);
meta.payload.syncID = Clients.syncID;
meta.payload.reason = reason;
this._updateRemoteVersion(meta);
},
@ -1331,16 +1296,7 @@ WeaveSvc.prototype = {
wipeRemote: function WeaveSvc_wipeRemote(engines)
this._catch(this._notify("wipe-remote", "", function() {
// Clear out any server data
//this.wipeServer(engines);
// Only wipe the engines provided
if (engines) {
engines.forEach(function(e) this.prepCommand("wipeEngine", [e]), this);
return;
}
// Tell the remote machines to wipe themselves
this.prepCommand("wipeAll", []);
this._freshStart(SYNCID_WIPE_REMOTE);
}))(),
/**
@ -1394,126 +1350,4 @@ WeaveSvc.prototype = {
this._log.debug("Could not remove old snapshots: " + Utils.exceptionStr(e));
}
}))(),
/**
* A hash of valid commands that the client knows about. The key is a command
* and the value is a hash containing information about the command such as
* number of arguments and description.
*/
_commands: [
["resetAll", 0, "Clear temporary local data for all engines"],
["resetEngine", 1, "Clear temporary local data for engine"],
["wipeAll", 0, "Delete all client data for all engines"],
["wipeEngine", 1, "Delete all client data for engine"],
["logout", 0, "Log out client"],
].reduce(function WeaveSvc__commands(commands, entry) {
commands[entry[0]] = {};
for (let [i, attr] in Iterator(["args", "desc"]))
commands[entry[0]][attr] = entry[i + 1];
return commands;
}, {}),
/**
* Check if the local client has any remote commands and perform them.
*
* @return False to abort sync
*/
processCommands: function WeaveSvc_processCommands()
this._notify("process-commands", "", function() {
let info = Clients.getInfo(Clients.clientID);
let commands = info.commands;
// Immediately clear out the commands as we've got them locally
delete info.commands;
Clients.setInfo(Clients.clientID, info);
// Process each command in order
for each ({command: command, args: args} in commands) {
this._log.debug("Processing command: " + command + "(" + args + ")");
let engines = [args[0]];
switch (command) {
case "resetAll":
engines = null;
// Fallthrough
case "resetEngine":
this.resetClient(engines);
break;
case "wipeAll":
engines = null;
// Fallthrough
case "wipeEngine":
this.wipeClient(engines);
break;
case "logout":
this.logout();
return false;
default:
this._log.debug("Received an unknown command: " + command);
break;
}
}
return true;
})(),
/**
* Prepare to send a command to each remote client. Calling this doesn't
* actually sync the command data to the server. If the client already has
* the command/args pair, it won't get a duplicate action.
*
* @param command
* Command to invoke on remote clients
* @param args
* Array of arguments to give to the command
*/
prepCommand: function WeaveSvc_prepCommand(command, args) {
let commandData = this._commands[command];
// Don't send commands that we don't know about
if (commandData == null) {
this._log.error("Unknown command to send: " + command);
return;
}
// Don't send a command with the wrong number of arguments
else if (args == null || args.length != commandData.args) {
this._log.error("Expected " + commandData.args + " args for '" +
command + "', but got " + args);
return;
}
// Package the command/args pair into an object
let action = {
command: command,
args: args,
};
let actionStr = command + "(" + args + ")";
// Convert args into a string to simplify array comparisons
let jsonArgs = JSON.stringify(args);
let notDupe = function(action) action.command != command ||
JSON.stringify(action.args) != jsonArgs;
this._log.info("Sending clients: " + actionStr + "; " + commandData.desc);
// Add the action to each remote client
for (let guid in Clients.getClients()) {
// Don't send commands to the local client
if (guid == Clients.clientID)
continue;
let info = Clients.getInfo(guid);
// Set the action to be a new commands array if none exists
if (info.commands == null)
info.commands = [action];
// Add the new action if there are no duplicates
else if (info.commands.every(notDupe))
info.commands.push(action);
// Must have been a dupe.. skip!
else
continue;
Clients.setInfo(guid, info);
this._log.trace("Client " + guid + " got a new action: " + actionStr);
}
},
};