WIP block history requests that bypass JOIN restriction (where appropriate)

This commit is contained in:
ansuz 2020-02-19 15:32:15 -05:00
parent 79bc8830ef
commit 597f417ad6
2 changed files with 63 additions and 51 deletions

View File

@ -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.

View File

@ -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];
// XXX RESTRICT
// metadata might already be in memory.
// rejecting unauthorized users here is an optimization
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);
}
// look up the appropriate command in the map of commands or fall back to RPC
var command = directMessageCommands[parsed[0]] || handleRPC;
// 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;
}
// run the command with the standard function signature
command(Env, Server, seq, userId, parsed);
// likewise, we can't do anything more here if there's no metadata
// jump to the next block
if (!metadata) { return; }
// 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