diff --git a/lib/historyKeeper.js b/lib/historyKeeper.js index 53de34e6b..93644f571 100644 --- a/lib/historyKeeper.js +++ b/lib/historyKeeper.js @@ -153,14 +153,9 @@ module.exports.create = function (config, cb) { // and get the list of keys for which this user has already authenticated var session = HK.getNetfluxSession(Env, userId); - // iterate over their keys. If any of them are in the allow list, let them join - if (session) { - for (var unsafeKey in session) { - if (allowed.indexOf(unsafeKey) !== -1) { - proceed(); - return void next(); - } - } + if (HK.isUserSessionAllowed(allowed, session)) { + proceed(); + return void next(); } // otherwise they're not allowed. diff --git a/lib/hk-util.js b/lib/hk-util.js index eac886c79..049529a74 100644 --- a/lib/hk-util.js +++ b/lib/hk-util.js @@ -75,11 +75,6 @@ const isMetadataMessage = function (parsed) { return Boolean(parsed && parsed.channel); }; -const isChannelRestricted = function (metadata) { // XXX RESTRICT - metadata = metadata; - return false; -}; - HK.listAllowedUsers = function (metadata) { return (metadata.owners || []).concat((metadata.allowed || [])); }; @@ -88,6 +83,16 @@ HK.getNetfluxSession = function (Env, netfluxId) { return Env.netfluxUsers[netfluxId]; }; +HK.isUserSessionAllowed = function (allowed, session) { + if (!session) { return false; } + for (var unsafeKey in session) { + if (allowed.indexOf(unsafeKey) !== -1) { + return true; + } + } + return false; +}; + HK.authenticateNetfluxSession = function (Env, netfluxId, unsafeKey) { var user = Env.netfluxUsers[netfluxId] = Env.netfluxUsers[netfluxId] || {}; user[unsafeKey] = +new Date(); @@ -97,24 +102,6 @@ HK.closeNetfluxSession = function (Env, netfluxId) { delete Env.netfluxUsers[netfluxId]; }; -const isUserAllowed = function (metadata, userId) { // XXX RESTRICT -/* - - at this point all we have is the user's netflux id. - the allow-list is encoded for 'unsafeKeys' (URL-unsafe base64 encoded public signing keys). - - we need a lookup table: netfluxId => public keys with which this netflux session has authenticated. - from there we can check whether the user has authenticated for any of the allowed keys this session. - - owners are implicitly allowed to view any file they own. - pending_owners too. - otherwise check metadata.allowed. - -*/ - userId = userId; - return false; -}; - // validateKeyStrings supplied by clients must decode to 32-byte Uint8Arrays const isValidValidateKeyString = function (key) { try { @@ -690,15 +677,6 @@ const handleGetHistory = function (Env, Server, seq, userId, parsed) { // FIXME this is hard to read because 'checkExpired' has side effects if (checkExpired(Env, Server, channelName)) { return void waitFor.abort(); } - // XXX RESTRICT - // once we've loaded the metadata we can check whether the channel is restricted - // and notify the user if they're not included in the list - if (isChannelRestricted(index.metadata) && isUserAllowed(index.metadata, userId)) { - // XXX RESTRICT send a message indicating that they need to authenticate - // for a list of private keys... - return void waitFor.abort(); - } - // always send metadata with GET_HISTORY requests Server.send(userId, [0, HISTORY_KEEPER_ID, 'MSG', userId, JSON.stringify(index.metadata)], w); })); @@ -865,20 +843,59 @@ HK.onDirectMessage = function (Env, Server, seq, userId, json) { return; } - // If the requested history is for an expired channel, abort - // Note the if we don't have the keys for that channel in metadata_cache, we'll - // have to abort later (once we know the expiration time) - if (checkExpired(Env, Server, parsed[1])) { return; } + var first = parsed[0]; + + if (typeof(directMessageCommands[first]) !== 'function') { + // it's either an unsupported command or an RPC call + // either way, RPC has it covered + return void handleRPC(Env, Server, seq, userId, parsed); + } + + // otherwise it's some kind of history retrieval command... + // go grab its metadata, because unfortunately people can ask for history + // whether or not they have joined the channel, so we can't rely on JOIN restriction + // to stop people from loading history they shouldn't see. + var channelName = parsed[1]; + nThen(function (w) { + HK.getMetadata(Env, channelName, w(function (err, metadata) { + if (err) { + // stream errors? + // we should log these, but if we can't load metadata + // then it's probably not restricted or expired + // it's not like anything else will recover from this anyway + return; + } - // XXX RESTRICT - // metadata might already be in memory. - // rejecting unauthorized users here is an optimization - // look up the appropriate command in the map of commands or fall back to RPC - var command = directMessageCommands[parsed[0]] || handleRPC; + // likewise, we can't do anything more here if there's no metadata + // jump to the next block + if (!metadata) { return; } - // run the command with the standard function signature - command(Env, Server, seq, userId, parsed); + // If the requested history is for an expired channel, abort + // checkExpired has side effects and will disconnect users for you... + if (checkExpired(Env, Server, parsed[1])) { + // if the channel is expired just abort. + w.abort(); + return; + } + + // jump to handling the command if there's no restriction... + if (!metadata.restricted) { return; } + + // check if the user is in the allow list... + const allowed = HK.listAllowedUsers(metadata); + const session = HK.getNetfluxSession(Env, userId); + + if (HK.isUserSessionAllowed(allowed, session)) { + return; + } + + // XXX NOT ALLOWED + })); + }).nThen(function () { + // run the appropriate command from the map + directMessageCommands[first](Env, Server, seq, userId, parsed); + }); }; /* onChannelMessage