continue refactoring rpc

pull/1/head
ansuz 5 years ago
parent d17e180420
commit bde17a62a1

@ -2,6 +2,8 @@
const BatchRead = require("../batch-read"); const BatchRead = require("../batch-read");
const nThen = require("nthen"); const nThen = require("nthen");
const getFolderSize = require("get-folder-size"); const getFolderSize = require("get-folder-size");
const Util = require("../common-util");
var Fs = require("fs"); var Fs = require("fs");
var Admin = module.exports; 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; var admins = Env.admins;
if (admins.indexOf(publicKey) === -1) { var unsafeKey = Util.unescapeKeyCharacters(safeKey);
if (admins.indexOf(unsafeKey) === -1) {
return void cb("FORBIDDEN"); return void cb("FORBIDDEN");
} }

@ -31,7 +31,7 @@ const Util = require("../common-util");
author of the block, since we assume that the block will have been author of the block, since we assume that the block will have been
encrypted with xsalsa20-poly1305 which is authenticated. 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 // convert the public key to a Uint8Array and validate it
if (typeof(publicKey) !== 'string') { return void cb('E_INVALID_KEY'); } 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); 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); //console.log(msg);
var publicKey = msg[0]; var publicKey = msg[0];
var signature = msg[1]; var signature = msg[1];
var block = msg[2]; 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 (e) { return void cb(e); }
if (!(validatedBlock instanceof Uint8Array)) { return void cb('E_INVALID_BLOCK'); } 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. 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 publicKey = msg[0];
var signature = msg[1]; var signature = msg[1];
var block = Nacl.util.decodeUTF8('DELETE_BLOCK'); // clients and the server will have to agree on this constant 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); } if (e) { return void cb(e); }
// derive the filepath // derive the filepath
var path = createLoginBlockPath(Env, publicKey); var path = createLoginBlockPath(Env, publicKey);

@ -160,7 +160,7 @@ Channel.isNewChannel = function (Env, channel, cb) {
Otherwise behaves the same as sending to a channel 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 channelId = args[0];
var msg = args[1]; var msg = args[1];

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

@ -8,10 +8,12 @@ const Core = require("./core");
const Util = require("../common-util"); const Util = require("../common-util");
const batchMetadata = BatchRead("GET_METADATA"); 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 (!Core.isValidId(channel)) { return void cb('INVALID_CHAN'); }
if (channel.length !== 32) { return cb("INVALID_CHAN_LENGTH"); } 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) { batchMetadata(channel, cb, function (done) {
var ref = {}; var ref = {};
var lineHandler = Meta.createLineHandler(ref, Env.Log.error); var lineHandler = Meta.createLineHandler(ref, Env.Log.error);

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

@ -18,98 +18,30 @@ var RPC = module.exports;
const Store = require("../storage/file"); const Store = require("../storage/file");
const BlobStore = require("../storage/blob"); const BlobStore = require("../storage/blob");
const UNAUTHENTICATED_CALLS = [ const UNAUTHENTICATED_CALLS = {
'GET_FILE_SIZE', GET_FILE_SIZE: Pinning.getFileSize, // XXX TEST
'GET_METADATA', GET_MULTIPLE_FILE_SIZE: Pinning.getMultipleFileSize,
'GET_MULTIPLE_FILE_SIZE', GET_DELETED_PADS: Pinning.getDeletedPads,
'IS_CHANNEL_PINNED', IS_CHANNEL_PINNED: Pinning.isChannelPinned,
'IS_NEW_CHANNEL', IS_NEW_CHANNEL: Channel.isNewChannel,
'GET_DELETED_PADS', WRITE_PRIVATE_MESSAGE: Channel.writePrivateMessage,
'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;
}; };
var isUnauthenticateMessage = function (msg) { 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) { var handleUnauthenticatedMessage = function (Env, msg, respond, Server) {
Env.Log.silly('LOG_RPC', msg[0]); Env.Log.silly('LOG_RPC', msg[0]);
switch (msg[0]) {
case 'GET_FILE_SIZE': var method = UNAUTHENTICATED_CALLS[msg[0]];
return void Pinning.getFileSize(Env, msg[1], function (e, size) { method(Env, msg[1], function (err, value) {
Env.WARN(e, msg[1]); if (err) {
respond(e, [null, size, null]); Env.WARN(err, msg[1]);
}); return void respond(err);
case 'GET_METADATA': }
return void Metadata.getMetadata(Env, msg[1], function (e, data) { respond(err, [null, value, null]);
Env.WARN(e, msg[1]); }, Server);
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);
}
}; };
const AUTHENTICATED_USER_TARGETED = { const AUTHENTICATED_USER_TARGETED = {
@ -124,6 +56,9 @@ const AUTHENTICATED_USER_TARGETED = {
UPLOAD_COMPLETE: Upload.complete, UPLOAD_COMPLETE: Upload.complete,
UPLOAD_CANCEL: Upload.cancel, UPLOAD_CANCEL: Upload.cancel,
OWNED_UPLOAD_COMPLETE: Upload.complete_owned, OWNED_UPLOAD_COMPLETE: Upload.complete_owned,
WRITE_LOGIN_BLOCK: Block.writeLoginBlock,
REMOVE_LOGIN_BLOCK: Block.removeLoginBlock,
ADMIN: Admin.command,
}; };
const AUTHENTICATED_USER_SCOPED = { const AUTHENTICATED_USER_SCOPED = {
@ -135,13 +70,33 @@ const AUTHENTICATED_USER_SCOPED = {
REMOVE_PINS: Pinning.removePins, REMOVE_PINS: Pinning.removePins,
TRIM_PINS: Pinning.trimPins, TRIM_PINS: Pinning.trimPins,
SET_METADATA: Metadata.setMetadata, SET_METADATA: Metadata.setMetadata,
COOKIE: Core.haveACookie,
};
var isAuthenticatedCall = function (call) {
if (call === 'UPLOAD') { return false; }
return typeof(AUTHENTICATED_USER_TARGETED[call] || AUTHENTICATED_USER_SCOPED[call]) === 'function';
}; };
var handleAuthenticatedMessage = function (Env, map) { var handleAuthenticatedMessage = function (Env, unsafeKey, msg, respond, Server) {
var msg = map.msg; /* If you have gotten this far, you have signed the message with the
var safeKey = map.safeKey; public key which you provided.
var Respond = map.Respond; */
var Server = map.Server;
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]; 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) { return void AUTHENTICATED_USER_TARGETED[TYPE](Env, safeKey, msg[1], function (e, value) {
Env.WARN(e, value); Env.WARN(e, value);
return void Respond(e, value); return void Respond(e, value);
}); }, Server);
} }
if (typeof(AUTHENTICATED_USER_SCOPED[TYPE]) === 'function') { if (typeof(AUTHENTICATED_USER_SCOPED[TYPE]) === 'function') {
@ -164,35 +119,7 @@ var handleAuthenticatedMessage = function (Env, map) {
}); });
} }
switch (msg[0]) { return void Respond('UNSUPPORTED_RPC_CALL', msg);
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);
}
}; };
var rpc = function (Env, Server, data, respond) { 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'); return void respond('INVALID_MESSAGE_OR_PUBLIC_KEY');
} }
if (isAuthenticatedCall(msg[1])) { var command = msg[1];
if (Core.checkSignature(Env, serialized, signature, publicKey) !== true) {
return void respond("INVALID_SIGNATURE_OR_PUBLIC_KEY");
}
} else if (msg[1] !== 'UPLOAD') {
Env.Log.warn('INVALID_RPC_CALL', msg[1]);
return void respond("INVALID_RPC_CALL");
}
var safeKey = Util.escapeKeyCharacters(publicKey); if (command === 'UPLOAD') {
/* If you have gotten this far, you have signed the message with the // UPLOAD is a special case that skips signature validation
public key which you provided. // intentional fallthrough behaviour
return void handleAuthenticatedMessage(Env, publicKey, msg, respond, Server);
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');
} }
if (isAuthenticatedCall(command)) {
handleAuthenticatedMessage(Env, { // check the signature on the message
msg: msg, // refuse the command if it doesn't validate
safeKey: safeKey, if (Core.checkSignature(Env, serialized, signature, publicKey) === true) {
Respond: Respond, return void handleAuthenticatedMessage(Env, publicKey, msg, respond, Server);
Server: Server, }
}); return void respond("INVALID_SIGNATURE_OR_PUBLIC_KEY");
}
Env.Log.warn('INVALID_RPC_CALL', command);
return void respond("INVALID_RPC_CALL");
}; };
RPC.create = function (config, cb) { 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 = { var Env = {
historyKeeper: config.historyKeeper, historyKeeper: config.historyKeeper,
intervals: config.intervals || {}, intervals: config.intervals || {},

Loading…
Cancel
Save