continue refactoring rpc

This commit is contained in:
ansuz 2020-02-05 17:31:44 -05:00
parent d17e180420
commit bde17a62a1
7 changed files with 86 additions and 170 deletions

View File

@ -2,6 +2,8 @@
const BatchRead = require("../batch-read");
const nThen = require("nthen");
const getFolderSize = require("get-folder-size");
const Util = require("../common-util");
var Fs = require("fs");
var Admin = module.exports;
@ -90,9 +92,10 @@ var getDiskUsage = function (Env, cb) {
});
};
Admin.command = function (Env, Server, publicKey, data, cb) {
Admin.command = function (Env, safeKey, data, cb, Server) {
var admins = Env.admins;
if (admins.indexOf(publicKey) === -1) {
var unsafeKey = Util.unescapeKeyCharacters(safeKey);
if (admins.indexOf(unsafeKey) === -1) {
return void cb("FORBIDDEN");
}

View File

@ -31,7 +31,7 @@ const Util = require("../common-util");
author of the block, since we assume that the block will have been
encrypted with xsalsa20-poly1305 which is authenticated.
*/
Block.validateLoginBlock = function (Env, publicKey, signature, block, cb) { // FIXME BLOCKS
var validateLoginBlock = function (Env, publicKey, signature, block, cb) { // FIXME BLOCKS
// convert the public key to a Uint8Array and validate it
if (typeof(publicKey) !== 'string') { return void cb('E_INVALID_KEY'); }
@ -86,13 +86,13 @@ var createLoginBlockPath = function (Env, publicKey) { // FIXME BLOCKS
return Path.join(Env.paths.block, safeKey.slice(0, 2), safeKey);
};
Block.writeLoginBlock = function (Env, msg, cb) { // FIXME BLOCKS
Block.writeLoginBlock = function (Env, safeKey, msg, cb) { // FIXME BLOCKS
//console.log(msg);
var publicKey = msg[0];
var signature = msg[1];
var block = msg[2];
Block.validateLoginBlock(Env, publicKey, signature, block, function (e, validatedBlock) {
validateLoginBlock(Env, publicKey, signature, block, function (e, validatedBlock) {
if (e) { return void cb(e); }
if (!(validatedBlock instanceof Uint8Array)) { return void cb('E_INVALID_BLOCK'); }
@ -141,12 +141,12 @@ Block.writeLoginBlock = function (Env, msg, cb) { // FIXME BLOCKS
information, we can just sign some constant and use that as proof.
*/
Block.removeLoginBlock = function (Env, msg, cb) { // FIXME BLOCKS
Block.removeLoginBlock = function (Env, safeKey, msg, cb) { // FIXME BLOCKS
var publicKey = msg[0];
var signature = msg[1];
var block = Nacl.util.decodeUTF8('DELETE_BLOCK'); // clients and the server will have to agree on this constant
Block.validateLoginBlock(Env, publicKey, signature, block, function (e /*::, validatedBlock */) {
validateLoginBlock(Env, publicKey, signature, block, function (e /*::, validatedBlock */) {
if (e) { return void cb(e); }
// derive the filepath
var path = createLoginBlockPath(Env, publicKey);

View File

@ -160,7 +160,7 @@ Channel.isNewChannel = function (Env, channel, cb) {
Otherwise behaves the same as sending to a channel
*/
Channel.writePrivateMessage = function (Env, args, Server, cb) {
Channel.writePrivateMessage = function (Env, args, cb, Server) { // XXX odd signature
var channelId = args[0];
var msg = args[1];

View File

@ -184,5 +184,7 @@ Core.isPendingOwner = function (metadata, unsafeKey) {
return metadata.pending_owners.indexOf(unsafeKey) !== -1;
};
Core.haveACookie = function (Env, safeKey, cb) {
cb();
};

View File

@ -8,10 +8,12 @@ const Core = require("./core");
const Util = require("../common-util");
const batchMetadata = BatchRead("GET_METADATA");
Data.getMetadata = function (Env, channel, cb) {
Data.getMetadata = function (Env, channel, cb/* , Server */) {
if (!Core.isValidId(channel)) { return void cb('INVALID_CHAN'); }
if (channel.length !== 32) { return cb("INVALID_CHAN_LENGTH"); }
// XXX get metadata from the server cache if it is available
// Server isn't always passed, though...
batchMetadata(channel, cb, function (done) {
var ref = {};
var lineHandler = Meta.createLineHandler(ref, Env.Log.error);

View File

@ -454,10 +454,10 @@ Pinning.loadChannelPins = function (Env) {
Pinning.isChannelPinned = function (Env, channel, cb) {
Env.evPinnedPadsReady.reg(() => {
if (Env.pinnedPads[channel] && Object.keys(Env.pinnedPads[channel]).length) {
cb(true);
cb(void 0, true);
} else {
delete Env.pinnedPads[channel];
cb(false);
delete Env.pinnedPads[channel]; // XXX WAT
cb(void 0, false);
}
});
};

View File

@ -18,98 +18,30 @@ var RPC = module.exports;
const Store = require("../storage/file");
const BlobStore = require("../storage/blob");
const UNAUTHENTICATED_CALLS = [
'GET_FILE_SIZE',
'GET_METADATA',
'GET_MULTIPLE_FILE_SIZE',
'IS_CHANNEL_PINNED',
'IS_NEW_CHANNEL',
'GET_DELETED_PADS',
'WRITE_PRIVATE_MESSAGE',
];
var isUnauthenticatedCall = function (call) {
return UNAUTHENTICATED_CALLS.indexOf(call) !== -1;
};
const AUTHENTICATED_CALLS = [
'COOKIE',
'RESET',
'PIN',
'UNPIN',
'GET_HASH',
'GET_TOTAL_SIZE',
'UPDATE_LIMITS',
'GET_LIMIT',
'UPLOAD_STATUS',
'UPLOAD_COMPLETE',
'OWNED_UPLOAD_COMPLETE',
'UPLOAD_CANCEL',
'EXPIRE_SESSION',
'TRIM_OWNED_CHANNEL_HISTORY',
'CLEAR_OWNED_CHANNEL',
'REMOVE_OWNED_CHANNEL',
'REMOVE_PINS',
'TRIM_PINS',
'WRITE_LOGIN_BLOCK',
'REMOVE_LOGIN_BLOCK',
'ADMIN',
'SET_METADATA'
];
var isAuthenticatedCall = function (call) {
return AUTHENTICATED_CALLS.indexOf(call) !== -1;
const UNAUTHENTICATED_CALLS = {
GET_FILE_SIZE: Pinning.getFileSize, // XXX TEST
GET_MULTIPLE_FILE_SIZE: Pinning.getMultipleFileSize,
GET_DELETED_PADS: Pinning.getDeletedPads,
IS_CHANNEL_PINNED: Pinning.isChannelPinned,
IS_NEW_CHANNEL: Channel.isNewChannel,
WRITE_PRIVATE_MESSAGE: Channel.writePrivateMessage,
};
var isUnauthenticateMessage = function (msg) {
return msg && msg.length === 2 && isUnauthenticatedCall(msg[0]);
return msg && msg.length === 2 && typeof(UNAUTHENTICATED_CALLS[msg[0]]) === 'function';
};
var handleUnauthenticatedMessage = function (Env, msg, respond, Server) {
Env.Log.silly('LOG_RPC', msg[0]);
switch (msg[0]) {
case 'GET_FILE_SIZE':
return void Pinning.getFileSize(Env, msg[1], function (e, size) {
Env.WARN(e, msg[1]);
respond(e, [null, size, null]);
});
case 'GET_METADATA':
return void Metadata.getMetadata(Env, msg[1], function (e, data) {
Env.WARN(e, msg[1]);
respond(e, [null, data, null]);
});
case 'GET_MULTIPLE_FILE_SIZE': // XXX not actually used on the client?
return void Pinning.getMultipleFileSize(Env, msg[1], function (e, dict) {
if (e) {
Env.WARN(e, dict);
return respond(e);
}
respond(e, [null, dict, null]);
});
case 'GET_DELETED_PADS':
return void Pinning.getDeletedPads(Env, msg[1], function (e, list) {
if (e) {
Env.WARN(e, msg[1]);
return respond(e);
}
respond(e, [null, list, null]);
});
case 'IS_CHANNEL_PINNED':
return void Pinning.isChannelPinned(Env, msg[1], function (isPinned) {
respond(null, [null, isPinned, null]);
});
case 'IS_NEW_CHANNEL':
return void Channel.isNewChannel(Env, msg[1], function (e, isNew) {
respond(e, [null, isNew, null]);
});
case 'WRITE_PRIVATE_MESSAGE':
return void Channel.writePrivateMessage(Env, msg[1], Server, function (e, output) {
respond(e, output);
});
default:
Env.Log.warn("UNSUPPORTED_RPC_CALL", msg);
return respond('UNSUPPORTED_RPC_CALL', msg);
}
var method = UNAUTHENTICATED_CALLS[msg[0]];
method(Env, msg[1], function (err, value) {
if (err) {
Env.WARN(err, msg[1]);
return void respond(err);
}
respond(err, [null, value, null]);
}, Server);
};
const AUTHENTICATED_USER_TARGETED = {
@ -124,6 +56,9 @@ const AUTHENTICATED_USER_TARGETED = {
UPLOAD_COMPLETE: Upload.complete,
UPLOAD_CANCEL: Upload.cancel,
OWNED_UPLOAD_COMPLETE: Upload.complete_owned,
WRITE_LOGIN_BLOCK: Block.writeLoginBlock,
REMOVE_LOGIN_BLOCK: Block.removeLoginBlock,
ADMIN: Admin.command,
};
const AUTHENTICATED_USER_SCOPED = {
@ -135,13 +70,33 @@ const AUTHENTICATED_USER_SCOPED = {
REMOVE_PINS: Pinning.removePins,
TRIM_PINS: Pinning.trimPins,
SET_METADATA: Metadata.setMetadata,
COOKIE: Core.haveACookie,
};
var handleAuthenticatedMessage = function (Env, map) {
var msg = map.msg;
var safeKey = map.safeKey;
var Respond = map.Respond;
var Server = map.Server;
var isAuthenticatedCall = function (call) {
if (call === 'UPLOAD') { return false; }
return typeof(AUTHENTICATED_USER_TARGETED[call] || AUTHENTICATED_USER_SCOPED[call]) === 'function';
};
var handleAuthenticatedMessage = function (Env, unsafeKey, msg, respond, Server) {
/* If you have gotten this far, you have signed the message with the
public key which you provided.
*/
var safeKey = Util.escapeKeyCharacters(unsafeKey);
var Respond = function (e, value) {
var session = Env.Sessions[safeKey];
var token = session? session.tokens.slice(-1)[0]: '';
var cookie = Core.makeCookie(token).join('|');
respond(e ? String(e): e, [cookie].concat(typeof(value) !== 'undefined' ?value: []));
};
msg.shift();
// discard validated cookie from message
if (!msg.length) {
return void Respond('INVALID_MSG');
}
var TYPE = msg[0];
@ -151,7 +106,7 @@ var handleAuthenticatedMessage = function (Env, map) {
return void AUTHENTICATED_USER_TARGETED[TYPE](Env, safeKey, msg[1], function (e, value) {
Env.WARN(e, value);
return void Respond(e, value);
});
}, Server);
}
if (typeof(AUTHENTICATED_USER_SCOPED[TYPE]) === 'function') {
@ -164,35 +119,7 @@ var handleAuthenticatedMessage = function (Env, map) {
});
}
switch (msg[0]) {
case 'COOKIE': return void Respond(void 0);
case 'WRITE_LOGIN_BLOCK':
return void Block.writeLoginBlock(Env, msg[1], function (e) { // XXX SPECIAL
if (e) {
Env.WARN(e, 'WRITE_LOGIN_BLOCK');
return void Respond(e);
}
Respond(e);
});
case 'REMOVE_LOGIN_BLOCK':
return void Block.removeLoginBlock(Env, msg[1], function (e) { // XXX SPECIAL
if (e) {
Env.WARN(e, 'REMOVE_LOGIN_BLOCK');
return void Respond(e);
}
Respond(e);
});
case 'ADMIN':
return void Admin.command(Env, Server, safeKey, msg[1], function (e, result) { // XXX SPECIAL
if (e) {
Env.WARN(e, result);
return void Respond(e);
}
Respond(void 0, result);
});
default:
return void Respond('UNSUPPORTED_RPC_CALL', msg);
}
return void Respond('UNSUPPORTED_RPC_CALL', msg);
};
var rpc = function (Env, Server, data, respond) {
@ -241,45 +168,23 @@ var rpc = function (Env, Server, data, respond) {
return void respond('INVALID_MESSAGE_OR_PUBLIC_KEY');
}
if (isAuthenticatedCall(msg[1])) {
if (Core.checkSignature(Env, serialized, signature, publicKey) !== true) {
return void respond("INVALID_SIGNATURE_OR_PUBLIC_KEY");
var command = msg[1];
if (command === 'UPLOAD') {
// UPLOAD is a special case that skips signature validation
// intentional fallthrough behaviour
return void handleAuthenticatedMessage(Env, publicKey, msg, respond, Server);
}
if (isAuthenticatedCall(command)) {
// check the signature on the message
// refuse the command if it doesn't validate
if (Core.checkSignature(Env, serialized, signature, publicKey) === true) {
return void handleAuthenticatedMessage(Env, publicKey, msg, respond, Server);
}
} else if (msg[1] !== 'UPLOAD') {
Env.Log.warn('INVALID_RPC_CALL', msg[1]);
return void respond("INVALID_RPC_CALL");
return void respond("INVALID_SIGNATURE_OR_PUBLIC_KEY");
}
var safeKey = Util.escapeKeyCharacters(publicKey);
/* If you have gotten this far, you have signed the message with the
public key which you provided.
We can safely modify the state for that key
OR it's an unauthenticated call, which must not modify the state
for that key in a meaningful way.
*/
// discard validated cookie from message
msg.shift();
var Respond = function (e, msg) {
var session = Env.Sessions[safeKey];
var token = session? session.tokens.slice(-1)[0]: '';
var cookie = Core.makeCookie(token).join('|');
respond(e ? String(e): e, [cookie].concat(typeof(msg) !== 'undefined' ?msg: []));
};
if (typeof(msg) !== 'object' || !msg.length) {
return void Respond('INVALID_MSG');
}
handleAuthenticatedMessage(Env, {
msg: msg,
safeKey: safeKey,
Respond: Respond,
Server: Server,
});
Env.Log.warn('INVALID_RPC_CALL', command);
return void respond("INVALID_RPC_CALL");
};
RPC.create = function (config, cb) {
@ -302,6 +207,10 @@ RPC.create = function (config, cb) {
}
};
if (typeof(config.domain) !== 'undefined') {
throw new Error('fuck');
}
var Env = {
historyKeeper: config.historyKeeper,
intervals: config.intervals || {},