Merge pull request #7 from Mega-Mewthree/e2ee-dev

E2ee dev
This commit is contained in:
Mega-Mewthree 2018-08-13 13:19:27 -07:00 committed by GitHub
commit 0ea5bc2dcc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 96 additions and 9 deletions

View File

@ -90,6 +90,32 @@ export default new class E2EE extends BuiltinModule {
Settings.getSetting('security', 'e2eedb', 'e2ekvps').addItem({ value: { key: channelId, value: key } }); Settings.getSetting('security', 'e2eedb', 'e2ekvps').addItem({ value: { key: channelId, value: key } });
} }
<<<<<<< Updated upstream
=======
get ecdhStorage() {
return this._ecdhStorage || (this._ecdhStorage = {});
}
createKeyExchange(dmChannelID) {
this.ecdhStorage[dmChannelID] = Security.createECDH();
return Security.generateECDHKeys(this.ecdhStorage[dmChannelID]);
}
publicKeyFor(dmChannelID) {
return Security.getECDHPublicKey(this.ecdhStorage[dmChannelID]);
}
computeSecret(dmChannelID, otherKey) {
try {
const secret = Security.computeECDHSecret(this.ecdhStorage[dmChannelID], otherKey);
delete this.ecdhStorage[dmChannelID];
return Security.sha256(secret);
} catch (e) {
throw e;
}
}
>>>>>>> Stashed changes
async enabled(e) { async enabled(e) {
seed = Security.randomBytes(); seed = Security.randomBytes();
// TODO Input modal for key // TODO Input modal for key

View File

@ -9,7 +9,11 @@
*/ */
<template> <template>
<<<<<<< Updated upstream
<div class="bd-e2eeTaContainer" @contextmenu.prevent="channelType === 'DM' && $refs.ee2eLockContextMenu.open()"> <div class="bd-e2eeTaContainer" @contextmenu.prevent="channelType === 'DM' && $refs.ee2eLockContextMenu.open()">
=======
<div class="bd-e2eeTaContainer" @contextmenu.prevent="currentChannel.type === 'DM' && $refs.ee2eLockContextMenu.open()">
>>>>>>> Stashed changes
<v-popover popoverClass="bd-popover bd-e2eePopover" placement="top"> <v-popover popoverClass="bd-popover bd-e2eePopover" placement="top">
<div v-if="error" class="bd-e2eeTaBtn bd-e2eeLock bd-error"> <div v-if="error" class="bd-e2eeTaBtn bd-e2eeLock bd-error">
<MiLock v-tooltip="error" /> <MiLock v-tooltip="error" />
@ -28,6 +32,9 @@
<template slot="popover"> <template slot="popover">
<div @click="toggleEncrypt" :class="{'bd-warn': !E2EE.encryptNewMessages, 'bd-ok': E2EE.encryptNewMessages}"><MiLock size="16" v-tooltip="'Toggle Encryption'" /></div> <div @click="toggleEncrypt" :class="{'bd-warn': !E2EE.encryptNewMessages, 'bd-ok': E2EE.encryptNewMessages}"><MiLock size="16" v-tooltip="'Toggle Encryption'" /></div>
<div v-close-popover @click="showUploadDialog" v-if="!error"><MiImagePlus size="16" v-tooltip="'Upload Encrypted Image'" /></div> <div v-close-popover @click="showUploadDialog" v-if="!error"><MiImagePlus size="16" v-tooltip="'Upload Encrypted Image'" /></div>
<!-- Using these icons for now -->
<div v-close-popover @click="generatePublicKey" v-if="currentChannel.type === 'DM'"><MiPencil size="16" v-tooltip="'Generate Public Key'" /></div>
<div v-close-popover @click="receivePublicKey" v-if="currentChannel.type === 'DM' && E2EE.ecdhStorage[currentChannel.id]"><MiRefresh size="16" v-tooltip="'Receive Public Key'" /></div>
</template> </template>
</v-popover> </v-popover>
<div class="bd-taDivider"></div> <div class="bd-taDivider"></div>
@ -46,18 +53,26 @@
import { remote } from 'electron'; import { remote } from 'electron';
import { E2EE } from 'builtin'; import { E2EE } from 'builtin';
import { DiscordApi, Security } from 'modules'; import { DiscordApi, Security } from 'modules';
<<<<<<< Updated upstream
import { MiLock, MiPlus, MiImagePlus } from '../ui/components/common/MaterialIcon'; import { MiLock, MiPlus, MiImagePlus } from '../ui/components/common/MaterialIcon';
import contextMenu from 'vue-context-menu'; import contextMenu from 'vue-context-menu';
=======
import { MiLock, MiPlus, MiImagePlus, MiPencil, MiRefresh } from '../ui/components/common/MaterialIcon';
>>>>>>> Stashed changes
import { Toasts } from 'ui'; import { Toasts } from 'ui';
export default { export default {
components: { MiLock, MiPlus, MiImagePlus }, components: { MiLock, MiPlus, MiImagePlus, MiPencil, MiRefresh },
data() { data() {
return { return {
E2EE, E2EE,
state: 'loading', state: 'loading',
error: null, error: null,
<<<<<<< Updated upstream
channelType: DiscordApi.currentChannel.type channelType: DiscordApi.currentChannel.type
=======
currentChannel: DiscordApi.currentChannel
>>>>>>> Stashed changes
}; };
}, },
methods: { methods: {
@ -90,12 +105,17 @@
Toasts.success('New messages will be encrypted'); Toasts.success('New messages will be encrypted');
}, },
generatePublicKey() { generatePublicKey() {
<<<<<<< Updated upstream
const dmChannelID = location.pathname.split("/")[3]; const dmChannelID = location.pathname.split("/")[3];
=======
const dmChannelID = DiscordApi.currentChannel.id;
>>>>>>> Stashed changes
const publicKeyMessage = `My public key is: \`${E2EE.createKeyExchange(dmChannelID)}\`. Please give me your public key if you haven't done so and add my public key by pasting it in the chat textbox, right clicking the lock icon, and selecting \`Receive Public Key\`.`; const publicKeyMessage = `My public key is: \`${E2EE.createKeyExchange(dmChannelID)}\`. Please give me your public key if you haven't done so and add my public key by pasting it in the chat textbox, right clicking the lock icon, and selecting \`Receive Public Key\`.`;
const chatInput = document.getElementsByClassName('da-textArea')[0]; const chatInput = document.getElementsByClassName('da-textArea')[0];
chatInput.value = publicKeyMessage; chatInput.value = publicKeyMessage;
const evt = { currentTarget: chatInput }; const evt = { currentTarget: chatInput };
chatInput[Object.keys(chatInput).find(k => k.startsWith('__reactEventHandlers'))].onChange.call(chatInput, evt); chatInput[Object.keys(chatInput).find(k => k.startsWith('__reactEventHandlers'))].onChange.call(chatInput, evt);
<<<<<<< Updated upstream
}, },
computeSharedSecret() { computeSharedSecret() {
try { try {
@ -111,6 +131,25 @@
} catch (e) { } catch (e) {
Toasts.error("Invalid public key. Please set up a new key exchange."); Toasts.error("Invalid public key. Please set up a new key exchange.");
console.error(e); console.error(e);
=======
this.$forceUpdate();
},
receivePublicKey() {
try {
const dmChannelID = DiscordApi.currentChannel.id;
const chatInput = document.getElementsByClassName('da-textArea')[0];
const otherPublicKey = chatInput.value;
const secret = E2EE.computeSecret(dmChannelID, otherPublicKey);
E2EE.setKey(dmChannelID, secret);
chatInput.value = "";
const evt = { currentTarget: chatInput };
chatInput[Object.keys(chatInput).find(k => k.startsWith('__reactEventHandlers'))].onChange.call(chatInput, evt);
Toasts.success("Encryption key has been set for this DM channel.");
this.$forceUpdate();
} catch (e) {
Toasts.error("Invalid public key. Please set up a new key exchange.");
console.error(e);
>>>>>>> Stashed changes
} }
} }
}, },

View File

@ -80,4 +80,26 @@ export default class Security {
}); });
} }
static createECDH() {
return nodecrypto.createECDH('secp521r1');
}
static sha256(text) {
const hash = nodecrypto.createHash('sha256');
hash.update(text);
return hash.digest('base64');
}
static generateECDHKeys(ecdh) {
return ecdh.generateKeys('base64');
}
static getECDHPublicKey(ecdh) {
return ecdh.getPublicKey('base64');
}
static computeECDHSecret(ecdh, otherPublicKey) {
return ecdh.computeSecret(otherPublicKey, 'base64', 'base64');
}
} }

16
package-lock.json generated
View File

@ -4797,9 +4797,9 @@
"dev": true, "dev": true,
"optional": true, "optional": true,
"requires": { "requires": {
"asynckit": "0.4.0", "asynckit": "^0.4.0",
"combined-stream": "1.0.5", "combined-stream": "^1.0.5",
"mime-types": "2.1.15" "mime-types": "^2.1.12"
} }
}, },
"fs.realpath": { "fs.realpath": {
@ -4902,8 +4902,8 @@
"dev": true, "dev": true,
"optional": true, "optional": true,
"requires": { "requires": {
"ajv": "4.11.8", "ajv": "^4.9.1",
"har-schema": "1.0.5" "har-schema": "^1.0.5"
} }
}, },
"has-unicode": { "has-unicode": {
@ -4972,7 +4972,7 @@
"integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=",
"dev": true, "dev": true,
"requires": { "requires": {
"number-is-nan": "1.0.1" "number-is-nan": "^1.0.0"
} }
}, },
"is-typedarray": { "is-typedarray": {
@ -5077,7 +5077,7 @@
"integrity": "sha1-pOv1BkCUVpI3uM9wBGd20J/JKu0=", "integrity": "sha1-pOv1BkCUVpI3uM9wBGd20J/JKu0=",
"dev": true, "dev": true,
"requires": { "requires": {
"mime-db": "1.27.0" "mime-db": "~1.27.0"
} }
}, },
"minimatch": { "minimatch": {
@ -5086,7 +5086,7 @@
"integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
"dev": true, "dev": true,
"requires": { "requires": {
"brace-expansion": "1.1.7" "brace-expansion": "^1.1.7"
} }
}, },
"minimist": { "minimist": {