Automated merge with ssh://hg.mozilla.org/labs/weave/

This commit is contained in:
Myk Melez 2008-06-30 15:16:31 -07:00
commit ac691d002a
5 changed files with 138 additions and 101 deletions

View File

@ -82,23 +82,27 @@ let gOutstandingGenerators = new NamableTracker();
// asynchronous coroutine-based functions our current one was called
// from.
function AsyncException(asyncStack, exceptionToWrap) {
this._exceptionToWrap = exceptionToWrap;
this._originalException = exceptionToWrap;
this._asyncStack = asyncStack;
// Here we'll have our exception instance's prototype be dynamically
// generated; this ultimately allows us to dynamically "subclass"
// the exception we're wrapping at runtime.
this.__proto__ = {
get asyncStack() {
return this._asyncStack;
},
__proto__: this._originalException,
get asyncStack() this._asyncStack,
get originalException() this._originalException,
addAsyncFrame: function AsyncException_addAsyncFrame(frame) {
this._asyncStack += ((this._asyncStack? "\n" : "") +
formatAsyncFrame(frame));
},
toString: function AsyncException_toString() {
return this._originalException;
}
};
this.__proto__.__proto__ = this._exceptionToWrap;
}
function Generator(thisArg, method, onComplete, args) {

View File

@ -229,4 +229,44 @@ CryptoSvc.prototype = {
identity.privkeyWrapIV);
self.done(ret);
},
// This function tests to see if the passphrase which encrypts
// the private key for the given identity is valid.
isPassphraseValid: function Crypto_isPassphraseValid(identity) {
var self = yield;
// We do this in a somewhat roundabout way; an alternative is
// to use a hard-coded symmetric key, but even that is still
// roundabout--ideally, the IWeaveCrypto interface should
// expose some sort of functionality to make this easier,
// or perhaps it should just offer this very function. -AV
// Generate a temporary fake identity.
var idTemp = {realm: "Temporary passphrase validation"};
// Generate a random symmetric key.
this.randomKeyGen.async(Crypto, self.cb, idTemp);
yield;
// Encrypt the symmetric key with the user's public key.
this.wrapKey.async(Crypto, self.cb, idTemp.bulkKey, identity);
let wrappedKey = yield;
let unwrappedKey;
// Decrypt the symmetric key with the user's private key.
try {
this.unwrapKey.async(Crypto, self.cb, wrappedKey, identity);
unwrappedKey = yield;
} catch (e) {
self.done(false);
return;
}
// Ensure that the original symmetric key is identical to
// the decrypted version.
if (unwrappedKey != idTemp.bulkKey)
throw new Error("Unwrapped key is not identical to original key.");
self.done(true);
}
};

View File

@ -147,6 +147,7 @@ WeaveSvc.prototype = {
_localLock: Wrap.localLock,
_osPrefix: "weave:service:",
_loggedIn: false,
_syncInProgress: false,
__os: null,
get _os() {
@ -197,13 +198,8 @@ WeaveSvc.prototype = {
get userPath() { return ID.get('WeaveID').username; },
get isLoggedIn() {
return this._loggedIn;
},
get enabled() {
return Utils.prefs.getBoolPref("enabled");
},
get isLoggedIn() this._loggedIn,
get enabled() Utils.prefs.getBoolPref("enabled"),
get schedule() {
if (!this.enabled)
@ -237,7 +233,7 @@ WeaveSvc.prototype = {
}
},
_enableSchedule: function WeaveSync__enableSchedule() {
_enableSchedule: function WeaveSvc__enableSchedule() {
if (this._scheduleTimer) {
this._scheduleTimer.cancel();
this._scheduleTimer = null;
@ -250,7 +246,7 @@ WeaveSvc.prototype = {
this._log.info("Weave scheduler enabled");
},
_disableSchedule: function WeaveSync__disableSchedule() {
_disableSchedule: function WeaveSvc__disableSchedule() {
if (this._scheduleTimer) {
this._scheduleTimer.cancel();
this._scheduleTimer = null;
@ -258,18 +254,18 @@ WeaveSvc.prototype = {
this._log.info("Weave scheduler disabled");
},
_onSchedule: function WeaveSync__onSchedule() {
_onSchedule: function WeaveSvc__onSchedule() {
if (this.enabled) {
if (!DAV.allowLock) {
this._log.info("Skipping scheduled sync; local operation in progress")
} else {
this._log.info("Running scheduled sync");
this._notify("syncAsNeeded", this._lock(this._syncAsNeeded)).async(this);
this._notify("sync-as-needed", this._lock(this._syncAsNeeded)).async(this);
}
}
},
_initLogs: function WeaveSync__initLogs() {
_initLogs: function WeaveSvc__initLogs() {
this._log = Log4Moz.Service.getLogger("Service.Main");
this._log.level =
Log4Moz.Level[Utils.prefs.getCharPref("log.logger.service.main")];
@ -312,7 +308,7 @@ WeaveSvc.prototype = {
this._debugApp.clear();
},
_uploadVersion: function WeaveSync__uploadVersion() {
_uploadVersion: function WeaveSvc__uploadVersion() {
let self = yield;
DAV.MKCOL("meta", self.cb);
@ -326,7 +322,7 @@ WeaveSvc.prototype = {
},
// force a server wipe when the version is lower than ours (or there is none)
_versionCheck: function WeaveSync__versionCheck() {
_versionCheck: function WeaveSvc__versionCheck() {
let self = yield;
DAV.GET("meta/version", self.cb);
@ -334,17 +330,13 @@ WeaveSvc.prototype = {
if (!Utils.checkStatus(ret.status)) {
this._log.info("Server has no version file. Wiping server data.");
this._serverWipe.async(this, self.cb);
yield;
this._uploadVersion.async(this, self.cb);
yield;
yield this._serverWipe.async(this, self.cb);
yield this._uploadVersion.async(this, self.cb);
} else if (ret.responseText < STORAGE_FORMAT_VERSION) {
this._log.info("Server version too low. Wiping server data.");
this._serverWipe.async(this, self.cb);
yield;
this._uploadVersion.async(this, self.cb);
yield;
yield this._serverWipe.async(this, self.cb);
yield this._uploadVersion.async(this, self.cb);
} else if (ret.responseText > STORAGE_FORMAT_VERSION) {
// FIXME: should we do something here?
@ -368,7 +360,7 @@ WeaveSvc.prototype = {
finally { DAV.defaultPrefix = prefix; }
},
_getKeypair : function WeaveSync__getKeypair() {
_getKeypair : function WeaveSvc__getKeypair() {
let self = yield;
if ("none" == Utils.prefs.getCharPref("encryption"))
@ -389,8 +381,7 @@ WeaveSvc.prototype = {
"Could not get public key from server", [[200,300],404]);
if (privkeyResp.status == 404 || pubkeyResp.status == 404) {
this._generateKeys.async(this, self.cb);
yield;
yield this._generateKeys.async(this, self.cb);
return;
}
@ -417,7 +408,7 @@ WeaveSvc.prototype = {
// know if the user's passphrase works or not.
},
_generateKeys: function WeaveSync__generateKeys() {
_generateKeys: function WeaveSvc__generateKeys() {
let self = yield;
this._log.debug("Generating new RSA key");
@ -452,7 +443,7 @@ WeaveSvc.prototype = {
let pubkeyData = { version : 1,
algorithm : id.keypairAlg,
pubkey : id.pubkey,
pubkey : id.pubkey
};
data = this._json.encode(pubkeyData);
@ -466,7 +457,7 @@ WeaveSvc.prototype = {
// nsIObserver
observe: function WeaveSync__observe(subject, topic, data) {
observe: function WeaveSvc__observe(subject, topic, data) {
switch (topic) {
case "nsPref:changed":
switch (data) {
@ -482,7 +473,7 @@ WeaveSvc.prototype = {
}
},
_onQuitApplication: function WeaveSync__onQuitApplication() {
_onQuitApplication: function WeaveSvc__onQuitApplication() {
if (!this.enabled ||
!Utils.prefs.getBoolPref("syncOnQuit.enabled") ||
!this._loggedIn)
@ -502,11 +493,12 @@ WeaveSvc.prototype = {
// These are global (for all engines)
verifyLogin: function WeaveSync_verifyLogin(username, password) {
this._localLock(this._notify("verify-login", this._verifyLogin, username, password)).async(this, null);
verifyLogin: function WeaveSvc_verifyLogin(username, password) {
this._localLock(this._notify("verify-login", this._verifyLogin,
username, password)).async(this, null);
},
_verifyLogin: function WeaveSync__verifyLogin(username, password) {
_verifyLogin: function WeaveSvc__verifyLogin(username, password) {
let self = yield;
this._log.debug("Verifying login for user " + username);
@ -525,10 +517,10 @@ WeaveSvc.prototype = {
Utils.ensureStatus(status, "Login verification failed");
},
login: function WeaveSync_login(onComplete) {
login: function WeaveSvc_login(onComplete) {
this._localLock(this._notify("login", this._login)).async(this, onComplete);
},
_login: function WeaveSync__login() {
_login: function WeaveSvc__login() {
let self = yield;
this._log.debug("Logging in user " + this.username);
@ -552,7 +544,7 @@ WeaveSvc.prototype = {
self.done(true);
},
logout: function WeaveSync_logout() {
logout: function WeaveSvc_logout() {
this._log.info("Logging out");
this._disableSchedule();
this._loggedIn = false;
@ -597,16 +589,13 @@ WeaveSvc.prototype = {
// These are per-engine
sync: function WeaveSync_sync(onComplete) {
sync: function WeaveSvc_sync(onComplete) {
this._notify("sync", this._lock(this._sync)).async(this, onComplete);
},
_sync: function WeaveSync__sync() {
_sync: function WeaveSvc__sync() {
let self = yield;
if (!this._loggedIn)
throw "Can't sync: Not logged in";
yield this._versionCheck.async(this, self.cb);
yield this._getKeypair.async(this, self.cb);
@ -624,17 +613,11 @@ WeaveSvc.prototype = {
// at different rates, so we store them in a hash indexed by engine name.
_syncThresholds: {},
_syncAsNeeded: function WeaveSync__syncAsNeeded() {
_syncAsNeeded: function WeaveSvc__syncAsNeeded() {
let self = yield;
if (!this._loggedIn)
throw "Can't sync: Not logged in";
this._versionCheck.async(this, self.cb);
yield;
this._getKeypair.async(this, self.cb);
yield;
yield this._versionCheck.async(this, self.cb);
yield this._getKeypair.async(this, self.cb);
let engines = Engines.getAll();
for each (let engine in engines) {
@ -689,16 +672,13 @@ WeaveSvc.prototype = {
}
},
resetServer: function WeaveSync_resetServer(onComplete) {
resetServer: function WeaveSvc_resetServer(onComplete) {
this._notify("reset-server",
this._lock(this._resetServer)).async(this, onComplete);
},
_resetServer: function WeaveSync__resetServer() {
_resetServer: function WeaveSvc__resetServer() {
let self = yield;
if (!this._loggedIn)
throw "Can't reset server: Not logged in";
let engines = Engines.getAll();
for (let i = 0; i < engines.length; i++) {
if (!engines[i].enabled)
@ -708,11 +688,11 @@ WeaveSvc.prototype = {
}
},
resetClient: function WeaveSync_resetClient(onComplete) {
resetClient: function WeaveSvc_resetClient(onComplete) {
this._localLock(this._notify("reset-client",
this._resetClient)).async(this, onComplete);
},
_resetClient: function WeaveSync__resetClient() {
_resetClient: function WeaveSvc__resetClient() {
let self = yield;
let engines = Engines.getAll();
for (let i = 0; i < engines.length; i++) {
@ -723,7 +703,7 @@ WeaveSvc.prototype = {
}
},
shareData: function WeaveSync_shareData(dataType,
shareData: function WeaveSvc_shareData(dataType,
onComplete,
guid,
username) {
@ -747,7 +727,7 @@ WeaveSvc.prototype = {
username)).async(this, onComplete);
},
_shareData: function WeaveSync__shareData(dataType,
_shareData: function WeaveSvc__shareData(dataType,
guid,
username) {
let self = yield;
@ -765,7 +745,7 @@ WeaveSvc.prototype = {
/* LONGTERM TODO this is almost duplicated code, maybe just have
* one function where we pass in true to share and false to stop
* sharing. */
stopSharingData: function WeaveSync_stopSharingData(dataType,
stopSharingData: function WeaveSvc_stopSharingData(dataType,
onComplete,
guid,
username) {
@ -777,7 +757,7 @@ WeaveSvc.prototype = {
username)).async(this, onComplete);
},
_stopSharingData: function WeaveSync__stopSharingData(dataType,
_stopSharingData: function WeaveSvc__stopSharingData(dataType,
onComplete,
guid,
username) {

View File

@ -85,6 +85,7 @@ let Wrap = {
try {
this._os.notifyObservers(null, this._osPrefix + savedName + ":start", "");
this._os.notifyObservers(null, this._osPrefix + "global:start", "");
args = savedArgs.concat(args);
args.unshift(this, savedMethod, self.cb);
@ -92,9 +93,11 @@ let Wrap = {
ret = yield;
this._os.notifyObservers(null, this._osPrefix + savedName + ":success", "");
this._os.notifyObservers(null, this._osPrefix + "global:success", "");
} catch (e) {
this._os.notifyObservers(null, this._osPrefix + savedName + ":error", "");
this._os.notifyObservers(null, this._osPrefix + "global:error", "");
throw e;
}
@ -113,11 +116,18 @@ let Wrap = {
let ret;
let args = Array.prototype.slice.call(arguments);
if (!this._loggedIn)
throw "Could not acquire lock (not logged in)";
if (DAV.locked)
throw "Could not acquire lock (lock already held)";
DAV.lock.async(DAV, self.cb);
let locked = yield;
if (!locked)
throw "Could not acquire lock";
this._os.notifyObservers(null, this._osPrefix + "lock:acquired", "");
try {
args = savedArgs.concat(args);
args.unshift(this, savedMethod, self.cb);
@ -128,8 +138,8 @@ let Wrap = {
throw e;
} finally {
DAV.unlock.async(DAV, self.cb);
yield;
yield DAV.unlock.async(DAV, self.cb);
this._os.notifyObservers(null, this._osPrefix + "lock:released", "");
}
self.done(ret);
@ -151,14 +161,23 @@ let Wrap = {
throw "Could not acquire lock";
DAV.allowLock = false;
this._os.notifyObservers(null,
this._osPrefix + "local-lock:acquired", "");
try {
args = savedArgs.concat(args);
args.unshift(this, savedMethod, self.cb);
Async.run.apply(Async, args);
ret = yield;
} catch (e) {
throw e;
} finally {
DAV.allowLock = true;
this._os.notifyObservers(null,
this._osPrefix + "local-lock:released", "");
}
catch (e) { throw e; }
finally { DAV.allowLock = true; }
self.done(ret);
};

View File

@ -6,47 +6,41 @@ Function.prototype.async = Async.sugar;
let __fakeCryptoID = {
keypairAlg: "RSA",
// This private key is encrypted with the passphrase 'passphrase',
// contained in our testing infrastructure.
privkey: "3ytj94K6Wo0mBjAVsiIwjm5x2+ENvpKTDUqLCz19iXbESf8RT6O8PmY7Pqcndpn+adqaQdvmr0T1JQ5bfLEHev0WBfo8oWJb+OS4rKoCWxDNzGwrOlW5hCfxSekw0KrKjqZyDZ0hT1Qt9vn6thlV2v9YWfmyn0OIxNC9hUqGwU3Wb2F2ejM0Tw40+IIW4eLEvFxLGv0vnEXpZvesPt413proL6FGQJe6vyapBg+sdX1JMYGaKZY84PUGIiDPxTbQg7yIWTSe3WlDhJ001khFiyEoTZvPhiAGXfML9ycrCRZUWkHp/cfS7QiusJXs6co0tLjrIk/rTk8h4mHBnyPkFIxh4YrfC7Bwf9npwomhaZCEQ32VK+a8grTDsGYHPZexDm3TcD2+d+hZ/u4lUOHFscQKX4w83tq942yqFtElCD2yQoqEDr1Z9zge5XBnLcYiH9hL0ozfpxBlTtpR1kSH663JHqlYim0qhuk0zrGAPkHna07UMFufxvgQBSd/YUqWCimJFGi+5QeOOFO20Skj882Bh1QDYsmbxZ/JED5ocGNHWSqpaOL2ML1F9nD5rdtffI0BsTe+j9h+HV4GlvzUz0Jd6RRf9xN4RyxqfENb8iGH5Pwbry7Qyk16rfm0s6JgG8pNb/8quKD+87RAtQFybZtdQ9NfGg+gyRiU9pbb6FPuPnGp+KpktaHu/K3HnomrVUoyLQALfCSbPXg2D9ta6dRV0JRqOZz4w52hlHIa62iJO6QecbdBzPYGT0QfOy/vp6ndRDR+2xMD/BmlaQwm3+58cqhIw9SVV5h/Z5PVaXxAOqg5vpU1NjrbF4uIFo5rmR0PyA/6qtxZaBY6w3I4sUWdDkIer8QsyrFrO7MIEdxksvDoFIeIM5eN8BufLu3ymS5ZXBiFr/iRxlYcQVHK2hz0/7syWUYsrz5/l1mj+qbWGx+6daWOk3xt4SH+p0hUpMC4FbJ9m/xr4im+X5m5ZYiajaF1QPOXTTny2plE0vfqMVlwX1HFFTJrAP+E85sZI8LPHAYO80qhSi3tV/LHjxCnC1LHJXaRkG202pQFWF1yVT/o82HBt9OC1xY6TVcy4Uh+6piNIQ9FxXGWrzjz0AUkxwkSN3Foqlfiq+mqJmNwzIdEQTmNAcBBsN3vWngU4elHjYI5qFZBzxJIkH8tfvivOshrOZIZB9TD9GIRhQwIBWc6i4fnqE9GUK2Jle6werdFATiMU4msQg7ClURaMn/p3MOLoxTmsPd1iBYPQkqnJgEAdNfKj3KRqSc6M/x09hGDSzK2d9Y03pyDGPh2sopcMFdCQbMy8VOld2/hEGakMJv6BPoRfhKmJbgGVf5x4B9dWZNa8WCmlcxaZ7KG43UA0zLm1VgfTcDW5qazDFoxIcfhmO5KoRI3q8vNs+Wh+smLC6yFODdF9HzrPimEYSc6OWHWgUcuiIBRjKeo5gBTbExWmri2VG+cn005vQNxK+0s7JVyFB8TzZ96pV3nFjkYy9OUkaiJxGd6OVGcvhbbrcNsKkaZff7OsLqczf6x0bhwh+y8+bLjLkuusGYUdBvdeiuv12IfeRupvwD8Z3aZOgcD7d+8VTyTyd/KX9fu8P7tD5SojJ5joRPjcv4Q8/mhRgtwx1McMIL3YnKHG+U=",
privkeyWrapIV: "fZ7CB/KQAUjEhkmrEkns4Q==",
passphraseSalt: "JFs5h2RKX9m0Op9DlQIcCOSfOH1MuDrrrHxCx+CpCUU=",
pubkey: "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAxxwObnXIoYeQKMG9RbvLkgsu/idDo25qOX87jIEiXkgW1wLKp/1D/DBLUEW303tVszNGVt6bTyAXOIj6skpmYoDs9Z48kvU3+g7Vi4QXEw5moSS4fr+yFpKiYd2Kx1+jCFGvGZjBzAAvnjsWmWrSA+LHJSrFlKY6SM3kNg8KrE8dxUi3wztlZnhZgo1ZYe7/VeBOXUfThtoadIl1VdREw2e79eiMQpPa0XLv4grCaMd/wLRs0be1/nPt7li4NyT0fnYFWg75SU3ni/xSaq/zR4NmW/of5vB2EcKyUG+/mvNplQ0CX+v3hRBCdhpCyPmcbHKUluyKzj7Ms9pKyCkwxwIDAQAB"
};
function checkpassphrase_coroutine() {
var self = yield;
var idRSA = ID.get("WeaveCryptoID");
var idTemp = new Identity("temp", "temp", null);
// Generate a random symmetric key.
Crypto.randomKeyGen.async(Crypto, self.cb, idTemp);
yield;
// Encrypt the symmetric key with the user's public key.
Crypto.wrapKey.async(Crypto, self.cb, idTemp.bulkKey, idRSA);
let wrappedKey = yield;
// Decrypt the symmetric key with the user's private key.
Crypto.unwrapKey.async(Crypto, self.cb, wrappedKey, idRSA);
let unwrappedKey = yield;
// Ensure that the original symmetric key is identical to
// the decrypted version.
do_check_eq(unwrappedKey, idTemp.bulkKey);
self.done(true);
}
function test_passphrase_checking() {
let syncTesting = new SyncTestingInfrastructure();
function testGenerator() {
let self = yield;
let id = ID.get("WeaveCryptoID");
for (name in __fakeCryptoID)
id[name] = __fakeCryptoID[name];
function checkpassphrase(cb) {
checkpassphrase_coroutine.async({}, cb);
}
Crypto.isPassphraseValid.async(Crypto, self.cb, id);
let result = yield;
syncTesting.runAsyncFunc("Checking passphrase", checkpassphrase);
do_check_eq(result, true);
id.setTempPassword("incorrect passphrase");
Crypto.isPassphraseValid.async(Crypto, self.cb, id);
result = yield;
do_check_eq(result, false);
self.done();
}
function run_test() {
let syncTesting = new SyncTestingInfrastructure();
syncTesting.runAsyncFunc(
"Ensuring isPassphraseValid() works",
function runTest(cb) { testGenerator.async({}, cb); }
);
}