From 170aa6d47eb5e8f2eef7c8a15143bc83f8021f2d Mon Sep 17 00:00:00 2001 From: ansuz Date: Tue, 3 Mar 2020 15:52:49 -0500 Subject: [PATCH] clean up a few tasks related to allow lists --- lib/commands/channel.js | 76 +++++++++++++++++++++++++-------------- lib/historyKeeper.js | 3 +- lib/hk-util.js | 26 +++++++++++--- scripts/tests/test-rpc.js | 23 +++++++++--- 4 files changed, 91 insertions(+), 37 deletions(-) diff --git a/lib/commands/channel.js b/lib/commands/channel.js index da4fb6685..c24837df3 100644 --- a/lib/commands/channel.js +++ b/lib/commands/channel.js @@ -5,6 +5,7 @@ const Util = require("../common-util"); const nThen = require("nthen"); const Core = require("./core"); const Metadata = require("./metadata"); +const HK = require("../hk-util"); Channel.clearOwnedChannel = function (Env, safeKey, channelId, cb, Server) { if (typeof(channelId) !== 'string' || channelId.length !== 32) { @@ -228,7 +229,9 @@ Channel.isNewChannel = function (Env, channel, cb) { Otherwise behaves the same as sending to a channel */ -Channel.writePrivateMessage = function (Env, args, cb, Server) { +Channel.writePrivateMessage = function (Env, args, _cb, Server, netfluxId) { + var cb = Util.once(Util.mkAsync(_cb)); + var channelId = args[0]; var msg = args[1]; @@ -246,31 +249,52 @@ Channel.writePrivateMessage = function (Env, args, cb, Server) { return void cb("NOT_IMPLEMENTED"); } - // historyKeeper expects something with an 'id' attribute - // it will fail unless you provide it, but it doesn't need anything else - var channelStruct = { - id: channelId, - }; - - // construct a message to store and broadcast - var fullMessage = [ - 0, // idk - null, // normally the netflux id, null isn't rejected, and it distinguishes messages written in this way - "MSG", // indicate that this is a MSG - channelId, // channel id - msg // the actual message content. Generally a string - ]; - - // XXX RESTRICT respect allow lists - - // historyKeeper already knows how to handle metadata and message validation, so we just pass it off here - // if the message isn't valid it won't be stored. - Env.historyKeeper.channelMessage(Server, channelStruct, fullMessage); - - Server.getChannelUserList(channelId).forEach(function (userId) { - Server.send(userId, fullMessage); - }); + nThen(function (w) { + Metadata.getMetadataRaw(Env, channelId, w(function (err, metadata) { + if (err) { + w.abort(); + Env.Log.error('HK_WRITE_PRIVATE_MESSAGE', err); + return void cb('METADATA_ERR'); + } + + if (!metadata || !metadata.restricted) { + return; + } + + var session = HK.getNetfluxSession(Env, netfluxId); + var allowed = HK.listAllowedUsers(metadata); + + if (HK.isUserSessionAllowed(allowed, session)) { return; } - cb(); + w.abort(); + cb('INSUFFICIENT_PERMISSIONS'); + })); + }).nThen(function () { + // historyKeeper expects something with an 'id' attribute + // it will fail unless you provide it, but it doesn't need anything else + var channelStruct = { + id: channelId, + }; + + // construct a message to store and broadcast + var fullMessage = [ + 0, // idk + null, // normally the netflux id, null isn't rejected, and it distinguishes messages written in this way + "MSG", // indicate that this is a MSG + channelId, // channel id + msg // the actual message content. Generally a string + ]; + + + // historyKeeper already knows how to handle metadata and message validation, so we just pass it off here + // if the message isn't valid it won't be stored. + Env.historyKeeper.channelMessage(Server, channelStruct, fullMessage); + + Server.getChannelUserList(channelId).forEach(function (userId) { + Server.send(userId, fullMessage); + }); + + cb(); + }); }; diff --git a/lib/historyKeeper.js b/lib/historyKeeper.js index 3a27b228a..8d2806550 100644 --- a/lib/historyKeeper.js +++ b/lib/historyKeeper.js @@ -69,8 +69,7 @@ module.exports.create = function (config, cb) { blockDailyCheck: config.blockDailyCheck === true, myDomain: config.httpUnsafeOrigin, - // XXX not included in the config... - mySubdomain: config.mySubdomain, + mySubdomain: config.mySubdomain, // only exists for the accounts integration customLimits: config.customLimits || {}, // FIXME this attribute isn't in the default conf // but it is referenced in Quota diff --git a/lib/hk-util.js b/lib/hk-util.js index 41d305172..810077c1c 100644 --- a/lib/hk-util.js +++ b/lib/hk-util.js @@ -834,6 +834,7 @@ const directMessageCommands = { */ HK.onDirectMessage = function (Env, Server, seq, userId, json) { const Log = Env.Log; + const HISTORY_KEEPER_ID = Env.id; Log.silly('HK_MESSAGE', json); let parsed; @@ -891,10 +892,27 @@ HK.onDirectMessage = function (Env, Server, seq, userId, json) { return; } - // XXX NOT ALLOWED - // respond to txid with error as in handleGetHistory - // send the allow list anyway, it might not get used currently - // but will in the future +/* Anyone in the userlist that isn't in the allow list should have already + been kicked out of the channel. Likewise, disallowed users should not + be able to add themselves to the userlist because JOIN commands respect + access control settings. The error that is sent below protects against + the remaining case, in which users try to get history without having + joined the channel. Normally we'd send the allow list to tell them the + key with which they should authenticate, but since we don't use this + behaviour, I'm doing the easy thing and just telling them to GO AWAY. + + We can implement the more advanced behaviour later if it turns out that + we need it. This command validates guards against all kinds of history + access: GET_HISTORY, GET_HISTORY_RANGE, GET_FULL_HISTORY. +*/ + + w.abort(); + return void Server.send(userId, [ + seq, + 'ERROR', + 'ERESTRICTED', + HISTORY_KEEPER_ID + ]); })); }).nThen(function () { // run the appropriate command from the map diff --git a/scripts/tests/test-rpc.js b/scripts/tests/test-rpc.js index e944a498b..b9dcf9284 100644 --- a/scripts/tests/test-rpc.js +++ b/scripts/tests/test-rpc.js @@ -373,11 +373,24 @@ nThen(function (w) { } })); }).nThen(function (w) { - // XXX RESTRICT GET_METADATA should fail because alice is not on the allow list - // expect INSUFFICIENT_PERMISSIONS - alice.anonRpc.send('GET_METADATA', oscar.mailboxChannel, w(function (err) { - if (!err) { - // XXX RESTRICT alice should not be permitted to read oscar's mailbox's metadata + alice.anonRpc.send('GET_METADATA', oscar.mailboxChannel, w(function (err, response) { + if (!response) { throw new Error("EXPECTED RESPONSE"); } + var metadata = response[0]; + var expected_fields = ['restricted', 'allowed']; + for (var key in metadata) { + if (expected_fields.indexOf(key) === -1) { + console.log(metadata); + throw new Error("EXPECTED METADATA TO BE RESTRICTED"); + } + } + })); +}).nThen(function (w) { + alice.anonRpc.send('WRITE_PRIVATE_MESSAGE', [ + oscar.mailboxChannel, + '["VANDALISM"]', + ], w(function (err) { + if (err !== 'INSUFFICIENT_PERMISSIONS') { + throw new Error("EXPECTED INSUFFICIENT PERMISSIONS ERROR"); } })); }).nThen(function (w) {