diff --git a/.gitattributes b/.gitattributes index 07764a78..f7ba7b2b 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1 +1,6 @@ -* text eol=lf \ No newline at end of file +* text eol=lf +*.jpg binary +*.png binary +*.gif binary +*.ico binary +*.icns binary \ No newline at end of file diff --git a/README.md b/README.md index 5c60ebda..a3e30ee9 100644 --- a/README.md +++ b/README.md @@ -36,6 +36,7 @@ An application created with minimalism and semplicity in mind, with features in - Query suggestions. - Native dark theme. - Multi language. +- Secure password storage. - Auto updates. ## 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. - Users management (add/edit/delete). -- More secure password storage. - Database tools (variables, process list...). - SSL and SSH tunnel support. - Support for other databases. diff --git a/package.json b/package.json index 87b7e302..e9ac0096 100644 --- a/package.json +++ b/package.json @@ -49,7 +49,9 @@ "dependencies": { "@mdi/font": "^5.8.55", "electron-log": "^4.3.0", + "electron-store": "^6.0.1", "electron-updater": "^4.3.5", + "keytar": "^7.3.0", "lodash": "^4.17.20", "moment": "^2.29.1", "monaco-editor": "^0.20.0", diff --git a/src/main/index.js b/src/main/index.js index 9ccfd463..56c081dd 100644 --- a/src/main/index.js +++ b/src/main/index.js @@ -2,7 +2,9 @@ import { app, BrowserWindow, nativeImage } from 'electron'; import * as path from 'path'; +import crypto from 'crypto'; import { format as formatUrl } from 'url'; +import keytar from 'keytar'; import ipcHandlers from './ipc-handlers'; const isDevelopment = process.env.NODE_ENV !== 'production'; @@ -89,7 +91,14 @@ else { }); // 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(); }); } diff --git a/src/main/ipc-handlers/application.js b/src/main/ipc-handlers/application.js index a7e39183..efc36e9b 100644 --- a/src/main/ipc-handlers/application.js +++ b/src/main/ipc-handlers/application.js @@ -1,7 +1,13 @@ +import keytar from 'keytar'; import { app, ipcMain } from 'electron'; export default () => { ipcMain.on('close-app', () => { app.exit(); }); + + ipcMain.on('get-key', async event => { + const key = await keytar.getPassword('antares', 'user'); + event.returnValue = key; + }); }; diff --git a/src/renderer/ipc-api/Application.js b/src/renderer/ipc-api/Application.js new file mode 100644 index 00000000..e221e0cc --- /dev/null +++ b/src/renderer/ipc-api/Application.js @@ -0,0 +1,8 @@ +'use strict'; +import { ipcRenderer } from 'electron'; + +export default class { + static getKey (params) { + return ipcRenderer.sendSync('get-key', params); + } +} diff --git a/src/renderer/store/modules/connections.store.js b/src/renderer/store/modules/connections.store.js index 2c0b8145..4769a9e5 100644 --- a/src/renderer/store/modules/connections.store.js +++ b/src/renderer/store/modules/connections.store.js @@ -1,10 +1,20 @@ '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 { namespaced: true, strict: true, state: { - connections: [] + connections: persistentStore.get('connections') || [] }, getters: { getConnections: state => state.connections, @@ -20,9 +30,11 @@ export default { mutations: { ADD_CONNECTION (state, connection) { state.connections.push(connection); + persistentStore.set('connections', state.connections); }, DELETE_CONNECTION (state, connection) { state.connections = state.connections.filter(el => el.uid !== connection.uid); + persistentStore.set('connections', state.connections); }, EDIT_CONNECTION (state, connection) { const editedConnections = state.connections.map(conn => { @@ -31,9 +43,11 @@ export default { }); state.connections = editedConnections; state.selected_conection = {}; + persistentStore.set('connections', state.connections); }, UPDATE_CONNECTIONS (state, connections) { state.connections = connections; + persistentStore.set('connections', state.connections); } }, actions: { diff --git a/src/renderer/store/modules/settings.store.js b/src/renderer/store/modules/settings.store.js index 1751f8c1..1b5cb6a5 100644 --- a/src/renderer/store/modules/settings.store.js +++ b/src/renderer/store/modules/settings.store.js @@ -1,13 +1,15 @@ 'use strict'; import i18n from '@/i18n'; +import Store from 'electron-store'; +const persistentStore = new Store({ name: 'settings' }); export default { namespaced: true, strict: true, state: { - locale: 'en-US', - explorebar_size: null, - notifications_timeout: 5 + locale: persistentStore.get('locale') || 'en-US', + explorebar_size: persistentStore.get('explorebar_size') || null, + notifications_timeout: persistentStore.get('notifications_timeout') || 5 }, getters: { getLocale: state => state.locale, @@ -18,12 +20,15 @@ export default { SET_LOCALE (state, locale) { state.locale = locale; i18n.locale = locale; + persistentStore.set('locale', state.locale); }, SET_NOTIFICATIONS_TIMEOUT (state, timeout) { state.notifications_timeout = timeout; + persistentStore.set('notifications_timeout', state.notifications_timeout); }, SET_EXPLOREBAR_SIZE (state, size) { state.explorebar_size = size; + persistentStore.set('explorebar_size', state.explorebar_size); } }, actions: {