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

This commit is contained in:
Myk Melez 2008-06-18 19:35:31 -07:00
Родитель 26e6962578 d4048117ef
Коммит 001d6fc9e7
19 изменённых файлов: 486 добавлений и 485 удалений

Просмотреть файл

@ -48,7 +48,8 @@ Cu.import("resource://weave/util.js");
* Asynchronous generator helpers
*/
let currentId = 0;
let gCurrentId = 0;
let gOutstandingGenerators = 0;
function AsyncException(initFrame, message) {
this.message = message;
@ -71,13 +72,14 @@ AsyncException.prototype = {
};
function Generator(thisArg, method, onComplete, args) {
gOutstandingGenerators++;
this._outstandingCbs = 0;
this._log = Log4Moz.Service.getLogger("Async.Generator");
this._log.level =
Log4Moz.Level[Utils.prefs.getCharPref("log.logger.async")];
this._thisArg = thisArg;
this._method = method;
this._id = currentId++;
this._id = gCurrentId++;
this.onComplete = onComplete;
this._args = args;
this._initFrame = Components.stack.caller;
@ -251,6 +253,7 @@ Generator.prototype = {
this._log.trace("Initial stack trace:\n" + this.trace);
}
}
gOutstandingGenerators--;
}
};
@ -280,6 +283,7 @@ function trace(frame, str) {
Async = {
get outstandingGenerators() { return gOutstandingGenerators; },
// Use:
// let gen = Async.run(this, this.fooGen, ...);

Просмотреть файл

@ -65,27 +65,12 @@ CryptoSvc.prototype = {
return this.__os;
},
__xxtea: {},
__xxteaLoaded: false,
get _xxtea() {
if (!this.__xxteaLoaded) {
Cu.import("resource://weave/xxtea.js", this.__xxtea);
this.__xxteaLoaded = true;
}
return this.__xxtea;
},
get defaultAlgorithm() {
let branch = Cc["@mozilla.org/preferences-service;1"]
.getService(Ci.nsIPrefBranch);
return branch.getCharPref("extensions.weave.encryption");
return Utils.prefs.getCharPref("encryption");
},
set defaultAlgorithm(value) {
let branch = Cc["@mozilla.org/preferences-service;1"]
.getService(Ci.nsIPrefBranch);
let cur = branch.getCharPref("extensions.weave.encryption");
if (value != cur)
branch.setCharPref("extensions.weave.encryption", value);
if (value != Utils.prefs.getCharPref("encryption"))
Utils.prefs.setCharPref("encryption", value);
},
_init: function Crypto__init() {
@ -374,20 +359,17 @@ CryptoSvc.prototype = {
let cur = branch.getCharPref("extensions.weave.encryption");
if (cur == data)
return;
return;
switch (data) {
case "none":
this._log.info("Encryption disabled");
break;
case "XXTEA":
case "XXXTEA": // Weave 0.1 had this typo
this._log.info("Using encryption algorithm: " + data);
break;
default:
this._log.warn("Unknown encryption algorithm, resetting");
branch.setCharPref("extensions.weave.encryption", "XXTEA");
return; // otherwise we'll send the alg changed event twice
case "none":
this._log.info("Encryption disabled");
break;
default:
this._log.warn("Unknown encryption algorithm, resetting");
branch.clearUserPref("extensions.weave.encryption");
return; // otherwise we'll send the alg changed event twice
}
// FIXME: listen to this bad boy somewhere
this._os.notifyObservers(null, "weave:encryption:algorithm-changed", "");
@ -414,23 +396,6 @@ CryptoSvc.prototype = {
ret = data;
break;
case "XXXTEA": // Weave 0.1.12.10 and below had this typo
case "XXTEA": {
let gen = this._xxtea.encrypt(data, identity.password);
ret = gen.next();
let timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
try {
while (typeof(ret) == "object") {
timer.initWithCallback(self.listener, 0, timer.TYPE_ONE_SHOT);
yield; // Yield to main loop
ret = gen.next();
}
gen.close();
} finally {
timer = null;
}
} break;
case "aes-128-cbc":
case "aes-192-cbc":
case "aes-256-cbc":
@ -464,23 +429,6 @@ CryptoSvc.prototype = {
ret = data;
break;
case "XXXTEA": // Weave 0.1.12.10 and below had this typo
case "XXTEA": {
let gen = this._xxtea.decrypt(data, identity.password);
ret = gen.next();
let timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
try {
while (typeof(ret) == "object") {
timer.initWithCallback(self.listener, 0, timer.TYPE_ONE_SHOT);
yield; // Yield to main loop
ret = gen.next();
}
gen.close();
} finally {
timer = null;
}
} break;
case "aes-128-cbc":
case "aes-192-cbc":
case "aes-256-cbc":

Просмотреть файл

@ -44,6 +44,10 @@ const Cu = Components.utils;
// Annotation to use for shared bookmark folders, incoming and outgoing:
const INCOMING_SHARED_ANNO = "weave/shared-incoming";
const OUTGOING_SHARED_ANNO = "weave/shared-outgoing";
const SERVER_PATH_ANNO = "weave/shared-server-path";
// Standard names for shared files on the server
const KEYRING_FILE_NAME = "keyring";
const SHARED_BOOKMARK_FILE_NAME = "shared_bookmarks";
Cu.import("resource://weave/log4moz.js");
Cu.import("resource://weave/dav.js");
@ -97,7 +101,6 @@ BookmarksEngine.prototype = {
if ( Utils.prefs.getBoolPref( "xmpp.enabled" ) ) {
dump( "Starting XMPP client for bookmark engine..." );
this._startXmppClient.async(this);
//this._startXmppClient();
}
},
@ -108,7 +111,7 @@ BookmarksEngine.prototype = {
// Get serverUrl and realm of the jabber server from preferences:
let serverUrl = Utils.prefs.getCharPref( "xmpp.server.url" );
let realm = Utils.prefs.getCharPref( "xmpp.server.realm" );
// TODO once we have ejabberd talking to LDAP, the username/password
// for xmpp will be the same as the ones for Weave itself, so we can
// read username/password like this:
@ -117,9 +120,8 @@ BookmarksEngine.prototype = {
// until then get these from preferences as well:
let clientName = Utils.prefs.getCharPref( "xmpp.client.name" );
let clientPassword = Utils.prefs.getCharPref( "xmpp.client.password" );
let transport = new HTTPPollingTransport( serverUrl, false, 15000 );
let auth = new PlainAuthenticator();
let auth = new PlainAuthenticator();
// TODO use MD5Authenticator instead once we get it working -- plain is
// a security hole.
this._xmppClient = new XmppClient( clientName,
@ -131,26 +133,31 @@ BookmarksEngine.prototype = {
let messageHandler = {
handle: function ( messageText, from ) {
/* The callback function for incoming xmpp messages.
We expect message text to be either:
"share <dir>"
(sender offers to share directory dir with us)
or "stop <dir>"
(sender has stopped sharing directory dir with us.)
or "accept <dir>"
(sharee has accepted our offer to share our dir.)
or "decline <dir>"
(sharee has declined our offer to share our dir.)
We expect message text to be in the form of:
<command> <serverpath> <foldername>.
Where command is one of:
"share" (sender offers to share directory dir with us)
or "stop" (sender has stopped sharing directory dir with us.)
or "accept" (sharee has accepted our offer to share our dir.)
or "decline" (sharee has declined our offer to share our dir.)
Folder name is the human-readable name of the bookmark folder
being shared (it can contain spaces). serverpath is the path
on the server to the directory where the data is stored:
only the machine seese this, and it can't have spaces.
*/
let words = messageText.split(" ");
let commandWord = words[0];
let directoryName = words.slice(1).join(" ");
let serverPath = words[1];
let directoryName = words.slice(2).join(" ");
if ( commandWord == "share" ) {
bmkEngine._incomingShareOffer( directoryName, from );
bmkEngine._incomingShareOffer(from, serverPath, folderName);
} else if ( commandWord == "stop" ) {
bmkEngine._incomingShareWithdrawn( directoryName, from );
bmkEngine._incomingShareWithdrawn(from, serverPath, folderName);
}
}
}
};
this._xmppClient.registerMessageHandler( messageHandler );
this._xmppClient.connect( realm, self.cb );
yield;
@ -163,9 +170,11 @@ BookmarksEngine.prototype = {
self.done();
},
_incomingShareOffer: function BmkEngine__incomingShareOffer( dir, user ) {
/* Called when we receive an offer from another user to share a
directory.
_incomingShareOffer: function BmkEngine__incomingShareOffer(user,
serverPath,
folderName) {
/* Called when we receive an offer from another user to share a
folder.
TODO what should happen is that we add a notification to the queue
telling that the incoming share has been offered; when the offer
@ -176,14 +185,17 @@ BookmarksEngine.prototype = {
right ahead to creating the incoming share.
*/
dump( "I was offered the directory " + dir + " from user " + dir );
_createIncomingShare( user, serverPath, folderName );
},
_incomingShareWithdrawn: function BmkEngine__incomingShareStop( dir, user ) {
_incomingShareWithdrawn: function BmkEngine__incomingShareStop(user,
serverPath,
folderName) {
/* Called when we receive a message telling us that a user who has
already shared a directory with us has chosen to stop sharing
the directory.
TODO Find the incomingShare in our bookmark tree that corresponds
to the shared directory, and delete it; add a notification to
the queue telling us what has happened.
@ -196,6 +208,8 @@ BookmarksEngine.prototype = {
let self = yield;
this.__proto__.__proto__._sync.async(this, self.cb );
yield;
this.updateAllOutgoingShares(self.cb);
yield;
this.updateAllIncomingShares(self.cb);
yield;
self.done();
@ -213,13 +227,15 @@ BookmarksEngine.prototype = {
the UI. */
// Create the outgoing share folder on the server
// TODO do I need to call these asynchronously?
//this._createOutgoingShare.async( this, selectedFolder, username );
//this._updateOutgoingShare.async( this, selectedFolder, username );
dump( "About to call _createOutgoingShare asynchronously.\n" );
this._createOutgoingShare.async( this, self.cb, selectedFolder, username );
let serverPath = yield;
dump( "Done calling _createOutgoingShare asynchronously.\n" );
this._updateOutgoingShare.async( this, self.cb, selectedFolder );
yield;
/* Set the annotation on the folder so we know
it's an outgoing share: */
dump( "I'm in _share.\n" );
let folderItemId = selectedFolder.node.itemId;
let folderName = selectedFolder.getAttribute( "label" );
ans.setItemAnnotation(folderItemId, OUTGOING_SHARED_ANNO, username, 0,
@ -229,21 +245,21 @@ BookmarksEngine.prototype = {
// Send an xmpp message to the share-ee
if ( this._xmppClient ) {
if ( this._xmppClient._connectionStatus == this._xmppClient.CONNECTED ) {
dump( "Gonna send notification...\n" );
let msgText = "share " + folderName;
let msgText = "share " + serverPath + " " + folderName;
this._log.debug( "Sending XMPP message: " + msgText );
this._xmppClient.sendMessage( username, msgText );
} else {
this._log.info( "XMPP connection not available for share notification." );
this._log.warn( "No XMPP connection for share notification." );
}
}
}
/* LONGTERM TODO: in the future when we allow sharing one folder
with many people, the value of the annotation can be a whole list
of usernames instead of just one. */
dump( "Bookmark engine shared " +folderName + " with " + username );
dump( "Bookmark engine shared " +folderName + " with " + username + "\n" );
ret = true;
self.done( ret );
self.done( true );
},
updateAllIncomingShares: function BmkEngine_updateAllIncoming(onComplete) {
@ -271,66 +287,132 @@ BookmarksEngine.prototype = {
}
},
updateAllOutgoingShares: function BmkEngine_updateAllOutgoing(onComplete) {
// TODO implement me.
// Pseudocode:
// let shares = findFoldersWithAnnotation( OUTGOING_SHARE_ANNO );
// for ( let share in shares ) {
// if ( share.hasChanged() ) {
// this._updateOutgoingShare( share );
// }
// }
// Not sure how to implement share.hasChanged(). See if there's a
// corresponding entry in the latest diff?
},
_createOutgoingShare: function BmkEngine__createOutgoing(folder, username) {
/* To be called asynchronously. Folder is a node indicating the bookmark
folder that is being shared; username is a string indicating the user
that it is to be shared with. This function creates the directory and
keyring on the server in which the shared data will be put, but it
doesn't actually put the bookmark data there (that's done in
_updateOutgoingShare().) */
let self = yield;
let prefix = DAV.defaultPrefix;
let myUserName = ID.get('WeaveID').username;
this._log.debug("Sharing bookmarks from " + folder.getAttribute( "label" )
+ " with " + username);
this._log.debug("Sharing bookmarks from " + guid + " with " + username);
/* Generate a new GUID to use as the new directory name on the server
in which we'll store the shared data. */
let uuidgen = Cc["@mozilla.org/uuid-generator;1"].
getService(Ci.nsIUUIDGenerator);
let folderGuid = uuidgen.generateUUID().toString().replace(/[{}]/g, '');
this._getSymKey.async(this, self.cb);
/* Create the directory on the server if it does not exist already. */
let serverPath = "/user/" + myUserName + "/share/" + folderGuid;
DAV.MKCOL(serverPath, self.cb);
let ret = yield;
if (!ret) {
this._log.error("Can't create remote folder for outgoing share.");
self.done(false);
}
// TODO more error handling
/* Store the path to the server directory in an annotation on the shared
bookmark folder, so we can easily get back to it later. */
let ans = Cc["@mozilla.org/browser/annotation-service;1"].
getService(Ci.nsIAnnotationService);
ans.setItemAnnotation(folder.node.itemId,
SERVER_PATH_ANNO,
serverPath,
0,
ans.EXPIRE_NEVER);
// Create a new symmetric key, to be used only for encrypting this share.
Crypto.PBEkeygen.async(Crypto, self.cb);
let newSymKey = yield;
/* Get public keys for me and the user I'm sharing with.
Each user's public key is stored in /user/username/public/pubkey. */
let myPubKeyFile = new Resource("/user/" + myUserName + "/public/pubkey");
myPubKeyFile.get(self.cb);
let myPubKey = yield;
let userPubKeyFile = new Resource("/user/" + username + "/public/pubkey");
userPubKeyFile.get(self.cb);
let userPubKey = yield;
/* Create the keyring, containing the sym key encrypted with each
of our public keys: */
Crypto.RSAencrypt.async(Crypto, self.cb, symKey, {pubkey: myPubKey} );
let encryptedForMe = yield;
Crypto.RSAencrypt.async(Crypto, self.cb, symKey, {pubkey: userPubKey} );
let encryptedForYou = yield;
let keyring = { myUserName: encryptedForMe,
username: encryptedForYou };
let keyringFile = new Resource( serverPath + "/" + KEYRING_FILE_NAME );
keyringFile.put( self.cb, this._json.encode( keyring ) );
yield;
// copied from getSymKey
DAV.GET(this.keysFile, self.cb);
let ret = yield;
Utils.ensureStatus(ret.status, "Could not get keys file.");
// note: this._json is just an encoder/decoder, no state.
let keys = this._json.decode(ret.responseText);
// get the other user's pubkey
let serverURL = Utils.prefs.getCharPref("serverURL");
try {
DAV.defaultPrefix = "user/" + username + "/";
DAV.GET("public/pubkey", self.cb);
ret = yield;
}
catch (e) { throw e; }
finally { DAV.defaultPrefix = prefix; }
Utils.ensureStatus(ret.status, "Could not get public key for " + username);
let id = new Identity();
id.pubkey = ret.responseText;
// now encrypt the symkey with their pubkey and upload the new keyring
Crypto.RSAencrypt.async(Crypto, self.cb, this._engineId.password, id);
let enckey = yield;
if (!enckey)
throw "Could not encrypt symmetric encryption key";
keys.ring[username] = enckey;
DAV.PUT(this.keysFile, this._json.encode(keys), self.cb);
ret = yield;
Utils.ensureStatus(ret.status, "Could not upload keyring file.");
this._log.debug("All done sharing!");
// Call Atul's js api for setting htaccess:
let api = new Sharing.Api( DAV );
api.shareWithUsers( directory, [username], self.cb );
let sharingApi = new Sharing.Api( DAV );
sharingApi.shareWithUsers( serverPath, [username], self.cb );
let result = yield;
self.done(true);
// return the server path:
self.done( serverPath );
},
_updateOutgoingShare: function BmkEngine__updateOutgoing(guid, username) {
/* TODO this needs to have the logic to break the shared bookmark
subtree out of the store and put it in a separate file...*/
_updateOutgoingShare: function BmkEngine__updateOutgoing(folderNode) {
/* Puts all the bookmark data from the specified bookmark folder,
encrypted, onto the shared directory on the server (replacing
anything that was already there).
TODO: error handling*/
let self = yield;
let myUserName = ID.get('WeaveID').username;
// The folder has an annotation specifying the server path to the
// directory:
let ans = Cc["@mozilla.org/browser/annotation-service;1"].
getService(Ci.nsIAnnotationService);
let serverPath = ans.getItemAnnotation(folderNode, SERVER_PATH_ANNO);
// From that directory, get the keyring file, and from it, the symmetric
// key that we'll use to encrypt.
let keyringFile = new Resource(serverPath + "/" + KEYRING_FILE_NAME);
keyringFile.get(self.cb);
let keyring = yield;
let symKey = keyring[ myUserName ];
// Get the
let json = this._store._wrapMount( folderNode, myUserName );
/* TODO what does wrapMount do with this username? Should I be passing
in my own or that of the person I share with? */
// Encrypt it with the symkey and put it into the shared-bookmark file.
let bookmarkFile = new Resource(serverPath + "/" + SHARED_BOOKMARK_FILE_NAME);
Crypto.PBEencrypt.async( Crypto, self.cb, json, {password:symKey} );
let cyphertext = yield;
bookmarkFile.put( self.cb, cyphertext );
yield;
self.done();
},
_stopOutgoingShare: function BmkEngine__stopOutgoingShare( guid, username ) {
_stopOutgoingShare: function BmkEngine__stopOutgoingShare(folderNode) {
/* TODO implement this... */
// pseudocode:
// let serverPath = getAnnotation( folderNode, SERVER_PATH_ANNO );
// removeAnnotationFromFolder( folderNode, SERVER_PATH_ANNO );
// removeAnnotationFromFolder( folderNode, OUTGOING_SHARED_ANNO );
// server.deleteAllFromDirectory( serverPath );
},
_createIncomingShare: function BookmarkEngine__createShare(guid, id, title) {
@ -378,6 +460,9 @@ BookmarksEngine.prototype = {
/* Pull down bookmarks from the server for a single incoming
shared folder. */
// TODO can use this._remote.keys.getKey( sharer_identity ) to get
// the symmetric key for decryption of the resource. (That will throw
// exception if the resource isn't shared with me.)
/* TODO modify this: the old implementation assumes we want to copy
everything that the other user has, by pulling down snapshot and
diffs and applying the diffs to the snapshot. Instead, now we just

Просмотреть файл

@ -1,7 +1,5 @@
const EXPORTED_SYMBOLS = ['PasswordEngine'];
const Cc = Components.classes;
const Ci = Components.interfaces;
const Cu = Components.utils;
Cu.import("resource://weave/util.js");
@ -30,8 +28,8 @@ function _hashLoginInfo(aLogin) {
return Utils.sha1(loginKey);
}
function PasswordEngine(pbeId) {
this._init(pbeId);
function PasswordEngine() {
this._init();
}
PasswordEngine.prototype = {
get name() { return "passwords"; },
@ -63,8 +61,7 @@ PasswordSyncCore.prototype = {
__loginManager : null,
get _loginManager() {
if (!this.__loginManager)
this.__loginManager = Cc["@mozilla.org/login-manager;1"].
getService(Ci.nsILoginManager);
this.__loginManager = Utils.getLoginManager();
return this.__loginManager;
},
@ -100,21 +97,17 @@ PasswordStore.prototype = {
__loginManager : null,
get _loginManager() {
if (!this.__loginManager)
this.__loginManager = Cc["@mozilla.org/login-manager;1"].
getService(Ci.nsILoginManager);
this.__loginManager = Utils.getLoginManager();
return this.__loginManager;
},
__nsLoginInfo : null,
get _nsLoginInfo() {
if (!this.__nsLoginInfo)
this.__nsLoginInfo = new Components.Constructor(
"@mozilla.org/login-manager/loginInfo;1",
Ci.nsILoginInfo, "init");
this.__nsLoginInfo = Utils.makeNewLoginInfo();
return this.__nsLoginInfo;
},
_createCommand: function PasswordStore__createCommand(command) {
this._log.info("PasswordStore got createCommand: " + command );

Просмотреть файл

@ -58,7 +58,7 @@ IDManager.prototype = {
if (this._aliases[name])
return this._ids[this._aliases[name]];
else
return this._ids[name]
return this._ids[name];
},
set: function IDMgr_set(name, id) {
this._ids[name] = id;
@ -112,49 +112,14 @@ Identity.prototype = {
_password: null,
get password() {
if (!this._password)
return findPassword(this.realm, this.username);
return Utils.findPassword(this.realm, this.username);
return this._password;
},
set password(value) {
setPassword(this.realm, this.username, value);
Utils.setPassword(this.realm, this.username, value);
},
setTempPassword: function Id_setTempPassword(value) {
this._password = value;
}
};
// fixme: move these to util.js?
function findPassword(realm, username) {
// fixme: make a request and get the realm ?
let password;
let lm = Cc["@mozilla.org/login-manager;1"].getService(Ci.nsILoginManager);
let logins = lm.findLogins({}, 'chrome://sync', null, realm);
for (let i = 0; i < logins.length; i++) {
if (logins[i].username == username) {
password = logins[i].password;
break;
}
}
return password;
}
function setPassword(realm, username, password) {
// cleanup any existing passwords
let lm = Cc["@mozilla.org/login-manager;1"].getService(Ci.nsILoginManager);
let logins = lm.findLogins({}, 'chrome://sync', null, realm);
for(let i = 0; i < logins.length; i++) {
lm.removeLogin(logins[i]);
}
if (!password)
return;
// save the new one
let nsLoginInfo = new Components.Constructor(
"@mozilla.org/login-manager/loginInfo;1", Ci.nsILoginInfo, "init");
let login = new nsLoginInfo('chrome://sync', null, realm,
username, password, "", "");
lm.addLogin(login);
}

Просмотреть файл

@ -102,7 +102,7 @@ Utils.lazy(Weave, 'Service', WeaveSvc);
* Main entry point into Weave's sync framework
*/
function WeaveSvc() {
function WeaveSvc(engines) {
this._startupFinished = false;
this._initLogs();
this._log.info("Weave Sync Service Initializing");
@ -116,13 +116,19 @@ function WeaveSvc() {
ID.setAlias('WeaveID', 'DAV:default');
ID.setAlias('WeaveCryptoID', 'Engine:PBE:default');
// Register built-in engines
Engines.register(new BookmarksEngine());
Engines.register(new HistoryEngine());
Engines.register(new CookieEngine());
Engines.register(new PasswordEngine());
Engines.register(new FormEngine());
Engines.register(new TabEngine());
if (typeof engines == "undefined")
engines = [
new BookmarksEngine(),
new HistoryEngine(),
new CookieEngine(),
new PasswordEngine(),
new FormEngine(),
new TabEngine()
];
// Register engines
for (let i = 0; i < engines.length; i++)
Engines.register(engines[i]);
// Other misc startup
Utils.prefs.addObserver("", this, false);
@ -666,7 +672,6 @@ WeaveSvc.prototype = {
"share-bookmarks" will be sent out to any observers who are listening
for it. As far as I know, there aren't currently any listeners for
"share-bookmarks" but we'll send it out just in case. */
dump( "This fails with an Exception: cannot aquire internal lock.\n" );
this._lock(this._notify(messageName,
this._shareData,
dataType,
@ -677,6 +682,7 @@ WeaveSvc.prototype = {
_shareData: function WeaveSync__shareData(dataType,
guid,
username) {
dump( "in _shareData...\n" );
let self = yield;
if (!Engines.get(dataType).enabled) {
this._log.warn( "Can't share disabled data type: " + dataType );

Просмотреть файл

@ -76,16 +76,10 @@ Store.prototype = {
applyCommands: function Store_applyCommands(commandList) {
let self = yield;
let timer, listener;
if (this._yieldDuringApply) {
listener = new Utils.EventListener(self.cb);
timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
}
for (var i = 0; i < commandList.length; i++) {
if (this._yieldDuringApply) {
timer.initWithCallback(listener, 0, timer.TYPE_ONE_SHOT);
Utils.makeTimerForCall(self.cb);
yield; // Yield to main loop
}
var command = commandList[i];
@ -130,14 +124,6 @@ SnapshotStore.prototype = {
this._filename = value + ".json";
},
__dirSvc: null,
get _dirSvc() {
if (!this.__dirSvc)
this.__dirSvc = Cc["@mozilla.org/file/directory_service;1"].
getService(Ci.nsIProperties);
return this.__dirSvc;
},
// Last synced tree, version, and GUID (to detect if the store has
// been completely replaced and invalidate the snapshot)
@ -182,7 +168,7 @@ SnapshotStore.prototype = {
oldGUID = command.GUID;
this._data[newGUID] = this._data[oldGUID];
delete this._data[oldGUID]
delete this._data[oldGUID];
for (let GUID in this._data) {
if (this._data[GUID].parentGUID == oldGUID)
@ -199,14 +185,10 @@ SnapshotStore.prototype = {
save: function SStore_save() {
this._log.info("Saving snapshot to disk");
let file = this._dirSvc.get("ProfD", Ci.nsIFile);
file.QueryInterface(Ci.nsILocalFile);
file.append("weave");
file.append("snapshots");
file.append(this.filename);
if (!file.exists())
file.create(file.NORMAL_FILE_TYPE, PERMS_FILE);
let file = Utils.getProfileFile(
{path: "weave/snapshots/" + this.filename,
autoCreate: true}
);
let out = {version: this.version,
GUID: this.GUID,
@ -219,11 +201,7 @@ SnapshotStore.prototype = {
},
load: function SStore_load() {
let file = this._dirSvc.get("ProfD", Ci.nsIFile);
file.append("weave");
file.append("snapshots");
file.append(this.filename);
let file = Utils.getProfileFile("weave/snapshots/" + this.filename);
if (!file.exists())
return;

Просмотреть файл

@ -50,6 +50,83 @@ Cu.import("resource://weave/log4moz.js");
*/
let Utils = {
// Returns a nsILocalFile representing a file relative to the
// current user's profile directory. If the argument is a string,
// it should be a string with unix-style slashes for directory names
// (these slashes are automatically converted to platform-specific
// path separators).
//
// Alternatively, if the argument is an object, it should contain
// the following attributes:
//
// path: the path to the file, relative to the current user's
// profile dir.
//
// autoCreate: whether or not the file should be created if it
// doesn't already exist.
getProfileFile: function getProfileFile(arg) {
if (typeof arg == "string")
arg = {path: arg};
let pathParts = arg.path.split("/");
let dirSvc = Cc["@mozilla.org/file/directory_service;1"].
getService(Ci.nsIProperties);
let file = dirSvc.get("ProfD", Ci.nsIFile);
file.QueryInterface(Ci.nsILocalFile);
for (let i = 0; i < pathParts.length; i++)
file.append(pathParts[i]);
if (arg.autoCreate && !file.exists())
file.create(file.NORMAL_FILE_TYPE, PERMS_FILE);
return file;
},
getLoginManager: function getLoginManager() {
return Cc["@mozilla.org/login-manager;1"].
getService(Ci.nsILoginManager);
},
makeNewLoginInfo: function getNewLoginInfo() {
return new Components.Constructor(
"@mozilla.org/login-manager/loginInfo;1",
Ci.nsILoginInfo,
"init"
);
},
findPassword: function findPassword(realm, username) {
// fixme: make a request and get the realm ?
let password;
let lm = Cc["@mozilla.org/login-manager;1"]
.getService(Ci.nsILoginManager);
let logins = lm.findLogins({}, 'chrome://sync', null, realm);
for (let i = 0; i < logins.length; i++) {
if (logins[i].username == username) {
password = logins[i].password;
break;
}
}
return password;
},
setPassword: function setPassword(realm, username, password) {
// cleanup any existing passwords
let lm = Cc["@mozilla.org/login-manager;1"]
.getService(Ci.nsILoginManager);
let logins = lm.findLogins({}, 'chrome://sync', null, realm);
for (let i = 0; i < logins.length; i++)
lm.removeLogin(logins[i]);
if (!password)
return;
// save the new one
let nsLoginInfo = new Components.Constructor(
"@mozilla.org/login-manager/loginInfo;1", Ci.nsILoginInfo, "init");
let login = new nsLoginInfo('chrome://sync', null, realm,
username, password, "", "");
lm.addLogin(login);
},
// lazy load objects from a constructor on first access. It will
// work with the global object ('this' in the global context).

Просмотреть файл

@ -1,8 +1,10 @@
const EXPORTED_SYMBOLS = [ "PlainAuthenticator", "Md5DigestAuthenticator" ];
function LOG(aMsg) {
dump("Weave::AuthenticationLayer: " + aMsg + "\n");
}
var Cc = Components.classes;
var Ci = Components.interfaces;
var Cu = Components.utils;
Cu.import("resource://weave/log4moz.js");
if (typeof(atob) == 'undefined') {
// This code was written by Tyler Akins and has been placed in the
@ -367,7 +369,6 @@ PlainAuthenticator.prototype = {
this._jid = jidNodes[0].firstChild.nodeValue;
// TODO: Does the client need to do anything special with its new
// "client@host.com/resourceID" full JID?
LOG( "JID set to " + this._jid );
// If we still need to do session, then we're not done yet:
if ( this._needSession ) {

Просмотреть файл

@ -2,10 +2,9 @@ const EXPORTED_SYMBOLS = ['HTTPPollingTransport'];
var Cc = Components.classes;
var Ci = Components.interfaces;
var Cu = Components.utils;
function LOG(aMsg) {
dump("Weave::Transport-HTTP-Poll: " + aMsg + "\n");
}
Cu.import("resource://weave/log4moz.js");
/*
The interface that should be implemented by any Transport object:
@ -163,7 +162,8 @@ function HTTPPollingTransport( serverUrl, useKeys, interval ) {
}
HTTPPollingTransport.prototype = {
_init: function( serverUrl, useKeys, interval ) {
LOG("Initializing transport: serverUrl=" + serverUrl + ", useKeys=" + useKeys + ", interval=" + interval);
this._log = Log4Moz.Service.getLogger("Service.XmppTransportLayer");
this._log.info("Initializing transport: serverUrl=" + serverUrl + ", useKeys=" + useKeys + ", interval=" + interval);
this._serverUrl = serverUrl
this._n = 0;
this._key = this._makeSeed();
@ -223,7 +223,6 @@ HTTPPollingTransport.prototype = {
_setIdFromCookie: function( self, cookie ) {
// parse connection ID out of the cookie:
// dump( "Cookie is " + cookie + "\n" );
var cookieSegments = cookie.split( ";" );
cookieSegments = cookieSegments[0].split( "=" );
var newConnectionId = cookieSegments[1];
@ -242,13 +241,13 @@ HTTPPollingTransport.prototype = {
break;
default :
self._connectionId = cookieSegments[1];
// dump( "Connection ID set to " + self._connectionId + "\n" );
this._log.debug("Connection ID set to " + self._connectionId);
break;
}
},
_onError: function( errorText ) {
dump( "Transport error: " + errorText + "\n" );
this._log.error( errorText );
if ( this._callbackObject != null ) {
this._callbackObject.onTransportError( errorText );
}
@ -277,7 +276,7 @@ HTTPPollingTransport.prototype = {
if ( request.status == 200) {
// 200 means success.
LOG("Server says: " + request.responseText);
self._log.debug("Server says: " + request.responseText);
// Look for a set-cookie header:
var latestCookie = request.getResponseHeader( "Set-Cookie" );
if ( latestCookie.length > 0 ) {
@ -289,7 +288,7 @@ HTTPPollingTransport.prototype = {
callbackObj.onIncomingData( request.responseText );
}
} else {
LOG( "Error! Got HTTP status code " + request.status );
self._log.error( "Got HTTP status code " + request.status );
if ( request.status == 0 ) {
/* Sometimes the server gives us HTTP status code 0 in response
to an attempt to POST. I'm not sure why this happens, but
@ -320,11 +319,11 @@ HTTPPollingTransport.prototype = {
request.setRequestHeader( "Content-length", contents.length );
request.setRequestHeader( "Connection", "close" );
request.onreadystatechange = _processReqChange;
LOG("Sending: " + contents);
this._log.debug("Sending: " + contents);
request.send( contents );
} catch(ex) {
this._onError("Unable to send message to server: " + this._serverUrl);
LOG("Connection failure: " + ex);
this._log.error("Connection failure: " + ex);
}
},
@ -371,10 +370,10 @@ HTTPPollingTransport.prototype = {
testKeys: function () {
this._key = "foo";
LOG(this._key);
this._log.debug(this._key);
for ( var x = 1; x < 7; x++ ) {
this._advanceKey();
LOG(this._key);
this._log.debug(this._key);
}
}
};

Просмотреть файл

@ -14,10 +14,7 @@ var Cc = Components.classes;
var Ci = Components.interfaces;
var Cu = Components.utils;
function LOG(aMsg) {
dump("Weave::XMPPClient: " + aMsg + "\n");
}
Cu.import("resource://weave/log4moz.js");
Cu.import("resource://weave/xmpp/transportLayer.js");
Cu.import("resource://weave/xmpp/authenticationLayer.js");
@ -38,6 +35,7 @@ XmppClient.prototype = {
IQ_ERROR: -1,
_init: function( clientName, realm, clientPassword, transport, authenticator ) {
this._log = Log4Moz.Service.getLogger("Service.XmppClient");
this._myName = clientName;
this._realm = realm;
this._fullName = clientName + "@" + realm;
@ -47,7 +45,7 @@ XmppClient.prototype = {
this._streamOpen = false;
this._transportLayer = transport;
this._authenticationLayer = authenticator;
LOG("initialized auth with clientName=" + clientName + ", realm=" + realm + ", pw=" + clientPassword);
this._log.debug("initialized auth with clientName=" + clientName + ", realm=" + realm + ", pw=" + clientPassword);
this._authenticationLayer.initialize( clientName, realm, clientPassword );
this._messageHandlers = [];
this._iqResponders = [];
@ -71,9 +69,8 @@ XmppClient.prototype = {
},
parseError: function( streamErrorNode ) {
LOG( "Uh-oh, there was an error!" );
var error = streamErrorNode.childNodes[0];
LOG( "Name: " + error.nodeName + " Value: " + error.nodeValue );
this._log.error( "Name: " + error.nodeName + " Value: " + error.nodeValue );
this._error = error.nodeName;
this.disconnect();
/* Note there can be an optional <text>bla bla </text> node inside
@ -89,14 +86,14 @@ XmppClient.prototype = {
},
setError: function( errorText ) {
LOG( "Error: " + errorText );
this._log.error( errorText );
this._error = errorText;
this._connectionStatus = this.FAILED;
this._finishConnectionAttempt();
},
onIncomingData: function( messageText ) {
LOG("onIncomingData(): rcvd: " + messageText);
this._log.debug("onIncomingData(): rcvd: " + messageText);
var responseDOM = this._parser.parseFromString( messageText, "text/xml" );
// Handle server disconnection
@ -171,7 +168,7 @@ XmppClient.prototype = {
if (presences.length > 0 ) {
var from = presences[0].getAttribute( "from" );
if ( from != undefined ) {
LOG( "I see that " + from + " is online." );
this._log.debug( "I see that " + from + " is online." );
}
}
@ -200,14 +197,14 @@ XmppClient.prototype = {
},
processIncomingMessage: function( messageElem ) {
LOG( "in processIncomingMessage: messageElem is a " + messageElem );
this._log.debug("processIncomingMsg: messageElem is a " + messageElem);
var from = messageElem.getAttribute( "from" );
var contentElem = messageElem.firstChild;
// Go down till we find the element with nodeType = 3 (TEXT_NODE)
while ( contentElem.nodeType != 3 ) {
contentElem = contentElem.firstChild;
}
LOG( "Incoming message to you from " + from + ":" + contentElem.nodeValue );
this._log.debug("Incoming msg from " + from + ":" + contentElem.nodeValue);
for ( var x in this._messageHandlers ) {
// TODO do messages have standard place for metadata?
// will want to have handlers that trigger only on certain metadata.
@ -333,8 +330,7 @@ XmppClient.prototype = {
var msgXml = "<message xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' from='" +
fullName + "' to='" + recipient + "' xml:lang='en'><body>" +
messageText + "</body></message>";
LOG( "Message xml: " );
LOG( msgXml );
this._log.debug( "Outgoing Message xml: " + msgXml );
return msgXml;
},

Просмотреть файл

@ -1,163 +0,0 @@
/* ***** 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 Corrected Block TEA.
*
* The Initial Developer of the Original Code is
* Chris Veness
* Portions created by the Initial Developer are Copyright (C) 2005
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Chris Veness <chrisv@movable-type.co.uk>
*
* 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 ***** */
// Original 'Corrected Block TEA' algorithm David Wheeler & Roger Needham
// See http://en.wikipedia.org/wiki/XXTEA
//
// Javascript version by Chris Veness
// http://www.movable-type.co.uk/scripts/tea.html
const EXPORTED_SYMBOLS = ['encrypt', 'decrypt'];
function Paused() {
}
Paused.prototype = {
toString: function Paused_toString() {
return "[Generator Paused]";
}
}
// use (16 chars of) 'password' to encrypt 'plaintext'
//
// note1:this is a generator so the caller can pause and give control
// to the UI thread
//
// note2: if plaintext or password are passed as string objects, rather
// than strings, this function will throw an 'Object doesn't support
// this property or method' error
function encrypt(plaintext, password) {
var v = new Array(2), k = new Array(4), s = "", i;
// use escape() so only have single-byte chars to encode
plaintext = escape(plaintext);
// build key directly from 1st 16 chars of password
for (i = 0; i < 4; i++)
k[i] = Str4ToLong(password.slice(i * 4, (i + 1) * 4));
for (i = 0; i < plaintext.length; i += 8) {
// encode plaintext into s in 64-bit (8 char) blocks
// ... note this is 'electronic codebook' mode
v[0] = Str4ToLong(plaintext.slice(i, i + 4));
v[1] = Str4ToLong(plaintext.slice(i + 4, i + 8));
code(v, k);
s += LongToStr4(v[0]) + LongToStr4(v[1]);
if (i % 512 == 0)
yield new Paused();
}
yield escCtrlCh(s);
}
// use (16 chars of) 'password' to decrypt 'ciphertext' with xTEA
function decrypt(ciphertext, password) {
var v = new Array(2), k = new Array(4), s = "", i;
for (i = 0; i < 4; i++)
k[i] = Str4ToLong(password.slice(i * 4, (i + 1) * 4));
ciphertext = unescCtrlCh(ciphertext);
for (i = 0; i < ciphertext.length; i += 8) {
// decode ciphertext into s in 64-bit (8 char) blocks
v[0] = Str4ToLong(ciphertext.slice(i, i + 4));
v[1] = Str4ToLong(ciphertext.slice(i + 4, i + 8));
decode(v, k);
s += LongToStr4(v[0]) + LongToStr4(v[1]);
if (i % 512 == 0)
yield new Paused();
}
// strip trailing null chars resulting from filling 4-char blocks:
s = s.replace(/\0+$/, '');
yield unescape(s);
}
function code(v, k) {
// Extended TEA: this is the 1997 revised version of Needham & Wheeler's algorithm
// params: v[2] 64-bit value block; k[4] 128-bit key
var y = v[0], z = v[1];
var delta = 0x9E3779B9, limit = delta*32, sum = 0;
while (sum != limit) {
y += (z<<4 ^ z>>>5)+z ^ sum+k[sum & 3];
sum += delta;
z += (y<<4 ^ y>>>5)+y ^ sum+k[sum>>>11 & 3];
// note: unsigned right-shift '>>>' is used in place of original '>>', due to lack
// of 'unsigned' type declaration in JavaScript (thanks to Karsten Kraus for this)
}
v[0] = y; v[1] = z;
}
function decode(v, k) {
var y = v[0], z = v[1];
var delta = 0x9E3779B9, sum = delta*32;
while (sum != 0) {
z -= (y<<4 ^ y>>>5)+y ^ sum+k[sum>>>11 & 3];
sum -= delta;
y -= (z<<4 ^ z>>>5)+z ^ sum+k[sum & 3];
}
v[0] = y; v[1] = z;
}
// supporting functions
function Str4ToLong(s) { // convert 4 chars of s to a numeric long
var v = 0;
for (var i=0; i<4; i++) v |= s.charCodeAt(i) << i*8;
return isNaN(v) ? 0 : v;
}
function LongToStr4(v) { // convert a numeric long to 4 char string
var s = String.fromCharCode(v & 0xFF, v>>8 & 0xFF, v>>16 & 0xFF, v>>24 & 0xFF);
return s;
}
function escCtrlCh(str) { // escape control chars which might cause problems with encrypted texts
return str.replace(/[\0\t\n\v\f\r\xa0'"!]/g, function(c) { return '!' + c.charCodeAt(0) + '!'; });
}
function unescCtrlCh(str) { // unescape potentially problematic nulls and control characters
return str.replace(/!\d\d?\d?!/g, function(c) { return String.fromCharCode(c.slice(1,-1)); });
}

Просмотреть файл

@ -34,7 +34,7 @@ pref("extensions.weave.log.logger.service.main", "Trace");
pref("extensions.weave.xmpp.enabled", true);
pref("extensions.weave.xmpp.server.url",
"http://sm-labs01.mozilla.org:5280/http-poll");
"https://sm-labs01.mozilla.org:81/xmpp");
pref("extensions.weave.xmpp.server.realm", "sm-labs01.mozilla.org");
pref("extensions.weave.xmpp.client.name", "");
pref("extensions.weave.xmpp.client.password", "");

Просмотреть файл

@ -114,3 +114,88 @@ function makeAsyncTestRunner(generator) {
return run_test;
}
function FakePrefService(contents) {
Cu.import("resource://weave/util.js");
this.fakeContents = contents;
Utils.__prefs = this;
}
FakePrefService.prototype = {
_getPref: function fake__getPref(pref) {
Log4Moz.Service.rootLogger.trace("Getting pref: " + pref);
return this.fakeContents[pref];
},
getCharPref: function fake_getCharPref(pref) {
return this._getPref(pref);
},
getBoolPref: function fake_getBoolPref(pref) {
return this._getPref(pref);
},
getIntPref: function fake_getIntPref(pref) {
return this._getPref(pref);
},
addObserver: function fake_addObserver() {}
};
function makeFakeAsyncFunc(retval) {
Cu.import("resource://weave/async.js");
Function.prototype.async = Async.sugar;
function fakeAsyncFunc() {
let self = yield;
Utils.makeTimerForCall(self.cb);
yield;
self.done(retval);
}
return fakeAsyncFunc;
}
function FakeDAVService(contents) {
Cu.import("resource://weave/dav.js");
this.fakeContents = contents;
DAV.__proto__ = this;
this.checkLogin = makeFakeAsyncFunc(true);
}
FakeDAVService.prototype = {
PUT: function fake_PUT(path, data, onComplete) {
Log4Moz.Service.rootLogger.info("Putting " + path);
this.fakeContents[path] = data;
makeFakeAsyncFunc({status: 200}).async(this, onComplete);
},
GET: function fake_GET(path, onComplete) {
Log4Moz.Service.rootLogger.info("Retrieving " + path);
var result = {status: 404};
if (path in this.fakeContents)
result = {status: 200, responseText: this.fakeContents[path]};
return makeFakeAsyncFunc(result).async(this, onComplete);
},
MKCOL: function fake_MKCOL(path, onComplete) {
Log4Moz.Service.rootLogger.info("Creating dir " + path);
makeFakeAsyncFunc(true).async(this, onComplete);
}
};
function FakePasswordService(contents) {
Cu.import("resource://weave/util.js");
this.fakeContents = contents;
let self = this;
Utils.findPassword = function fake_findPassword(realm, username) {
Log4Moz.Service.rootLogger.trace("Password requested for " +
realm + ":" + username);
if (realm in self.fakeContents && username in self.fakeContents[realm])
return self.fakeContents[realm][username];
else
return null;
};
};

Просмотреть файл

@ -40,7 +40,11 @@ function run_test() {
do_check_eq(timesYielded, 2);
do_check_eq(Async.outstandingGenerators, 1);
do_check_true(fts.processCallback());
do_check_false(fts.processCallback());
do_check_eq(Async.outstandingGenerators, 0);
}

Просмотреть файл

@ -47,4 +47,5 @@ function run_test() {
runTestGenerator.async({});
for (var i = 0; fts.processCallback(); i++) {}
do_check_eq(i, 4);
do_check_eq(Async.outstandingGenerators, 0);
}

Просмотреть файл

@ -1,4 +1,23 @@
Cu.import("resource://weave/util.js");
Cu.import("resource://weave/async.js");
Cu.import("resource://weave/dav.js");
Cu.import("resource://weave/identity.js");
let __fakePasswords = {
'Mozilla Services Password': {foo: "bar"},
'Mozilla Services Encryption Passphrase': {foo: "passphrase"}
};
function run_test() {
var fpasses = new FakePasswordService(__fakePasswords);
var fprefs = new FakePrefService({"encryption" : "none"});
var fds = new FakeDAVService({});
var fts = new FakeTimerService();
var logStats = initTestLogging();
ID.set('Engine:PBE:default',
new Identity('Mozilla Services Encryption Passphrase', 'foo'));
// The JS module we're testing, with all members exposed.
var passwords = loadInSandbox("resource://weave/engines/passwords.js");
@ -13,10 +32,22 @@ function run_test() {
passwordField: "test_password"
};
// Fake nsILoginManager object.
var fakeLoginManager = {
getAllLogins: function() { return [fakeUser]; }
Utils.getLoginManager = function fake_getLoginManager() {
// Return a fake nsILoginManager object.
return {getAllLogins: function() { return [fakeUser]; }};
};
Utils.getProfileFile = function fake_getProfileFile(arg) {
return {exists: function() {return false;}};
};
Utils.open = function fake_open(file, mode) {
let fakeStream = {
writeString: function(data) {Log4Moz.Service.rootLogger.debug(data);},
close: function() {}
};
return [fakeStream];
};
// Ensure that _hashLoginInfo() works.
var fakeUserHash = passwords._hashLoginInfo(fakeUser);
@ -25,7 +56,14 @@ function run_test() {
// Ensure that PasswordSyncCore._itemExists() works.
var psc = new passwords.PasswordSyncCore();
psc.__loginManager = fakeLoginManager;
do_check_false(psc._itemExists("invalid guid"));
do_check_true(psc._itemExists(fakeUserHash));
// Make sure the engine can sync.
var engine = new passwords.PasswordEngine();
engine.sync();
while (fts.processCallback()) {}
do_check_eq(logStats.errorsLogged, 0);
do_check_eq(Async.outstandingGenerators, 0);
}

Просмотреть файл

@ -1,25 +1,25 @@
Cu.import("resource://weave/log4moz.js");
Cu.import("resource://weave/wrap.js");
Cu.import("resource://weave/async.js");
Cu.import("resource://weave/util.js");
Cu.import("resource://weave/dav.js");
Cu.import("resource://weave/crypto.js");
Cu.import("resource://weave/identity.js");
Function.prototype.async = Async.sugar;
let __fakePrefs = {
"log.logger.async" : "Debug",
"username" : "foo",
"serverURL" : "https://example.com/",
"encryption" : "aes-256-cbc",
"enabled" : true,
"schedule" : 0
};
function makeFakeAsyncFunc(retval) {
function fakeAsyncFunc() {
let self = yield;
let __fakeDAVContents = {
"meta/version" : "2",
"private/privkey" : "fake private key"
};
Utils.makeTimerForCall(self.cb);
yield;
self.done(retval);
}
return fakeAsyncFunc;
}
let __fakePasswords = {
'Mozilla Services Password': {foo: "bar"},
'Mozilla Services Encryption Passphrase': {foo: "passphrase"}
};
Crypto.__proto__ = {
RSAkeydecrypt: function fake_RSAkeydecrypt(identity) {
@ -33,53 +33,24 @@ Crypto.__proto__ = {
}
};
DAV.__proto__ = {
checkLogin: makeFakeAsyncFunc(true),
__contents: {"meta/version" : "2",
"private/privkey" : "fake private key"},
GET: function fake_GET(path, onComplete) {
Log4Moz.Service.rootLogger.info("Retrieving " + path);
var result = {status: 404};
if (path in this.__contents)
result = {status: 200, responseText: this.__contents[path]};
return makeFakeAsyncFunc(result).async(this, onComplete);
}
};
function FakeID(realm, username, password) {
this.realm = realm;
this.username = username;
this.password = password;
this.setTempPassword = function FID_setTempPassword(value) {
if (typeof value != "undefined")
this.password = value;
};
}
ID.__proto__ = {
__contents: {WeaveID: new FakeID("", "foo", "bar"),
WeaveCryptoID: new FakeID("", "", "passphrase")},
get: function fake_ID_get(name) {
return this.__contents[name];
}
};
let Service = loadInSandbox("resource://weave/service.js");
function TestService() {
this._startupFinished = false;
this._log = Log4Moz.Service.getLogger("Service.Main");
this.__superclassConstructor = Service.WeaveSvc;
this.__superclassConstructor([]);
}
TestService.prototype = {
_initLogs: function TS__initLogs() {
this._log = Log4Moz.Service.getLogger("Service.Main");
}
};
TestService.prototype.__proto__ = Service.WeaveSvc.prototype;
function test_login_works() {
var fds = new FakeDAVService(__fakeDAVContents);
var fprefs = new FakePrefService(__fakePrefs);
var fpasses = new FakePasswordService(__fakePasswords);
var fts = new FakeTimerService();
var logStats = initTestLogging();
var testService = new TestService();
@ -97,4 +68,5 @@ function test_login_works() {
do_check_true(finished);
do_check_true(successful);
do_check_eq(logStats.errorsLogged, 0);
do_check_eq(Async.outstandingGenerators, 0);
}

Просмотреть файл

@ -0,0 +1,12 @@
*** test pending
Running test: test_login_works
Service.Main INFO Weave Sync Service Initializing
Service.Main DEBUG Logging in
Service.Main INFO Using server URL: https://example.com/user/foo
root INFO Retrieving meta/version
root INFO Retrieving private/privkey
Service.Main INFO Weave scheduler disabled
1 of 1 tests passed.
*** test finished
*** exiting
*** PASS ***