feat: better security connections credentials storage

This commit is contained in:
Fabio Di Stasio 2020-12-18 18:44:32 +01:00
parent 65ad0e954d
commit fc35f271d7
8 changed files with 56 additions and 7 deletions

7
.gitattributes vendored
View File

@ -1 +1,6 @@
* text eol=lf * text eol=lf
*.jpg binary
*.png binary
*.gif binary
*.ico binary
*.icns binary

View File

@ -36,6 +36,7 @@ An application created with minimalism and semplicity in mind, with features in
- Query suggestions. - Query suggestions.
- Native dark theme. - Native dark theme.
- Multi language. - Multi language.
- Secure password storage.
- Auto updates. - Auto updates.
## Coming soon ## Coming soon
@ -44,7 +45,6 @@ This is a roadmap with major features will come in near future.
- Stored procedures, views, schedulers and triggers support. - Stored procedures, views, schedulers and triggers support.
- Users management (add/edit/delete). - Users management (add/edit/delete).
- More secure password storage.
- Database tools (variables, process list...). - Database tools (variables, process list...).
- SSL and SSH tunnel support. - SSL and SSH tunnel support.
- Support for other databases. - Support for other databases.

View File

@ -49,7 +49,9 @@
"dependencies": { "dependencies": {
"@mdi/font": "^5.8.55", "@mdi/font": "^5.8.55",
"electron-log": "^4.3.0", "electron-log": "^4.3.0",
"electron-store": "^6.0.1",
"electron-updater": "^4.3.5", "electron-updater": "^4.3.5",
"keytar": "^7.3.0",
"lodash": "^4.17.20", "lodash": "^4.17.20",
"moment": "^2.29.1", "moment": "^2.29.1",
"monaco-editor": "^0.20.0", "monaco-editor": "^0.20.0",

View File

@ -2,7 +2,9 @@
import { app, BrowserWindow, nativeImage } from 'electron'; import { app, BrowserWindow, nativeImage } from 'electron';
import * as path from 'path'; import * as path from 'path';
import crypto from 'crypto';
import { format as formatUrl } from 'url'; import { format as formatUrl } from 'url';
import keytar from 'keytar';
import ipcHandlers from './ipc-handlers'; import ipcHandlers from './ipc-handlers';
const isDevelopment = process.env.NODE_ENV !== 'production'; const isDevelopment = process.env.NODE_ENV !== 'production';
@ -89,7 +91,14 @@ else {
}); });
// create main BrowserWindow when electron is ready // create main BrowserWindow when electron is ready
app.on('ready', () => { app.on('ready', async () => {
let key = await keytar.getPassword('antares', 'user');
if (!key) {
key = crypto.randomBytes(16).toString('hex');
keytar.setPassword('antares', 'user', key);
}
mainWindow = createMainWindow(); mainWindow = createMainWindow();
}); });
} }

View File

@ -1,7 +1,13 @@
import keytar from 'keytar';
import { app, ipcMain } from 'electron'; import { app, ipcMain } from 'electron';
export default () => { export default () => {
ipcMain.on('close-app', () => { ipcMain.on('close-app', () => {
app.exit(); app.exit();
}); });
ipcMain.on('get-key', async event => {
const key = await keytar.getPassword('antares', 'user');
event.returnValue = key;
});
}; };

View File

@ -0,0 +1,8 @@
'use strict';
import { ipcRenderer } from 'electron';
export default class {
static getKey (params) {
return ipcRenderer.sendSync('get-key', params);
}
}

View File

@ -1,10 +1,20 @@
'use strict'; 'use strict';
import Store from 'electron-store';
import Application from '../../ipc-api/Application';
const key = Application.getKey();
console.log(key);
const persistentStore = new Store({
name: 'connections',
encryptionKey: key
});
export default { export default {
namespaced: true, namespaced: true,
strict: true, strict: true,
state: { state: {
connections: [] connections: persistentStore.get('connections') || []
}, },
getters: { getters: {
getConnections: state => state.connections, getConnections: state => state.connections,
@ -20,9 +30,11 @@ export default {
mutations: { mutations: {
ADD_CONNECTION (state, connection) { ADD_CONNECTION (state, connection) {
state.connections.push(connection); state.connections.push(connection);
persistentStore.set('connections', state.connections);
}, },
DELETE_CONNECTION (state, connection) { DELETE_CONNECTION (state, connection) {
state.connections = state.connections.filter(el => el.uid !== connection.uid); state.connections = state.connections.filter(el => el.uid !== connection.uid);
persistentStore.set('connections', state.connections);
}, },
EDIT_CONNECTION (state, connection) { EDIT_CONNECTION (state, connection) {
const editedConnections = state.connections.map(conn => { const editedConnections = state.connections.map(conn => {
@ -31,9 +43,11 @@ export default {
}); });
state.connections = editedConnections; state.connections = editedConnections;
state.selected_conection = {}; state.selected_conection = {};
persistentStore.set('connections', state.connections);
}, },
UPDATE_CONNECTIONS (state, connections) { UPDATE_CONNECTIONS (state, connections) {
state.connections = connections; state.connections = connections;
persistentStore.set('connections', state.connections);
} }
}, },
actions: { actions: {

View File

@ -1,13 +1,15 @@
'use strict'; 'use strict';
import i18n from '@/i18n'; import i18n from '@/i18n';
import Store from 'electron-store';
const persistentStore = new Store({ name: 'settings' });
export default { export default {
namespaced: true, namespaced: true,
strict: true, strict: true,
state: { state: {
locale: 'en-US', locale: persistentStore.get('locale') || 'en-US',
explorebar_size: null, explorebar_size: persistentStore.get('explorebar_size') || null,
notifications_timeout: 5 notifications_timeout: persistentStore.get('notifications_timeout') || 5
}, },
getters: { getters: {
getLocale: state => state.locale, getLocale: state => state.locale,
@ -18,12 +20,15 @@ export default {
SET_LOCALE (state, locale) { SET_LOCALE (state, locale) {
state.locale = locale; state.locale = locale;
i18n.locale = locale; i18n.locale = locale;
persistentStore.set('locale', state.locale);
}, },
SET_NOTIFICATIONS_TIMEOUT (state, timeout) { SET_NOTIFICATIONS_TIMEOUT (state, timeout) {
state.notifications_timeout = timeout; state.notifications_timeout = timeout;
persistentStore.set('notifications_timeout', state.notifications_timeout);
}, },
SET_EXPLOREBAR_SIZE (state, size) { SET_EXPLOREBAR_SIZE (state, size) {
state.explorebar_size = size; state.explorebar_size = size;
persistentStore.set('explorebar_size', state.explorebar_size);
} }
}, },
actions: { actions: {