cryptpad/customize.dist/user.js

190 lines
5.2 KiB
JavaScript

define([
'/api/config?cb=' + Math.random().toString().slice(2),
'/customize/messages.js',
'/bower_components/chainpad-listmap/chainpad-listmap.js',
'/bower_components/chainpad-crypto/crypto.js',
'/customize/store.js',
'/bower_components/scrypt-async/scrypt-async.min.js',
'/bower_components/tweetnacl/nacl-fast.min.js',
], function (Config, Messages, Listmap, Crypto, Store) {
var Scrypt = window.scrypt;
var Nacl = window.nacl;
var User = {};
var localKey = User.localKey = 'cryptpad_user_session';
var store;
Store.ready(function (err, s) {
if (err) {
console.error(err);
return;
}
store = s;
});
var isArray = function (o) { return Object.prototype.toString.call(o) === '[object Array]'; };
var session = User.session = function (secret, cb) {
if (secret) {
store.set(localKey, secret, cb);
return;
}
if (secret === null) {
store.remove(localKey, cb);
}
store.get(localKey, cb);
};
/* 64 uint8s symmetric keys
32 b64 channel
16 b64 key
16 b64 junk
32 uint8s ed signing key
32 uint8s curve public key */
var parse128 = function (A) {
if (A.length !== 128) {
throw new Error("Expected 128 uint8s!");
}
var symmetric = Nacl.util.encodeBase64(A.slice(0, 36));
return {
ed: A.slice(96),
curve: A.slice(64, 96),
channel: symmetric.slice(0, 32),
key: symmetric.slice(32),
extra: A.slice(36, 64),
};
};
var initialize = User.initialize = function (proxy, secret, cb) {
proxy.on('ready', function (info) {
var now = ''+new Date();
// old atime
var otime = proxy.atime;
var atime = proxy.atime = now;
// creation time
proxy.ctime = proxy.ctime || now;
proxy.username = proxy.username || secret.username;
proxy.schema = proxy.schema || 'login_data-v0';
proxy.documents = proxy.documents || [];
cb(void 0, proxy);
});
};
/*
cb(proxy);
*/
var connect = User.connect = function (secret, cb) {
if (!secret) {
// FIXME
return;
}
var config = {
websocketURL: Config.websocketURL,
channel: secret.channel,
data: {},
crypto: Crypto.createEncryptor(secret.key),
logLevel: 0,
};
var rt = Listmap.create(config);
initialize(rt.proxy, secret, cb);
};
var disconnect = User.disconnect = function (cb) {
var err = "User.disconnect is not implemented yet";
cb(err);
};
var genSecret = User.genSecret = function (uname, pw, cb) {
Scrypt(pw,
uname,
15, // memory cost parameter
8, // block size parameter
128, // derived key length
200, // interruptStep
function (bytes) {
var secret = parse128(bytes);
secret.username = uname;
cb(void 0, secret);
});
};
/* Asynchronously derive 128 random uint8s given a uname and password
cb(proxy, secret)
*/
var login = User.login = function (uname, pw, cb) {
genSecret(uname, pw, function (err, secret) {
session(secret, function (err) {
connect(secret, cb);
});
});
};
var prepareStore = User.prepareStore = function (proxy) {
var store = {};
var ps = proxy.store = proxy.store || {};
var set = store.set = function (key, val, cb) {
ps[key] = val;
cb();
};
var batchset = store.setBatch = function (map, cb) {
if (isArray(map) || typeof(map) !== 'object') {
cb('[setBatch.TypeError] expected key-value pairs to set');
return;
}
Object.keys(map).forEach(function (k) {
ps[k] = map[k];
});
cb();
};
var get = store.get = function (key, cb) {
cb(void 0, ps[key]);
};
var batchget = store.getBatch = function (keys, cb) {
if (!isArray(keys)) {
cb('[getBatch.TypeError] expected array of keys to return');
return;
}
var map = {};
keys.forEach(function (k) {
map[k] = ps[k];
});
cb(void 0, map);
};
var remove = store.remove = function (key, cb) {
ps[key] = undefined;
cb();
};
var batchremove = store.removeBatch = function (keys, cb) {
if (!isArray(keys)) {
cb('[batchremove.TypeError] expected array of keys to remove');
return;
}
keys.forEach(function (k) {
ps[k] = undefined;
});
cb();
};
var keys = store.keys = function (cb) {
cb(void 0, Object.keys(ps));
};
return store;
};
return User;
});