Add an option to store the master password in the system keychain
This commit is contained in:
parent
96b7e8d859
commit
d53afe2538
|
@ -12,7 +12,7 @@ import { Settings, Cache, Events } from 'modules';
|
||||||
import BuiltinModule from './BuiltinModule';
|
import BuiltinModule from './BuiltinModule';
|
||||||
import { WebpackModules, ReactComponents, MonkeyPatch, Patcher, DiscordApi, Security } from 'modules';
|
import { WebpackModules, ReactComponents, MonkeyPatch, Patcher, DiscordApi, Security } from 'modules';
|
||||||
import { VueInjector, Reflection, Modals, Toasts } from 'ui';
|
import { VueInjector, Reflection, Modals, Toasts } from 'ui';
|
||||||
import { ClientLogger as Logger } from 'common';
|
import { ClientLogger as Logger, ClientIPC } from 'common';
|
||||||
import { request } from 'vendor';
|
import { request } from 'vendor';
|
||||||
import { Utils } from 'common';
|
import { Utils } from 'common';
|
||||||
import E2EEComponent from './E2EEComponent.vue';
|
import E2EEComponent from './E2EEComponent.vue';
|
||||||
|
@ -35,33 +35,59 @@ export default new class E2EE extends BuiltinModule {
|
||||||
this.encryptNewMessages = true;
|
this.encryptNewMessages = true;
|
||||||
this.ecdhDate = START_DATE;
|
this.ecdhDate = START_DATE;
|
||||||
this.handlePublicKey = this.handlePublicKey.bind(this);
|
this.handlePublicKey = this.handlePublicKey.bind(this);
|
||||||
|
this.fetchMasterKey = this.fetchMasterKey.bind(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
async enabled(e) {
|
async enabled(e) {
|
||||||
try {
|
await this.fetchMasterKey();
|
||||||
const newMaster = await Modals.input('Open Database', 'Master Password', true).promise;
|
Settings.getSetting('security', 'default', 'use-keytar').on('setting-updated', this.fetchMasterKey);
|
||||||
this.setMaster(newMaster);
|
|
||||||
Events.on('discord:MESSAGE_CREATE', this.handlePublicKey);
|
Events.on('discord:MESSAGE_CREATE', this.handlePublicKey);
|
||||||
this.patchDispatcher();
|
this.patchDispatcher();
|
||||||
this.patchMessageContent();
|
this.patchMessageContent();
|
||||||
const selector = `.${WebpackModules.getClassName('channelTextArea', 'emojiButton')}`;
|
const selector = `.${WebpackModules.getClassName('channelTextArea', 'emojiButton')}`;
|
||||||
const cta = await ReactComponents.getComponent('ChannelTextArea', { selector });
|
const cta = await ReactComponents.getComponent('ChannelTextArea', { selector });
|
||||||
this.patchChannelTextArea(cta);
|
this.patchChannelTextArea(cta);
|
||||||
this.patchChannelTextAreaSubmit(cta);
|
this.patchChannelTextAreaSubmit(cta);
|
||||||
cta.forceUpdateAll();
|
cta.forceUpdateAll();
|
||||||
} catch (err) {
|
|
||||||
Settings.getSetting(...this.settingPath).value = false;
|
|
||||||
Toasts.error('Invalid master password! E2EE Disabled');
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async disabled(e) {
|
async disabled(e) {
|
||||||
|
Settings.getSetting('security', 'default', 'use-keytar').off('setting-updated', this.fetchMasterKey);
|
||||||
Events.off('discord:MESSAGE_CREATE', this.handlePublicKey);
|
Events.off('discord:MESSAGE_CREATE', this.handlePublicKey);
|
||||||
for (const patch of Patcher.getPatchesByCaller('BD:E2EE')) patch.unpatch();
|
for (const patch of Patcher.getPatchesByCaller('BD:E2EE')) patch.unpatch();
|
||||||
const ctaComponent = await ReactComponents.getComponent('ChannelTextArea');
|
const ctaComponent = await ReactComponents.getComponent('ChannelTextArea');
|
||||||
ctaComponent.forceUpdateAll();
|
ctaComponent.forceUpdateAll();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fetchMasterKey() {
|
||||||
|
try {
|
||||||
|
if (Settings.get('security', 'default', 'use-keytar')) {
|
||||||
|
const master = await ClientIPC.getPassword('betterdiscord', 'master');
|
||||||
|
if (master) return this.setMaster(master);
|
||||||
|
|
||||||
|
if (Settings.getSetting('security', 'e2eedb', 'e2ekvps').items.length) {
|
||||||
|
// Ask the user for their current password to save to the system keychain
|
||||||
|
const currentMaster = await Modals.input('Save to System Keychain', 'Master Password', true).promise;
|
||||||
|
await ClientIPC.setPassword('betterdiscord', 'master', currentMaster);
|
||||||
|
return this.setMaster(currentMaster);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generate a new master password and save it to the system keychain
|
||||||
|
const newMaster = Security.randomBytes();
|
||||||
|
await ClientIPC.setPassword('betterdiscord', 'master', newMaster);
|
||||||
|
return this.setMaster(newMaster);
|
||||||
|
} else {
|
||||||
|
const newMaster = await Modals.input('Open Database', 'Master Password', true).promise;
|
||||||
|
return this.setMaster(newMaster);
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
Settings.getSetting(...this.settingPath).value = false;
|
||||||
|
Toasts.error('Invalid master password! E2EE Disabled');
|
||||||
|
Logger.err('E2EE', ['Error fetching master password', err]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
setMaster(key) {
|
setMaster(key) {
|
||||||
seed = Security.randomBytes();
|
seed = Security.randomBytes();
|
||||||
const newMaster = Security.encrypt(seed, key);
|
const newMaster = Security.encrypt(seed, key);
|
||||||
|
@ -300,8 +326,11 @@ export default new class E2EE extends BuiltinModule {
|
||||||
|
|
||||||
component.props.readyState = 'LOADING';
|
component.props.readyState = 'LOADING';
|
||||||
Logger.info('E2EE', `Decrypting image: ${src}`);
|
Logger.info('E2EE', `Decrypting image: ${src}`);
|
||||||
request.get(src, { encoding: 'binary' }).then(res => {
|
|
||||||
(async () => {
|
(async () => {
|
||||||
|
try {
|
||||||
|
const res = await request.get(src, { encoding: 'binary' });
|
||||||
|
|
||||||
const arr = new Uint8Array(new ArrayBuffer(res.length));
|
const arr = new Uint8Array(new ArrayBuffer(res.length));
|
||||||
for (let i = 0; i < res.length; i++) arr[i] = res.charCodeAt(i);
|
for (let i = 0; i < res.length; i++) arr[i] = res.charCodeAt(i);
|
||||||
|
|
||||||
|
@ -330,10 +359,10 @@ export default new class E2EE extends BuiltinModule {
|
||||||
|
|
||||||
component.props.decrypting = false;
|
component.props.decrypting = false;
|
||||||
component.forceUpdate();
|
component.forceUpdate();
|
||||||
})();
|
} catch (err) {
|
||||||
}).catch(err => {
|
console.log('request error', err);
|
||||||
console.log('request error', err);
|
}
|
||||||
});
|
})();
|
||||||
}
|
}
|
||||||
|
|
||||||
patchChannelTextArea(cta) {
|
patchChannelTextArea(cta) {
|
||||||
|
@ -355,4 +384,5 @@ export default new class E2EE extends BuiltinModule {
|
||||||
if (!this.encryptNewMessages || !key) return;
|
if (!this.encryptNewMessages || !key) return;
|
||||||
component.props.value = Security.encrypt(Security.decrypt(seed, [this.master, key]), component.props.value, '$:');
|
component.props.value = Security.encrypt(Security.decrypt(seed, [this.master, key]), component.props.value, '$:');
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -235,6 +235,13 @@
|
||||||
"text": "E2EE",
|
"text": "E2EE",
|
||||||
"hint": "End-to-end encryption",
|
"hint": "End-to-end encryption",
|
||||||
"value": false
|
"value": false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "use-keytar",
|
||||||
|
"type": "bool",
|
||||||
|
"text": "Use system keychain",
|
||||||
|
"hint": "Store the master password in the system keychain",
|
||||||
|
"value": true
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
|
Loading…
Reference in New Issue