diff --git a/rpc.js b/rpc.js index 96ed2cde1..c7312ec0c 100644 --- a/rpc.js +++ b/rpc.js @@ -676,6 +676,29 @@ var makeFileStream = function (root, id, cb) { }); }; +var clearOwnedChannel = function (Env, channelId, unsafeKey, cb) { + if (typeof(channelId) !== 'string' || channelId.length !== 32) { + return cb('INVALID_ARGUMENTS'); + } + + if (!(Env.msgStore && Env.msgStore.getChannelMetadata)) { + return cb('E_NOT_IMPLEMENTED'); + } + + Env.msgStore.getChannelMetadata(channelId, function (e, metadata) { + if (e) { return Respond(e); } + if (!(metadata && Array.isArray(metadata.owners))) { return void cb('E_NO_OWNERS'); } + // Confirm that the channel is owned by the user is question + if (metadata.owners.indexOf(unsafeKey) === -1) { + return void cb('INSUFFICIENT_PERMISSIONS'); + } + + return void Env.msgStore.clearChannel(channelId, function (e) { + cb(e); + }); + }); +}; + var upload = function (Env, publicKey, content, cb) { var paths = Env.paths; var dec; @@ -1058,6 +1081,11 @@ RPC.create = function (config /*:typeof(ConfigType)*/, cb /*:(?Error, ?Function) expireSession(Sessions, safeKey); Respond(void 0, "OK"); }); + case 'CLEAR_OWNED_CHANNEL': + return void clearOwnedChannel(Env, msg[1], publicKey, function (e, response) { + if (e) { return void Respond(e); } + Respond(void 0, response); + }); // restricted to privileged users... case 'UPLOAD': if (!privileged) { return deny(); } diff --git a/storage/file.js b/storage/file.js index 857f147f4..ca293c777 100644 --- a/storage/file.js +++ b/storage/file.js @@ -6,6 +6,65 @@ var mkPath = function (env, channelId) { return Path.join(env.root, channelId.slice(0, 2), channelId) + '.ndjson'; }; +var getMetadataAtPath = function (Env, path, cb) { + var remainder = ''; + var stream = Fs.createReadStream(path, 'utf8'); + var complete = function (err, data) { + var _cb = cb; + cb = undefined; + if (_cb) { _cb(err, data); } + }; + stream.on('data', function (chunk) { + if (!/\n/.test(chunk)) { + remainder += chunk; + return; + } + stream.close(); + var metadata = chunk.split('\n')[0]; + + var parsed = null; + try { + parsed = JSON.parse(metadata); + complete(void 0, parsed); + } + catch (e) { + console.log(); + console.error(e); + complete('INVALID_METADATA'); + } + }); + stream.on('end', function () { + complete(null); + }); + stream.on('error', function (e) { complete(e); }); +}; + +var getChannelMetadata = function (Env, channelId, cb) { + var path = mkPath(Env, channelId); + getMetadataAtPath(Env, path, cb); +}; + +var clearChannel = function (Env, channelId, cb) { + var path = mkPath(Env, channelId); + getMetadataAtPath(Env, path, function (e, metadata) { + if (e) { return cb(e); } + if (!metadata) { + return void Fs.truncate(path, 0, function (err) { + if (err) { + return cb(err); + } + cb(void 0); + }); + } + + var len = JSON.stringify(metadata).length + 1; + Fs.truncate(path, len, function (err) { + if (err) { return cb(err); } + closeChannel(Env, channelId, cb); + }); + }); +}; + var readMessages = function (path, msgHandler, cb) { var remainder = ''; var stream = Fs.createReadStream(path, 'utf8'); @@ -260,6 +319,12 @@ module.exports.create = function (conf, cb) { getChannelSize: function (chanName, cb) { channelBytes(env, chanName, cb); }, + getChannelMetadata: function (channelName, cb) { + getChannelMetadata(env, channelName, cb); + }, + clearChannel: function (channelName, cb) { + clearChannel(env, channelName, cb); + }, }); }); setInterval(function () { diff --git a/www/common/cryptpad-common.js b/www/common/cryptpad-common.js index 3d7edb585..5974e5189 100644 --- a/www/common/cryptpad-common.js +++ b/www/common/cryptpad-common.js @@ -945,6 +945,11 @@ define([ common.getPinnedUsage(todo); }; + common.clearOwnedChannel = function (channel, cb) { + if (!pinsReady()) { return void cb('RPC_NOT_READY'); } + rpc.clearOwnedChannel(channel, cb); + }; + common.uploadComplete = function (cb) { if (!pinsReady()) { return void cb('RPC_NOT_READY'); } rpc.uploadComplete(cb); diff --git a/www/common/pinpad.js b/www/common/pinpad.js index 64bf04b57..327ceb2cd 100644 --- a/www/common/pinpad.js +++ b/www/common/pinpad.js @@ -136,6 +136,16 @@ define([ }); }; + exp.clearOwnedChannel = function (channel, cb) { + if (typeof(channel) !== 'string' || channel.length !== 32) { + return void cb('INVALID_ARGUMENTS'); + } + rpc.send('CLEAR_OWNED_CHANNEL', channel, function (e, response) { + if (e) { return cb(e); } + cb(response); + }); + }; + exp.uploadComplete = function (cb) { rpc.send('UPLOAD_COMPLETE', null, function (e, res) { if (e) { return void cb(e); }