check for the presence of a blockHash in localStorage when logging in
This commit is contained in:
parent
3ba0ad3cf1
commit
d03339f20b
7 changed files with 157 additions and 14 deletions
3
rpc.js
3
rpc.js
|
@ -1380,8 +1380,7 @@ var createLoginBlockPath = function (Env, publicKey) {
|
||||||
};
|
};
|
||||||
|
|
||||||
var writeLoginBlock = function (Env, msg, cb) {
|
var writeLoginBlock = function (Env, msg, cb) {
|
||||||
console.log(msg); // XXX
|
//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];
|
||||||
|
|
|
@ -10,9 +10,12 @@ define([
|
||||||
'/common/wire.js',
|
'/common/wire.js',
|
||||||
'/common/flat-dom.js',
|
'/common/flat-dom.js',
|
||||||
'/common/media-tag.js',
|
'/common/media-tag.js',
|
||||||
|
|
||||||
|
'/bower_components/tweetnacl/nacl-fast.min.js',
|
||||||
], function ($, Hyperjson, Sortify, Drive, Test, Hash, Util, Thumb, Wire, Flat, MediaTag) {
|
], function ($, Hyperjson, Sortify, Drive, Test, Hash, Util, Thumb, Wire, Flat, MediaTag) {
|
||||||
window.Hyperjson = Hyperjson;
|
window.Hyperjson = Hyperjson;
|
||||||
window.Sortify = Sortify;
|
window.Sortify = Sortify;
|
||||||
|
var Nacl = window.nacl;
|
||||||
|
|
||||||
var assertions = 0;
|
var assertions = 0;
|
||||||
var failed = false;
|
var failed = false;
|
||||||
|
@ -296,6 +299,18 @@ define([
|
||||||
!secret.hashData.present);
|
!secret.hashData.present);
|
||||||
}, "test support for ugly tracking query paramaters in url");
|
}, "test support for ugly tracking query paramaters in url");
|
||||||
|
|
||||||
|
assert(function (cb) {
|
||||||
|
var href = 'https://cryptpad.fr/block/pe/pewpewpewpewpew';
|
||||||
|
var key = Nacl.randomBytes(32);
|
||||||
|
|
||||||
|
var hash = Hash.createBlockHash(href, key);
|
||||||
|
|
||||||
|
var parsed = Hash.parseBlockHash(hash);
|
||||||
|
|
||||||
|
cb(parsed && href === parsed.href &&
|
||||||
|
parsed.keys.symmetric.length === key.length);
|
||||||
|
}, 'parse a block hash');
|
||||||
|
|
||||||
assert(function (cb) {
|
assert(function (cb) {
|
||||||
try {
|
try {
|
||||||
MediaTag(void 0).on('progress').on('decryption');
|
MediaTag(void 0).on('progress').on('decryption');
|
||||||
|
|
|
@ -474,6 +474,43 @@ Version 1
|
||||||
'/' + curvePublic.replace(/\//g, '-') + '/';
|
'/' + curvePublic.replace(/\//g, '-') + '/';
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// XXX consider putting Block functions in /common/outer/login-block.js
|
||||||
|
Hash.createBlockHash = function (href, key) {
|
||||||
|
if (typeof(href) !== 'string') { return; }
|
||||||
|
if (!key instanceof Uint8Array) { return; }
|
||||||
|
|
||||||
|
// TODO verify inputs
|
||||||
|
try { return href + '#' + Nacl.util.encodeBase64(key); }
|
||||||
|
catch (e) { return; }
|
||||||
|
};
|
||||||
|
|
||||||
|
var decodeSafeB64 = function (b64) {
|
||||||
|
try {
|
||||||
|
return Nacl.util.decodeBase64(b64.replace(/\-/g, '/'));
|
||||||
|
} catch (e) {
|
||||||
|
console.error(e);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Hash.parseBlockHash = function (hash) {
|
||||||
|
if (typeof(hash) !== 'string') { return; }
|
||||||
|
var parts = hash.split('#');
|
||||||
|
if (parts.length !== 2) { return; }
|
||||||
|
|
||||||
|
try {
|
||||||
|
return {
|
||||||
|
href: parts[0],
|
||||||
|
keys: {
|
||||||
|
symmetric: decodeSafeB64(parts[1]),
|
||||||
|
}
|
||||||
|
};
|
||||||
|
} catch (e) {
|
||||||
|
console.error(e);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
// Create untitled documents when no name is given
|
// Create untitled documents when no name is given
|
||||||
var getLocaleDate = function () {
|
var getLocaleDate = function () {
|
||||||
if (window.Intl && window.Intl.DateTimeFormat) {
|
if (window.Intl && window.Intl.DateTimeFormat) {
|
||||||
|
|
|
@ -137,17 +137,15 @@ define([], function () {
|
||||||
else if (bytes >= oneMegabyte) { return 'MB'; }
|
else if (bytes >= oneMegabyte) { return 'MB'; }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// given a path, asynchronously return an arraybuffer
|
||||||
Util.fetch = function (src, cb) {
|
Util.fetch = function (src, cb) {
|
||||||
var done = false;
|
var done = false;
|
||||||
var CB = function (err, res) {
|
var CB = Util.once(cb);
|
||||||
if (done) { return; }
|
|
||||||
done = true;
|
|
||||||
cb(err, res);
|
|
||||||
};
|
|
||||||
|
|
||||||
var xhr = new XMLHttpRequest();
|
var xhr = new XMLHttpRequest();
|
||||||
xhr.open("GET", src, true);
|
xhr.open("GET", src, true);
|
||||||
xhr.responseType = "arraybuffer";
|
xhr.responseType = "arraybuffer";
|
||||||
|
xhr.onerror = function (err) { CB(err); };
|
||||||
xhr.onload = function () {
|
xhr.onload = function () {
|
||||||
if (/^4/.test(''+this.status)) {
|
if (/^4/.test(''+this.status)) {
|
||||||
return CB('XHR_ERROR');
|
return CB('XHR_ERROR');
|
||||||
|
|
|
@ -8,11 +8,12 @@ define([
|
||||||
'/common/common-feedback.js',
|
'/common/common-feedback.js',
|
||||||
'/common/outer/local-store.js',
|
'/common/outer/local-store.js',
|
||||||
'/common/outer/worker-channel.js',
|
'/common/outer/worker-channel.js',
|
||||||
|
'/common/outer/login-block.js',
|
||||||
|
|
||||||
'/customize/application_config.js',
|
'/customize/application_config.js',
|
||||||
'/bower_components/nthen/index.js',
|
'/bower_components/nthen/index.js',
|
||||||
], function (Config, Messages, Util, Hash,
|
], function (Config, Messages, Util, Hash,
|
||||||
Messaging, Constants, Feedback, LocalStore, Channel,
|
Messaging, Constants, Feedback, LocalStore, Channel, Block,
|
||||||
AppConfig, Nthen) {
|
AppConfig, Nthen) {
|
||||||
|
|
||||||
/* This file exposes functionality which is specific to Cryptpad, but not to
|
/* This file exposes functionality which is specific to Cryptpad, but not to
|
||||||
|
@ -883,7 +884,46 @@ define([
|
||||||
if (AppConfig.beforeLogin) {
|
if (AppConfig.beforeLogin) {
|
||||||
AppConfig.beforeLogin(LocalStore.isLoggedIn(), waitFor());
|
AppConfig.beforeLogin(LocalStore.isLoggedIn(), waitFor());
|
||||||
}
|
}
|
||||||
|
|
||||||
}).nThen(function (waitFor) {
|
}).nThen(function (waitFor) {
|
||||||
|
var blockHash = LocalStore.getBlockHash();
|
||||||
|
|
||||||
|
if (blockHash) {
|
||||||
|
console.log(blockHash);
|
||||||
|
var parsed = Hash.parseBlockHash(blockHash);
|
||||||
|
|
||||||
|
if (typeof(parsed) !== 'object') {
|
||||||
|
console.error("Failed to parse blockHash");
|
||||||
|
console.log(parsed);
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
console.log(parsed);
|
||||||
|
}
|
||||||
|
Util.fetch(parsed.href, waitFor(function (err, arraybuffer) {
|
||||||
|
if (err) { return void console.log(err); }
|
||||||
|
|
||||||
|
// use the results to load your user hash and
|
||||||
|
// put your userhash into localStorage
|
||||||
|
try {
|
||||||
|
var block_info = Block.decrypt(arraybuffer, parsed.keys);
|
||||||
|
if (block_info[Constants.userHashKey]) { LocalStore.setUserHash(block_info[Constants.userHashKey]); }
|
||||||
|
} catch (e) {
|
||||||
|
console.error(e);
|
||||||
|
return void console.error("failed to decrypt or decode block content");
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
} else {
|
||||||
|
// XXX debugging
|
||||||
|
console.error("NO BLOCK HASH");
|
||||||
|
}
|
||||||
|
}).nThen(function (waitFor) {
|
||||||
|
// XXX debugging
|
||||||
|
if (LocalStore.getUserHash()) {
|
||||||
|
console.log('User_hash detected');
|
||||||
|
} else {
|
||||||
|
console.log("User_hash not detected");
|
||||||
|
}
|
||||||
|
|
||||||
var cfg = {
|
var cfg = {
|
||||||
init: true,
|
init: true,
|
||||||
//query: onMessage, // TODO temporary, will be replaced by a webworker channel
|
//query: onMessage, // TODO temporary, will be replaced by a webworker channel
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
define([
|
define([
|
||||||
'/common/common-util.js',
|
'/common/common-util.js',
|
||||||
|
'/api/config',
|
||||||
'/bower_components/tweetnacl/nacl-fast.min.js',
|
'/bower_components/tweetnacl/nacl-fast.min.js',
|
||||||
], function (Util) {
|
], function (Util, ApiConfig) {
|
||||||
var Nacl = window.nacl;
|
var Nacl = window.nacl;
|
||||||
|
|
||||||
var Block = {};
|
var Block = {};
|
||||||
|
@ -30,9 +31,11 @@ define([
|
||||||
var symmetric = seed.subarray(Nacl.sign.seedLength,
|
var symmetric = seed.subarray(Nacl.sign.seedLength,
|
||||||
Nacl.sign.seedLength + Nacl.secretbox.keyLength);
|
Nacl.sign.seedLength + Nacl.secretbox.keyLength);
|
||||||
|
|
||||||
|
console.log("symmetric key: ", Nacl.util.encodeBase64(symmetric));
|
||||||
|
|
||||||
return {
|
return {
|
||||||
sign: Nacl.sign.keyPair.fromSeed(signSeed), // 32 bytes
|
sign: Nacl.sign.keyPair.fromSeed(signSeed), // 32 bytes
|
||||||
symmetric: symmetric,
|
symmetric: symmetric, // 32 bytes ...
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -51,8 +54,15 @@ define([
|
||||||
Block.decrypt = function (u8_content, keys) {
|
Block.decrypt = function (u8_content, keys) {
|
||||||
// version is currently ignored since there is only one
|
// version is currently ignored since there is only one
|
||||||
var nonce = u8_content.subarray(1, 1 + Nacl.secretbox.nonceLength);
|
var nonce = u8_content.subarray(1, 1 + Nacl.secretbox.nonceLength);
|
||||||
var box = content.subarray(1 + Nacl.secretbox.nonceLength);
|
var box = u8_content.subarray(1 + Nacl.secretbox.nonceLength);
|
||||||
return Nacl.secretbox.open(box, nonce, keys.symmetric);
|
|
||||||
|
var plaintext = Nacl.secretbox.open(box, nonce, keys.symmetric);
|
||||||
|
try {
|
||||||
|
return JSON.parse(Nacl.util.encodeUTF8(plaintext));
|
||||||
|
} catch (e) {
|
||||||
|
console.error(e);
|
||||||
|
return;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// (Uint8Array block) => signature
|
// (Uint8Array block) => signature
|
||||||
|
@ -86,5 +96,18 @@ define([
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// FIXME don't spread the functions below across this file and common-hash
|
||||||
|
// find a permanent home for these hacks
|
||||||
|
var urlSafeB64 = function (u8) {
|
||||||
|
return Nacl.util.encodeBase64(u8).replace(/\//g, '-');
|
||||||
|
};
|
||||||
|
|
||||||
|
Block.getBlockHash = function (keys) {
|
||||||
|
var publicKey = urlSafeB64(keys.sign.publicKey);
|
||||||
|
var relative = 'block/' + publicKey.slice(0, 2) + '/' + publicKey; // XXX FIXME use configurable path from /api/config
|
||||||
|
var symmetric = urlSafeB64(keys.symmetric);
|
||||||
|
return ApiConfig.httpUnsafeOrigin + relative + '#' + symmetric;
|
||||||
|
};
|
||||||
|
|
||||||
return Block;
|
return Block;
|
||||||
});
|
});
|
||||||
|
|
|
@ -11,6 +11,7 @@ define([
|
||||||
'/common/hyperscript.js',
|
'/common/hyperscript.js',
|
||||||
'/customize/application_config.js',
|
'/customize/application_config.js',
|
||||||
'/api/config',
|
'/api/config',
|
||||||
|
'/common/outer/login-block.js', // XXX HACK
|
||||||
|
|
||||||
'/bower_components/file-saver/FileSaver.min.js',
|
'/bower_components/file-saver/FileSaver.min.js',
|
||||||
'css!/bower_components/bootstrap/dist/css/bootstrap.min.css',
|
'css!/bower_components/bootstrap/dist/css/bootstrap.min.css',
|
||||||
|
@ -28,7 +29,8 @@ define([
|
||||||
Messages,
|
Messages,
|
||||||
h,
|
h,
|
||||||
AppConfig,
|
AppConfig,
|
||||||
ApiConfig
|
ApiConfig,
|
||||||
|
Block // XXX HACK
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
var saveAs = window.saveAs;
|
var saveAs = window.saveAs;
|
||||||
|
@ -389,7 +391,36 @@ define([
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
updateBlock = updateBlock; // jshint..
|
var removeBlock = function (data, cb) {
|
||||||
|
sframeChan.query('Q_REMOVE_LOGIN_BLOCK', data, function (err, obj) {
|
||||||
|
if (err || obj.error) { return void cb ({error: err || obj.error}); }
|
||||||
|
cb (obj);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// XXX
|
||||||
|
if (false) { // STUBBED, just for development purposes
|
||||||
|
console.error("TRYING TO WRITE A BLOCK");
|
||||||
|
|
||||||
|
var keys = Block.genkeys(Block.seed());
|
||||||
|
var data = Block.serialize(JSON.stringify({
|
||||||
|
a: 5,
|
||||||
|
b: 6,
|
||||||
|
User_hash: "XXX", /// TODO encode newly derived User_hash here
|
||||||
|
}), keys);
|
||||||
|
|
||||||
|
updateBlock(data, function (err, thing) {
|
||||||
|
console.log(err, thing);
|
||||||
|
|
||||||
|
console.log(Block.getBlockHash(keys));
|
||||||
|
|
||||||
|
return;
|
||||||
|
removeBlock(Block.remove(keys), function (err, obj) {
|
||||||
|
console.log(err, obj);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
return $div;
|
return $div;
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in a new issue