Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

End-to-end Encrypted Chat #5

Open
wants to merge 2 commits into
base: master
from
Open
Changes from all commits
Commits
File filter...
Filter file types
Jump to…
Jump to file or symbol
Failed to load files and symbols.

Always

Just for now

@@ -3,7 +3,7 @@
"Kestrel": {
"EndPoints": {
"Http": {
"Url": "http://*:5000"
"Url": "http://*:5001"
}
}
}
@@ -1,38 +1,38 @@
#!/bin/bash
ssh root@app.gaevoy.com 'bash -s' <<'ENDSSH'
printf "Stopping service...\n"
systemctl stop GaevChat
systemctl stop GaevCryptoChat
printf "Service is "
systemctl is-active GaevChat
mkdir -p /apps/GaevChat
systemctl is-active GaevCryptoChat
mkdir -p /apps/GaevCryptoChat
ENDSSH

printf "Uploading new version of service...\n"
rsync -v -a ./bin/Release/netcoreapp2.2/ubuntu.16.04-x64/publish/ root@app.gaevoy.com:/apps/GaevChat/
rsync -v -a ./bin/Release/netcoreapp2.2/ubuntu.16.04-x64/publish/ root@app.gaevoy.com:/apps/GaevCryptoChat/

ssh root@app.gaevoy.com 'bash -s' <<'ENDSSH'
chmod 777 /apps/GaevChat/Gaev.Chat
if [[ ! -e /etc/systemd/system/GaevChat.service ]]; then
chmod 777 /apps/GaevCryptoChat/Gaev.Chat
if [[ ! -e /etc/systemd/system/GaevCryptoChat.service ]]; then
printf "Installing service...\n"
cat > /etc/systemd/system/GaevChat.service <<'EOF'
cat > /etc/systemd/system/GaevCryptoChat.service <<'EOF'
[Unit]
Description=GaevChat
Description=GaevCryptoChat
After=network.target
[Service]
WorkingDirectory=/apps/GaevChat
ExecStart=/apps/GaevChat/Gaev.Chat
WorkingDirectory=/apps/GaevCryptoChat
ExecStart=/apps/GaevCryptoChat/Gaev.Chat
Restart=always
KillSignal=SIGINT
[Install]
WantedBy=multi-user.target
EOF
systemctl daemon-reload
systemctl enable GaevChat
systemctl enable GaevCryptoChat
fi
printf "Starting service...\n"
systemctl start GaevChat
systemctl start GaevCryptoChat
printf "Service is "
systemctl is-active GaevChat
systemctl is-active GaevCryptoChat
ENDSSH
@@ -1,9 +1,9 @@
#!/bin/bash
ssh root@app.gaevoy.com 'bash -s' <<'ENDSSH'
systemctl stop GaevChat
systemctl disable GaevChat
rm /etc/systemd/system/GaevChat.service
systemctl stop GaevCryptoChat
systemctl disable GaevCryptoChat
rm /etc/systemd/system/GaevCryptoChat.service
systemctl daemon-reload
systemctl reset-failed
rm -rf /apps/GaevChat
rm -rf /apps/GaevCryptoChat
ENDSSH
@@ -3,8 +3,9 @@
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Chat</title>
<title>Crypto Chat</title>
<link rel="stylesheet" href="main.css">
<script src="kbpgp-2.1.0-min.js"></script>
<script src="main.js"></script>
</head>
<body>
@@ -14,7 +15,7 @@
enterChat(joinChat));
</script>
<section class="lobby">
<h1>Minimalist Chat</h1>
<h1>End-to-end Encrypted Chat</h1>
<p>Put room number you want to enter and nickname so the rest participant can understand who you are.</p>
<form class="join-form">
<label>Room number <input type="text" class="room" autofocus/></label>

Large diffs are not rendered by default.

Oops, something went wrong.
@@ -13,27 +13,47 @@ function enterChat(onDone) {
room = roomInput.value;
nickname = nicknameInput.value;
if (room.length && nickname.length) {
document.querySelector('.lobby').classList.add('hidden');
window.history.pushState(null, null, '#room/' + window.encodeURI(room));
onDone(room, nickname);
document.querySelector('.lobby .join-form').innerText = 'Generating cryptographic key...';
PgpKey.generate(nickname, myKey => {
document.querySelector('.lobby').classList.add('hidden');
window.history.pushState(null, null, '#room/' + window.encodeURI(room));
onDone(room, nickname, myKey);
});
}
});
}

function joinChat(room, nickname) {
function joinChat(room, nickname, myKey) {
let logs = document.querySelector(".chat .logs");
let newMessage = document.querySelector('.chat .new-message');
let chatApi = new ChatApi();
let keys = {};
document.querySelector('.chat .new-message-form').addEventListener('submit', evt => {
evt.preventDefault();
chatApi.sendMessage(room, {sender: nickname, text: newMessage.value});
Object.keys(keys).forEach(keyId =>
keys[keyId].encrypt(newMessage.value, cipher =>
chatApi.sendMessage(room, {sender: myKey.id(), recipient: keyId, text: cipher})));
newMessage.value = '';
});
chatApi.listenToMessages(room,
message => {
renderMessage(message.sender, message.text);
let sender = keys[message.sender];
let recipient = message.recipient && keys[message.recipient];
if (message.publicKey) {
if (sender) return;
PgpKey.load(message.publicKey, key => {
let isMyKey = myKey.id() === key.id();
keys[key.id()] = isMyKey ? myKey : key;
renderMessage(key.nickname() + ' joined', '');
if (!isMyKey)
chatApi.sendMessage(room, {sender: myKey.id(), publicKey: myKey.public()});
});
} else if (sender && recipient && recipient.canDecrypt()) {
recipient.decrypt(message.text, text =>
renderMessage(sender.nickname(), text));
}
},
() => chatApi.sendMessage(room, {sender: nickname + ' joined', text: '',}));
() => chatApi.sendMessage(room, {sender: myKey.id(), publicKey: myKey.public()}));
document.querySelector('.chat').classList.remove('hidden');
newMessage.select();

@@ -70,4 +90,53 @@ class ChatApi {
req.send(JSON.stringify(JSON.stringify(message)));
console.log('Message sent', message);
}
}

class PgpKey {
constructor(key) {
this._key = key;
if (this.canDecrypt()) {
this._ring = new kbpgp.keyring.KeyRing();
this._ring.add_key_manager(key);
}
}

public() {
return this._key.armored_pgp_public;
}

id() {
return this._key.get_pgp_short_key_id();
}

nickname() {
return this._key.userids[0].get_username();
}

encrypt(text, onDone) {
kbpgp.box({msg: text, encrypt_for: this._key}, (_, cipher) =>
onDone(cipher));
}

canDecrypt() {
return this._key.can_decrypt();
}

decrypt(cipher, onDone) {
kbpgp.unbox({keyfetch: this._ring, armored: cipher, progress_hook: null}, (_, literals) =>
onDone(literals[0].toString()));
}

static generate(nickname, onDone) {
let opt = {userid: nickname, primary: {nbits: 1024}, subkeys: []};
kbpgp.KeyManager.generate(opt, (_, key) =>
key.sign({}, () =>
key.export_pgp_public({}, () =>
onDone(new PgpKey(key)))));
}

static load(publicKey, onDone) {
kbpgp.KeyManager.import_from_armored_pgp({armored: publicKey}, (_, key) =>
onDone(new PgpKey(key)));
}
}
ProTip! Use n and p to navigate between commits in a pull request.
You can’t perform that action at this time.