cryptpad/www/common/cryptget.js

206 lines
6.3 KiB
JavaScript
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

define([
'/bower_components/chainpad-crypto/crypto.js',
'chainpad-netflux',
'netflux-client',
'/common/common-util.js',
'/common/common-hash.js',
'/common/common-realtime.js',
'/common/outer/network-config.js',
'/common/outer/cache-store.js',
'/common/pinpad.js',
'/bower_components/nthen/index.js',
'/bower_components/chainpad/chainpad.dist.js',
], function (Crypto, CPNetflux, Netflux, Util, Hash, Realtime, NetConfig, Cache, Pinpad, nThen) {
var finish = function (S, err, doc) {
if (S.done) { return; }
S.cb((err && err.error), doc, err);
S.done = true;
if (!S.hasNetwork) {
var disconnect = Util.find(S, ['network', 'disconnect']);
if (typeof(disconnect) === 'function') { disconnect(); }
}
if (S.realtime && S.realtime.stop) {
try {
S.realtime.stop();
} catch (e) { console.error(e); }
}
var abort = Util.find(S, ['session', 'realtime', 'abort']);
if (typeof(abort) === 'function') {
S.session.realtime.sync();
abort();
}
};
var makeNetwork = function (cb) {
var wsUrl = NetConfig.getWebsocketURL();
Netflux.connect(wsUrl).then(function (network) {
cb(null, network);
}, function (err) {
cb(err);
});
};
var start = function (Session, config) {
// Create a network and authenticate with all our keys if necessary,
// then start chainpad-netflux
nThen(function (waitFor) {
if (Session.hasNetwork) { return; }
makeNetwork(waitFor(function (err, network) {
if (err) { return; }
config.network = network;
}));
}).nThen(function () {
Session.realtime = CPNetflux.start(config);
});
};
var onRejected = function (config, Session, data, cb) {
// Check if we can authenticate
if (!Array.isArray(data) || !data.length || data[0].length !== 16) {
return void cb(true);
}
if (!Array.isArray(Session.accessKeys)) { return void cb(true); }
// Authenticate
config.network.historyKeeper = data[0];
nThen(function (waitFor) {
Session.accessKeys.forEach(function (obj) {
Pinpad.create(config.network, obj, waitFor(function (e) {
console.log('done', obj);
if (e) { console.error(e); }
}));
});
}).nThen(function () {
cb();
});
};
var makeConfig = function (hash, opt) {
var secret;
if (typeof(hash) === 'string') {
// We can't use cryptget with a file or a user so we can use 'pad' as hash type
secret = Hash.getSecrets('pad', hash, opt.password);
} else if (typeof(hash) === 'object') {
// we may want to just supply options directly
// and this is the easiest place to do it
secret = hash;
}
if (!secret.keys) { secret.keys = secret.key; } // support old hashses
var config = {
websocketURL: NetConfig.getWebsocketURL(opt.origin),
channel: secret.channel,
validateKey: secret.keys.validateKey || undefined,
crypto: Crypto.createEncryptor(secret.keys),
logLevel: 0,
initialState: opt.initialState,
Cache: Cache
};
return config;
};
var isObject = function (o) {
return typeof(o) === 'object';
};
var overwrite = function (a, b) {
if (!(isObject(a) && isObject(b))) { return; }
Object.keys(b).forEach(function (k) { a[k] = b[k]; });
};
var get = function (hash, cb, opt, progress) {
if (typeof(cb) !== 'function') {
throw new Error('Cryptget expects a callback');
}
opt = opt || {};
progress = progress || function () {};
var config = makeConfig(hash, opt);
var Session = {
cb: cb,
accessKeys: opt.accessKeys,
hasNetwork: Boolean(opt.network)
};
config.onRejected = function (data, cb) {
onRejected(config, Session, data, cb);
};
config.onReady = function (info) {
var rt = Session.session = info.realtime;
Session.network = info.network;
progress(1);
finish(Session, void 0, rt.getUserDoc());
};
config.onError = function (info) {
console.warn(info);
finish(Session, info);
};
config.onChannelError = function (info) {
console.error(info);
finish(Session, info);
};
config.onCacheReady = opt.onCacheReady;
// We use the new onMessage handler to compute the progress:
// we should receive 2 checkpoints max, so 100 messages max
// We're going to consider that 1 message = 1%, and we'll send 100%
// at the end
var i = 0;
config.onMessage = function () {
i++;
progress(Math.min(0.99, i/100));
};
overwrite(config, opt);
start(Session, config);
};
var put = function (hash, doc, cb, opt) {
if (typeof(cb) !== 'function') {
throw new Error('Cryptput expects a callback');
}
opt = opt || {};
var config = makeConfig(hash, opt);
var Session = {
cb: cb,
accessKeys: opt.accessKeys,
hasNetwork: Boolean(opt.network)
};
config.onRejected = function (data, cb) {
onRejected(config, Session, data, cb);
};
config.onReady = function (info) {
var realtime = Session.session = info.realtime;
Session.network = info.network;
realtime.contentUpdate(doc);
var to = setTimeout(function () {
cb(new Error("Timeout"));
}, 15000);
Realtime.whenRealtimeSyncs(realtime, function () {
clearTimeout(to);
var doc = realtime.getAuthDoc();
realtime.abort();
finish(Session, void 0, doc);
});
};
overwrite(config, opt);
start(Session, config);
};
return {
get: get,
put: put,
};
});