separate validation and storage methods for blocks

pull/1/head
ansuz 3 years ago
parent 9806d718d5
commit ba1a7b37e1

@ -1,14 +1,10 @@
/*jshint esversion: 6 */ /*jshint esversion: 6 */
/* globals Buffer*/ /* globals Buffer*/
var Block = module.exports; const Block = module.exports;
const Fs = require("fs");
const Fse = require("fs-extra");
const Path = require("path");
const Nacl = require("tweetnacl/nacl-fast"); const Nacl = require("tweetnacl/nacl-fast");
const nThen = require("nthen"); const nThen = require("nthen");
const Util = require("../common-util"); const Util = require("../common-util");
const BlockStore = require("../storage/block");
/* /*
We assume that the server is secured against MitM attacks We assume that the server is secured against MitM attacks
@ -31,7 +27,9 @@ 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.
*/ */
var validateLoginBlock = function (Env, publicKey, signature, block, cb) { // FIXME BLOCKS var validateLoginBlock = function (Env, publicKey, signature, block, _cb) { // FIXME BLOCKS
var cb = Util.once(Util.mkAsync(_cb));
// 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'); }
@ -72,34 +70,6 @@ var validateLoginBlock = function (Env, publicKey, signature, block, cb) { // FI
return void cb(null, u8_block); return void cb(null, u8_block);
}; };
var createLoginBlockPath = function (Env, publicKey) { // FIXME BLOCKS
// prepare publicKey to be used as a file name
var safeKey = Util.escapeKeyCharacters(publicKey);
// validate safeKey
if (typeof(safeKey) !== 'string') {
return;
}
// derive the full path
// /home/cryptpad/cryptpad/block/fg/fg32kefksjdgjkewrjksdfksjdfsdfskdjfsfd
return Path.join(Env.paths.block, safeKey.slice(0, 2), safeKey);
};
var createLoginBlockArchivePath = function (Env, publicKey) {
// prepare publicKey to be used as a file name
var safeKey = Util.escapeKeyCharacters(publicKey);
// validate safeKey
if (typeof(safeKey) !== 'string') {
return;
}
// derive the full path
// /home/cryptpad/cryptpad/block/fg/fg32kefksjdgjkewrjksdfksjdfsdfskdjfsfd
return Path.join(Env.paths.archive, 'block', safeKey.slice(0, 2), safeKey);
};
Block.validateAncestorProof = function (Env, proof, _cb) { Block.validateAncestorProof = function (Env, proof, _cb) {
var cb = Util.once(Util.mkAsync(_cb)); var cb = Util.once(Util.mkAsync(_cb));
/* prove that you own an existing block by signing for its publicKey */ /* prove that you own an existing block by signing for its publicKey */
@ -117,31 +87,26 @@ Block.validateAncestorProof = function (Env, proof, _cb) {
return void cb('E_INVALID_ANCESTOR_PROOF'); return void cb('E_INVALID_ANCESTOR_PROOF');
} }
// else fall through to next step // else fall through to next step
}).nThen(function (w) {
var path = createLoginBlockPath(Env, pub);
Fs.access(path, Fs.constants.F_OK, w(function (err) {
if (!err) { return; }
w.abort(); // else
return void cb("E_MISSING_ANCESTOR");
}));
}).nThen(function () { }).nThen(function () {
cb(void 0, pub); Block.check(Env, pub, function (err) {
if (err) { return void cb('E_MISSING_ANCESTOR'); }
cb(void 0, pub);
});
}); });
} catch (err) { } catch (err) {
return void cb(err); return void cb(err);
} }
}; };
Block.writeLoginBlock = function (Env, safeKey, msg, _cb) { // FIXME BLOCKS Block.writeLoginBlock = function (Env, safeKey, msg, _cb) {
var cb = Util.once(Util.mkAsync(_cb)); var cb = Util.once(Util.mkAsync(_cb));
//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];
var registrationProof = msg[3]; var registrationProof = msg[3];
var previousKey; var previousKey;
var validatedBlock, parsed, path; var validatedBlock, path;
nThen(function (w) { nThen(function (w) {
if (Util.escapeKeyCharacters(publicKey) !== safeKey) { if (Util.escapeKeyCharacters(publicKey) !== safeKey) {
w.abort(); w.abort();
@ -181,33 +146,9 @@ Block.writeLoginBlock = function (Env, safeKey, msg, _cb) { // FIXME BLOCKS
} }
validatedBlock = _validatedBlock; validatedBlock = _validatedBlock;
// derive the filepath
path = createLoginBlockPath(Env, publicKey);
// make sure the path is valid
if (typeof(path) !== 'string') {
return void cb('E_INVALID_BLOCK_PATH');
}
parsed = Path.parse(path);
if (!parsed || typeof(parsed.dir) !== 'string') {
w.abort();
return void cb("E_INVALID_BLOCK_PATH_2");
}
}));
}).nThen(function (w) {
// make sure the path to the file exists
Fse.mkdirp(parsed.dir, w(function (e) {
if (e) {
w.abort();
cb(e);
}
})); }));
}).nThen(function () { }).nThen(function () {
// actually write the block BlockStore.write(Env, publicKey, Buffer.from(validatedBlock), function (err) {
Fs.writeFile(path, Buffer.from(validatedBlock), { encoding: "binary", }, function (err) {
if (err) { return void cb(err); }
Env.Log.info('BLOCK_WRITE_BY_OWNER', { Env.Log.info('BLOCK_WRITE_BY_OWNER', {
safeKey: safeKey, safeKey: safeKey,
blockId: publicKey, blockId: publicKey,
@ -215,11 +156,13 @@ Block.writeLoginBlock = function (Env, safeKey, msg, _cb) { // FIXME BLOCKS
previousKey: previousKey, previousKey: previousKey,
path: path, path: path,
}); });
cb(); cb(err);
}); });
}); });
}; };
const DELETE_BLOCK = Nacl.util.decodeUTF8('DELETE_BLOCK');
/* /*
When users write a block, they upload the block, and provide When users write a block, they upload the block, and provide
a signature proving that they deserve to be able to write to a signature proving that they deserve to be able to write to
@ -230,10 +173,11 @@ Block.writeLoginBlock = function (Env, safeKey, 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, safeKey, msg, cb) { Block.removeLoginBlock = function (Env, safeKey, msg, _cb) {
var cb = Util.once(Util.mkAsync(_cb));
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
nThen(function (w) { nThen(function (w) {
if (Util.escapeKeyCharacters(publicKey) !== safeKey) { if (Util.escapeKeyCharacters(publicKey) !== safeKey) {
@ -241,33 +185,14 @@ Block.removeLoginBlock = function (Env, safeKey, msg, cb) {
return void cb("INCORRECT_KEY"); return void cb("INCORRECT_KEY");
} }
}).nThen(function () { }).nThen(function () {
validateLoginBlock(Env, publicKey, signature, block, function (e /*::, validatedBlock */) { validateLoginBlock(Env, publicKey, signature, DELETE_BLOCK, function (e /*::, validatedBlock */) {
if (e) { return void cb(e); } if (e) { return void cb(e); }
// derive the filepath BlockStore.archive(Env, publicKey, function (err) {
var currentPath = createLoginBlockPath(Env, publicKey);
// make sure the path is valid
if (typeof(currentPath) !== 'string') {
return void cb('E_INVALID_BLOCK_PATH');
}
var archivePath = createLoginBlockArchivePath(Env, publicKey);
// make sure the path is valid
if (typeof(archivePath) !== 'string') {
return void cb('E_INVALID_BLOCK_ARCHIVAL_PATH');
}
Fse.move(currentPath, archivePath, {
overwrite: true,
}, function (err) {
Env.Log.info('ARCHIVAL_BLOCK_BY_OWNER_RPC', { Env.Log.info('ARCHIVAL_BLOCK_BY_OWNER_RPC', {
publicKey: publicKey, publicKey: publicKey,
currentPath: currentPath,
archivePath: archivePath,
status: err? String(err): 'SUCCESS', status: err? String(err): 'SUCCESS',
}); });
if (err) { return void cb(err); } cb(err);
cb();
}); });
}); });
}); });

@ -0,0 +1,92 @@
/*jshint esversion: 6 */
const Block = module.exports;
const Util = require("../common-util");
const Path = require("path");
const Fs = require("fs");
const Fse = require("fs-extra");
const nThen = require("nthen");
Block.mkPath = function (Env, publicKey) {
// prepare publicKey to be used as a file name
var safeKey = Util.escapeKeyCharacters(publicKey);
// validate safeKey
if (typeof(safeKey) !== 'string') { return; }
// derive the full path
// /home/cryptpad/cryptpad/block/fg/fg32kefksjdgjkewrjksdfksjdfsdfskdjfsfd
return Path.join(Env.paths.block, safeKey.slice(0, 2), safeKey);
};
Block.mkArchivePath = function (Env, publicKey) {
// prepare publicKey to be used as a file name
var safeKey = Util.escapeKeyCharacters(publicKey);
// validate safeKey
if (typeof(safeKey) !== 'string') {
return;
}
// derive the full path
// /home/cryptpad/cryptpad/block/fg/fg32kefksjdgjkewrjksdfksjdfsdfskdjfsfd
return Path.join(Env.paths.archive, 'block', safeKey.slice(0, 2), safeKey);
};
Block.archive = function (Env, publicKey, _cb) {
var cb = Util.once(Util.mkAsync(_cb));
// derive the filepath
var currentPath = Block.mkPath(Env, publicKey);
// make sure the path is valid
if (typeof(currentPath) !== 'string') {
return void cb('E_INVALID_BLOCK_PATH');
}
var archivePath = Block.mkArchivePath(Env, publicKey);
// make sure the path is valid
if (typeof(archivePath) !== 'string') {
return void cb('E_INVALID_BLOCK_ARCHIVAL_PATH');
}
Fse.move(currentPath, archivePath, {
overwrite: true,
}, cb);
};
Block.check = function (Env, publicKey, _cb) { // 'check' because 'exists' implies boolean
var cb = Util.once(Util.mkAsync(_cb));
var path = Block.mkPath(Env, publicKey);
Fs.access(path, Fs.constants.F_OK, cb);
};
Block.write = function (Env, publicKey, buffer, _cb) {
var cb = Util.once(Util.mkAsync(_cb));
var path = Block.mkPath(Env, publicKey);
if (typeof(path) !== 'string') { return void cb('INVALID_PATH'); }
var parsed = Path.parse(path);
nThen(function (w) {
Fse.mkdirp(parsed.dir, w(function (err) {
if (!err) { return; }
w.abort();
cb(err);
}));
}).nThen(function () {
// XXX BLOCK check whether this overwrites a block
// XXX archive the old one if so
Fs.writeFile(path, buffer, { encoding: 'binary' }, cb);
});
};
/*
Block.create = function (opt, _cb) {
var cb = Util.once(Util.mkAsync(_cb));
var env = {
root: opt.root || '', // XXX
};
};
*/
Loading…
Cancel
Save