mirror of https://github.com/xwiki-labs/cryptpad
separate validation and storage methods for blocks
This commit is contained in:
parent
9806d718d5
commit
ba1a7b37e1
|
@ -1,14 +1,10 @@
|
|||
/*jshint esversion: 6 */
|
||||
/* globals Buffer*/
|
||||
var Block = module.exports;
|
||||
|
||||
const Fs = require("fs");
|
||||
const Fse = require("fs-extra");
|
||||
const Path = require("path");
|
||||
const Block = module.exports;
|
||||
const Nacl = require("tweetnacl/nacl-fast");
|
||||
const nThen = require("nthen");
|
||||
|
||||
const Util = require("../common-util");
|
||||
const BlockStore = require("../storage/block");
|
||||
|
||||
/*
|
||||
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
|
||||
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
|
||||
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);
|
||||
};
|
||||
|
||||
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) {
|
||||
var cb = Util.once(Util.mkAsync(_cb));
|
||||
/* 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');
|
||||
}
|
||||
// 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 () {
|
||||
cb(void 0, pub);
|
||||
Block.check(Env, pub, function (err) {
|
||||
if (err) { return void cb('E_MISSING_ANCESTOR'); }
|
||||
cb(void 0, pub);
|
||||
});
|
||||
});
|
||||
} catch (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));
|
||||
//console.log(msg);
|
||||
var publicKey = msg[0];
|
||||
var signature = msg[1];
|
||||
var block = msg[2];
|
||||
var registrationProof = msg[3];
|
||||
var previousKey;
|
||||
|
||||
var validatedBlock, parsed, path;
|
||||
var validatedBlock, path;
|
||||
nThen(function (w) {
|
||||
if (Util.escapeKeyCharacters(publicKey) !== safeKey) {
|
||||
w.abort();
|
||||
|
@ -181,33 +146,9 @@ Block.writeLoginBlock = function (Env, safeKey, msg, _cb) { // FIXME BLOCKS
|
|||
}
|
||||
|
||||
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 () {
|
||||
// actually write the block
|
||||
Fs.writeFile(path, Buffer.from(validatedBlock), { encoding: "binary", }, function (err) {
|
||||
if (err) { return void cb(err); }
|
||||
BlockStore.write(Env, publicKey, Buffer.from(validatedBlock), function (err) {
|
||||
Env.Log.info('BLOCK_WRITE_BY_OWNER', {
|
||||
safeKey: safeKey,
|
||||
blockId: publicKey,
|
||||
|
@ -215,11 +156,13 @@ Block.writeLoginBlock = function (Env, safeKey, msg, _cb) { // FIXME BLOCKS
|
|||
previousKey: previousKey,
|
||||
path: path,
|
||||
});
|
||||
cb();
|
||||
cb(err);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
const DELETE_BLOCK = Nacl.util.decodeUTF8('DELETE_BLOCK');
|
||||
|
||||
/*
|
||||
When users write a block, they upload the block, and provide
|
||||
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.
|
||||
|
||||
*/
|
||||
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 signature = msg[1];
|
||||
var block = Nacl.util.decodeUTF8('DELETE_BLOCK'); // clients and the server will have to agree on this constant
|
||||
|
||||
nThen(function (w) {
|
||||
if (Util.escapeKeyCharacters(publicKey) !== safeKey) {
|
||||
|
@ -241,33 +185,14 @@ Block.removeLoginBlock = function (Env, safeKey, msg, cb) {
|
|||
return void cb("INCORRECT_KEY");
|
||||
}
|
||||
}).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); }
|
||||
// derive the filepath
|
||||
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) {
|
||||
BlockStore.archive(Env, publicKey, function (err) {
|
||||
Env.Log.info('ARCHIVAL_BLOCK_BY_OWNER_RPC', {
|
||||
publicKey: publicKey,
|
||||
currentPath: currentPath,
|
||||
archivePath: archivePath,
|
||||
status: err? String(err): 'SUCCESS',
|
||||
});
|
||||
if (err) { return void cb(err); }
|
||||
cb();
|
||||
cb(err);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -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…
Reference in New Issue