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