You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
cryptpad/www/auth/main.js

194 lines
7.3 KiB
JavaScript

This file contains invisible Unicode characters!

This file contains invisible Unicode characters that may be processed differently from what appears below. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to reveal hidden characters.

define([
'jquery',
'/api/config',
'/common/cryptget.js',
'/common/pinpad.js',
'/common/common-constants.js',
'/common/common-hash.js',
'/common/outer/local-store.js',
'/common/outer/login-block.js',
'/common/outer/network-config.js',
'/customize/login.js',
'/common/test.js',
'/bower_components/nthen/index.js',
'/bower_components/netflux-websocket/netflux-client.js',
'/bower_components/tweetnacl/nacl-fast.min.js'
], function ($, ApiConfig, Crypt, Pinpad, Constants, Hash, LocalStore, Block, NetConfig, Login, Test, nThen, Netflux) {
var Nacl = window.nacl;
var signMsg = function (msg, privKey) {
var signKey = Nacl.util.decodeBase64(privKey);
var buffer = Nacl.util.decodeUTF8(msg);
return Nacl.util.encodeBase64(Nacl.sign(buffer, signKey));
};
// TODO: Allow authing for any domain as long as the user clicks an "accept" button
// inside of the iframe.
var AUTHORIZED_DOMAINS = [
/\.cryptpad\.fr$/,
/^http(s)?:\/\/localhost\:/
];
// Safari is weird about localStorage in iframes but seems to let sessionStorage slide.
localStorage[Constants.userHashKey] = localStorage[Constants.userHashKey] ||
sessionStorage[Constants.userHashKey];
var proxy;
var rpc;
var network;
var rpcError;
var contacts = {};
var loadProxy = function (hash) {
nThen(function (waitFor) {
var wsUrl = NetConfig.getWebsocketURL();
var w = waitFor();
Netflux.connect(wsUrl).then(function (_network) {
network = _network;
w();
}, function (err) {
rpcError = err;
console.error(err);
});
}).nThen(function (waitFor) {
Crypt.get(hash, waitFor(function (err, val) {
if (err) {
waitFor.abort();
console.error(err);
return;
}
try {
var parsed = JSON.parse(val);
proxy = parsed;
} catch (e) {
console.log("Can't parse user drive", e);
}
}), {
network: network
});
}).nThen(function () {
var origin = ApiConfig.fileHost || window.location.origin;
// Get contacts and extract their avatar channel and key
var getData = function (obj, href) {
var parsed = Hash.parsePadUrl(href);
if (!parsed || parsed.type !== "file") { return; }
var secret = Hash.getSecrets('file', parsed.hash);
if (!secret.keys || !secret.channel) { return; }
obj.avatarKey = Hash.encodeBase64(secret.keys && secret.keys.cryptKey);
obj.avatarSrc = origin + Hash.getBlobPathFromHex(secret.channel);
};
contacts.teams = proxy.teams || {};
contacts.friends = proxy.friends || {};
Object.keys(contacts.friends).map(function (key) {
var friend = contacts.friends[key];
if (!friend) { return; }
var ret = {
edPublic: friend.edPublic,
name: friend.displayName,
};
getData(ret, friend.avatar);
contacts.friends[key] = ret;
});
Object.keys(contacts.teams).map(function (key) {
var team = contacts.teams[key];
if (!team) { return; }
var avatar = team.metadata && team.metadata.avatar;
var ret = {
edPublic: team.keys && team.keys.drive && team.keys.drive.edPublic,
name: team.metadata && team.metadata.name
};
getData(ret, avatar);
contacts.teams[key] = ret;
});
contacts.origin = window.location.origin;
}).nThen(function (waitFor) {
if (!network) { return void waitFor.abort(); }
Pinpad.create(network, proxy, waitFor(function (e, call) {
if (e) {
rpcError = e;
return void waitFor.abort();
}
rpc = call;
}));
}).nThen(function () {
Test(function () {
// This is only here to maybe trigger an error.
window.drive = proxy['drive'];
Test.passed();
});
});
};
var whenReady = function (cb) {
if (proxy && (rpc || rpcError)) { return void cb(); }
console.log('CryptPad not ready...');
setTimeout(function () {
whenReady(cb);
}, 100);
};
$(window).on("message", function (jqe) {
var evt = jqe.originalEvent;
var data = JSON.parse(evt.data);
var domain = evt.origin;
var srcWindow = evt.source;
var ret = { txid: data.txid };
console.log('CP receiving', data);
if (data.cmd === 'PING') {
ret.res = 'PONG';
} else if (data.cmd === 'LOGIN') {
Login.loginOrRegister(data.data.name, data.data.password, false, false, function (err) {
if (err) {
ret.error = 'LOGIN_ERROR';
srcWindow.postMessage(JSON.stringify(ret), domain);
return;
}
loadProxy(LocalStore.getUserHash());
srcWindow.postMessage(JSON.stringify(ret), domain);
});
return;
} else if (data.cmd === 'SIGN') {
if (!AUTHORIZED_DOMAINS.filter(function (x) { return x.test(domain); }).length) {
ret.error = "UNAUTH_DOMAIN";
} else if (!LocalStore.isLoggedIn()) {
ret.error = "NOT_LOGGED_IN";
} else {
return void whenReady(function () {
var sig = signMsg(data.data, proxy.edPrivate);
ret.res = {
uname: proxy.login_name,
edPublic: proxy.edPublic,
sig: sig
};
ret.contacts = contacts;
srcWindow.postMessage(JSON.stringify(ret), domain);
});
}
} else if (data.cmd === 'UPDATE_LIMIT') {
return void whenReady(function () {
if (rpcError) {
// Tell the user on accounts that there was an issue and they need to wait maximum 24h or contact an admin
ret.warning = true;
srcWindow.postMessage(JSON.stringify(ret), domain);
return;
}
rpc.updatePinLimits(function (e, limit, plan, note) {
if (e) {
ret.warning = true;
}
ret.res = [limit, plan, note];
srcWindow.postMessage(JSON.stringify(ret), domain);
});
});
} else {
ret.error = "UNKNOWN_CMD";
}
srcWindow.postMessage(JSON.stringify(ret), domain);
});
var userHash = LocalStore.getUserHash();
if (userHash) {
loadProxy(userHash);
}
});