diff --git a/scripts/tests/test-rpc.js b/scripts/tests/test-rpc.js index d6f8053f9..178a07c0d 100644 --- a/scripts/tests/test-rpc.js +++ b/scripts/tests/test-rpc.js @@ -190,14 +190,13 @@ var createUser = function (config, cb) { })); }).nThen(function () { /* - // XXX race condition because both users try to pin things... + // FIXME race condition because both users try to pin things... user.team_rpc.getServerHash(w(function (err, hash) { if (err) { w.abort(); return void cb(err); } - - /* +/* if (!hash || hash[0] !== EMPTY_ARRAY_HASH) { console.error("EXPECTED EMPTY ARRAY HASH"); process.exit(1); diff --git a/storage/blob.js b/storage/blob.js index 6b3e891dd..759839fd8 100644 --- a/storage/blob.js +++ b/storage/blob.js @@ -74,7 +74,8 @@ var isFile = function (filePath, cb) { }); }; -var makeFileStream = function (full, cb) { +var makeFileStream = function (full, _cb) { + var cb = Util.once(Util.mkAsync(_cb)); Fse.mkdirp(Path.dirname(full), function (e) { if (e || !full) { // !full for pleasing flow, it's already checked return void cb(e ? e.message : 'INTERNAL_ERROR'); @@ -89,10 +90,8 @@ var makeFileStream = function (full, cb) { stream.on('open', function () { cb(void 0, stream); }); - stream.on('error', function (/* e */) { - //console.error("MAKE_FILE_STREAM", full); - // XXX ERROR - //WARN('stream error', e); + stream.on('error', function (err) { + cb(err); }); } catch (err) { cb('BAD_STREAM'); diff --git a/www/common/outer/roster.js b/www/common/outer/roster.js index 0cc37d35c..6730d3261 100644 --- a/www/common/outer/roster.js +++ b/www/common/outer/roster.js @@ -197,14 +197,22 @@ var factory = function (Util, Hash, CPNetflux, Sortify, nThen, Crypto) { } var members = roster.state.members; - var changed = false; + // validate first... args.forEach(function (curve) { if (!isValidId(curve)) { throw new Error("INVALID_CURVE_KEY"); } - // don't try to remove something that isn't there - if (!members[curve]) { return; } + // even members can remove themselves + if (curve === author) { return; } + + // but if it concerns anyone else, validate that the author has sufficient permissions var role = members[curve].role; if (!canRemoveRole(author, role, members)) { throw new Error("INSUFFICIENT_PERMISSIONS"); } + }); + + var changed = false; + args.forEach(function (curve) { + // don't try to remove something that isn't there + if (!members[curve]) { return; } changed = true; delete members[curve]; }); @@ -352,6 +360,8 @@ var factory = function (Util, Hash, CPNetflux, Sortify, nThen, Crypto) { var keys = config.keys; var me = keys.myCurvePublic; var channel = config.channel; + var lastKnownHash = config.lastKnownHash || -1; + var ref = { state: { members: { }, @@ -360,7 +370,7 @@ var factory = function (Util, Hash, CPNetflux, Sortify, nThen, Crypto) { internal: { initialized: false, sinceLastCheckpoint: 0, - lastCheckpointHash: -1 + lastCheckpointHash: lastKnownHash, }, }; var roster = {}; @@ -462,7 +472,7 @@ var factory = function (Util, Hash, CPNetflux, Sortify, nThen, Crypto) { try { changed = handleCommand(parsed, author, ref); } catch (err) { - error = err; + error = err.message; } var id = getMessageId(hash); @@ -517,7 +527,7 @@ var factory = function (Util, Hash, CPNetflux, Sortify, nThen, Crypto) { // simulate the command before you send it changed = simulate(msg, keys.myCurvePublic, ref); } catch (err) { - return void cb(err); + return void cb(err.message); } if (!changed) { return void cb("NO_CHANGE"); } @@ -533,7 +543,7 @@ var factory = function (Util, Hash, CPNetflux, Sortify, nThen, Crypto) { channel, ciphertext ], function (err) { - if (err) { return response.handle(id, [err]); } + if (err) { return response.handle(id, [err.message || err]); } }); return id; }; @@ -644,7 +654,6 @@ var factory = function (Util, Hash, CPNetflux, Sortify, nThen, Crypto) { return void cb(err); } }).nThen(function () { - var lastKnownHash = config.lastKnownHash || -1; if (typeof(lastKnownHash) === 'string') { console.log("Synchronizing from checkpoint"); }