1
1
mirror of https://github.com/Fabio286/antares.git synced 2025-02-17 04:00:48 +01:00

feat: support to ssl connections

This commit is contained in:
Fabio Di Stasio 2021-02-03 21:53:24 +01:00
parent 15417e8a77
commit 4e72bb1587
6 changed files with 512 additions and 248 deletions

View File

@ -1,17 +1,28 @@
import fs from 'fs';
import { ipcMain } from 'electron'; import { ipcMain } from 'electron';
import { ClientsFactory } from '../libs/ClientsFactory'; import { ClientsFactory } from '../libs/ClientsFactory';
export default connections => { export default connections => {
ipcMain.handle('test-connection', async (event, conn) => { ipcMain.handle('test-connection', async (event, conn) => {
const params = {
host: conn.host,
port: +conn.port,
user: conn.user,
password: conn.password
};
if (conn.ssl) {
params.ssl = {
key: conn.key ? fs.readFileSync(conn.key) : null,
cert: conn.cert ? fs.readFileSync(conn.cert) : null,
ca: conn.ca ? fs.readFileSync(conn.ca) : null,
ciphers: conn.ciphers
};
}
const connection = ClientsFactory.getConnection({ const connection = ClientsFactory.getConnection({
client: conn.client, client: conn.client,
params: { params
host: conn.host,
port: +conn.port,
user: conn.user,
password: conn.password
}
}); });
await connection.connect(); await connection.connect();
@ -32,14 +43,25 @@ export default connections => {
}); });
ipcMain.handle('connect', async (event, conn) => { ipcMain.handle('connect', async (event, conn) => {
const params = {
host: conn.host,
port: +conn.port,
user: conn.user,
password: conn.password
};
if (conn.ssl) {
params.ssl = {
key: conn.key ? fs.readFileSync(conn.key) : null,
cert: conn.cert ? fs.readFileSync(conn.cert) : null,
ca: conn.ca ? fs.readFileSync(conn.ca) : null,
ciphers: conn.ciphers
};
}
const connection = ClientsFactory.getConnection({ const connection = ClientsFactory.getConnection({
client: conn.client, client: conn.client,
params: { params,
host: conn.host,
port: +conn.port,
user: conn.user,
password: conn.password
},
poolSize: 1 poolSize: 1
}); });

View File

@ -10,36 +10,56 @@
</div> </div>
<a class="btn btn-clear c-hand" @click="closeModal" /> <a class="btn btn-clear c-hand" @click="closeModal" />
</div> </div>
<div class="modal-body pb-0"> <div class="modal-body p-0">
<div class="content"> <div class="panel">
<form class="form-horizontal"> <div class="panel-nav">
<fieldset class="m-0" :disabled="isTesting"> <ul class="tab tab-block">
<div class="form-group"> <li
<div class="col-4 col-sm-12"> class="tab-item"
<label class="form-label">{{ $t('word.connectionName') }}</label> :class="{'active': selectedTab === 'general'}"
</div> @click="selectTab('general')"
<div class="col-8 col-sm-12"> >
<input <a class="c-hand">{{ $t('word.general') }}</a>
ref="firstInput" </li>
v-model="localConnection.name" <li
class="form-input" class="tab-item"
type="text" :class="{'active': selectedTab === 'ssl'}"
> @click="selectTab('ssl')"
</div> >
</div> <a class="c-hand">{{ $t('word.ssl') }}</a>
<div class="form-group"> </li>
<div class="col-4 col-sm-12"> </ul>
<label class="form-label">{{ $t('word.client') }}</label> </div>
</div> <div v-if="selectedTab === 'general'" class="panel-body py-0">
<div class="col-8 col-sm-12"> <div class="container">
<select v-model="localConnection.client" class="form-select"> <form class="form-horizontal">
<option value="mysql"> <fieldset class="m-0" :disabled="isTesting">
MySQL <div class="form-group">
</option> <div class="col-4 col-sm-12">
<option value="maria"> <label class="form-label">{{ $t('word.connectionName') }}</label>
MariaDB </div>
</option> <div class="col-8 col-sm-12">
<!-- <option value="mssql"> <input
ref="firstInput"
v-model="localConnection.name"
class="form-input"
type="text"
>
</div>
</div>
<div class="form-group">
<div class="col-4 col-sm-12">
<label class="form-label">{{ $t('word.client') }}</label>
</div>
<div class="col-8 col-sm-12">
<select v-model="localConnection.client" class="form-select">
<option value="mysql">
MySQL
</option>
<option value="maria">
MariaDB
</option>
<!-- <option value="mssql">
Microsoft SQL Microsoft SQL
</option> </option>
<option value="pg"> <option value="pg">
@ -48,99 +68,177 @@
<option value="oracledb"> <option value="oracledb">
Oracle DB Oracle DB
</option> --> </option> -->
</select> </select>
</div>
</div>
<div class="form-group">
<div class="col-4 col-sm-12">
<label class="form-label">{{ $t('word.hostName') }}/IP</label>
</div>
<div class="col-8 col-sm-12">
<input
v-model="localConnection.host"
class="form-input"
type="text"
>
</div>
</div>
<div class="form-group">
<div class="col-4 col-sm-12">
<label class="form-label">{{ $t('word.port') }}</label>
</div>
<div class="col-8 col-sm-12">
<input
v-model="localConnection.port"
class="form-input"
type="number"
min="1"
max="65535"
>
</div>
</div>
<div class="form-group">
<div class="col-4 col-sm-12">
<label class="form-label">{{ $t('word.user') }}</label>
</div>
<div class="col-8 col-sm-12">
<input
v-model="localConnection.user"
class="form-input"
type="text"
:disabled="localConnection.ask"
>
</div>
</div>
<div class="form-group">
<div class="col-4 col-sm-12">
<label class="form-label">{{ $t('word.password') }}</label>
</div>
<div class="col-8 col-sm-12">
<input
v-model="localConnection.password"
class="form-input"
type="password"
:disabled="localConnection.ask"
>
</div>
</div>
<div class="form-group">
<div class="col-4 col-sm-12" />
<div class="col-8 col-sm-12">
<label class="form-checkbox form-inline">
<input v-model="localConnection.ask" type="checkbox"><i class="form-icon" /> {{ $t('message.askCredentials') }}
</label>
</div>
</div>
</fieldset>
</form>
</div>
<BaseToast
class="mb-2"
:message="toast.message"
:status="toast.status"
/>
</div>
<div v-if="selectedTab === 'ssl'" class="panel-body py-0">
<div class="container">
<form class="form-horizontal">
<div class="form-group">
<div class="col-4 col-sm-12">
<label class="form-label">
{{ $t('message.enableSsl') }}
</label>
</div>
<div class="col-8 col-sm-12">
<label class="form-switch d-inline-block" @click.prevent="toggleSsl">
<input type="checkbox" :checked="localConnection.ssl">
<i class="form-icon" />
</label>
</div>
</div> </div>
</div> <fieldset class="m-0" :disabled="isTesting || !localConnection.ssl">
<div class="form-group"> <div class="form-group">
<div class="col-4 col-sm-12"> <div class="col-4 col-sm-12">
<label class="form-label">{{ $t('word.hostName') }}/IP</label> <label class="form-label">{{ $t('word.privateKey') }}</label>
</div> </div>
<div class="col-8 col-sm-12"> <div class="col-8 col-sm-12">
<input <input
v-model="localConnection.host" class="form-input"
class="form-input" type="file"
type="text" @change="pathSelection($event, 'key')"
> >
</div> </div>
</div> </div>
<div class="form-group"> <div class="form-group">
<div class="col-4 col-sm-12"> <div class="col-4 col-sm-12">
<label class="form-label">{{ $t('word.port') }}</label> <label class="form-label">{{ $t('word.certificate') }}</label>
</div> </div>
<div class="col-8 col-sm-12"> <div class="col-8 col-sm-12">
<input <input
v-model="localConnection.port" class="form-input"
class="form-input" type="file"
type="number" @change="pathSelection($event, 'cert')"
min="1" >
max="65535" </div>
> </div>
</div> <div class="form-group">
</div> <div class="col-4 col-sm-12">
<div class="form-group"> <label class="form-label">{{ $t('word.caCertificate') }}</label>
<div class="col-4 col-sm-12"> </div>
<label class="form-label">{{ $t('word.user') }}</label> <div class="col-8 col-sm-12">
</div> <input
<div class="col-8 col-sm-12"> class="form-input"
<input type="file"
v-model="localConnection.user" @change="pathSelection($event, 'ca')"
class="form-input" >
type="text" </div>
:disabled="localConnection.ask" </div>
>
</div> <div class="form-group">
</div> <div class="col-4 col-sm-12">
<div class="form-group"> <label class="form-label">{{ $t('word.ciphers') }}</label>
<div class="col-4 col-sm-12"> </div>
<label class="form-label">{{ $t('word.password') }}</label> <div class="col-8 col-sm-12">
</div> <input
<div class="col-8 col-sm-12"> ref="firstInput"
<input v-model="localConnection.ciphers"
v-model="localConnection.password" class="form-input"
class="form-input" type="text"
type="password" >
:disabled="localConnection.ask" </div>
> </div>
</div> </fieldset>
</div> </form>
<div class="form-group"> </div>
<div class="col-4 col-sm-12" /> <BaseToast
<div class="col-8 col-sm-12"> class="mb-2"
<label class="form-checkbox form-inline"> :message="toast.message"
<input v-model="localConnection.ask" type="checkbox"><i class="form-icon" /> {{ $t('message.askCredentials') }} :status="toast.status"
</label> />
</div> </div>
</div> <div class="modal-footer text-light">
</fieldset> <button
</form> class="btn btn-gray mr-2"
:class="{'loading': isTesting}"
@click="startTest"
>
{{ $t('message.testConnection') }}
</button>
<button class="btn btn-primary mr-2" @click="saveEditConnection">
{{ $t('word.save') }}
</button>
<button class="btn btn-link" @click="closeModal">
{{ $t('word.close') }}
</button>
</div>
</div> </div>
<BaseToast <ModalAskCredentials
class="mb-2" v-if="isAsking"
:message="toast.message" @close-asking="closeAsking"
:status="toast.status" @credentials="continueTest"
/> />
</div> </div>
<div class="modal-footer text-light">
<button
class="btn btn-gray mr-2"
:class="{'loading': isTesting}"
@click="startTest"
>
{{ $t('message.testConnection') }}
</button>
<button class="btn btn-primary mr-2" @click="saveEditConnection">
{{ $t('word.save') }}
</button>
<button class="btn btn-link" @click="closeModal">
{{ $t('word.close') }}
</button>
</div>
</div> </div>
<ModalAskCredentials
v-if="isAsking"
@close-asking="closeAsking"
@credentials="continueTest"
/>
</div> </div>
</template> </template>
@ -167,7 +265,8 @@ export default {
}, },
isTesting: false, isTesting: false,
isAsking: false, isAsking: false,
localConnection: null localConnection: null,
selectedTab: 'general'
}; };
}, },
created () { created () {
@ -240,6 +339,18 @@ export default {
e.stopPropagation(); e.stopPropagation();
if (e.key === 'Escape') if (e.key === 'Escape')
this.closeModal(); this.closeModal();
},
selectTab (tab) {
this.selectedTab = tab;
},
toggleSsl () {
this.localConnection.ssl = !this.localConnection.ssl;
},
pathSelection (event, name) {
const { files } = event.target;
if (!files.length) return;
this.localConnection[name] = files[0].path;
} }
} }
}; };
@ -247,6 +358,8 @@ export default {
<style scoped> <style scoped>
.modal-container { .modal-container {
position: absolute;
max-width: 450px; max-width: 450px;
top: 17.5vh;
} }
</style> </style>

View File

@ -10,119 +10,217 @@
</div> </div>
<a class="btn btn-clear c-hand" @click="closeModal" /> <a class="btn btn-clear c-hand" @click="closeModal" />
</div> </div>
<div class="modal-body pb-0"> <div class="modal-body p-0">
<div class="content"> <div class="panel">
<form class="form-horizontal"> <div class="panel-nav">
<fieldset class="m-0" :disabled="isTesting"> <ul class="tab tab-block">
<div class="form-group"> <li
<div class="col-4 col-sm-12"> class="tab-item"
<label class="form-label">{{ $t('word.connectionName') }}</label> :class="{'active': selectedTab === 'general'}"
@click="selectTab('general')"
>
<a class="c-hand">{{ $t('word.general') }}</a>
</li>
<li
class="tab-item"
:class="{'active': selectedTab === 'ssl'}"
@click="selectTab('ssl')"
>
<a class="c-hand">{{ $t('word.ssl') }}</a>
</li>
</ul>
</div>
<div v-if="selectedTab === 'general'" class="panel-body py-0">
<div class="container">
<form class="form-horizontal">
<fieldset class="m-0" :disabled="isTesting">
<div class="form-group">
<div class="col-4 col-sm-12">
<label class="form-label">{{ $t('word.connectionName') }}</label>
</div>
<div class="col-8 col-sm-12">
<input
ref="firstInput"
v-model="connection.name"
class="form-input"
type="text"
>
</div>
</div>
<div class="form-group">
<div class="col-4 col-sm-12">
<label class="form-label">{{ $t('word.client') }}</label>
</div>
<div class="col-8 col-sm-12">
<select
v-model="connection.client"
class="form-select"
@change="setDefaults"
>
<option value="mysql">
MySQL
</option>
<option value="maria">
MariaDB
</option>
<!-- <option value="mssql">
Microsoft SQL
</option>
<option value="pg">
PostgreSQL
</option>
<option value="oracledb">
Oracle DB
</option> -->
</select>
</div>
</div>
<div class="form-group">
<div class="col-4 col-sm-12">
<label class="form-label">{{ $t('word.hostName') }}/IP</label>
</div>
<div class="col-8 col-sm-12">
<input
v-model="connection.host"
class="form-input"
type="text"
>
</div>
</div>
<div class="form-group">
<div class="col-4 col-sm-12">
<label class="form-label">{{ $t('word.port') }}</label>
</div>
<div class="col-8 col-sm-12">
<input
v-model="connection.port"
class="form-input"
type="number"
min="1"
max="65535"
>
</div>
</div>
<div class="form-group">
<div class="col-4 col-sm-12">
<label class="form-label">{{ $t('word.user') }}</label>
</div>
<div class="col-8 col-sm-12">
<input
v-model="connection.user"
class="form-input"
type="text"
:disabled="connection.ask"
>
</div>
</div>
<div class="form-group">
<div class="col-4 col-sm-12">
<label class="form-label">{{ $t('word.password') }}</label>
</div>
<div class="col-8 col-sm-12">
<input
v-model="connection.password"
class="form-input"
type="password"
:disabled="connection.ask"
>
</div>
</div>
<div class="form-group">
<div class="col-4 col-sm-12" />
<div class="col-8 col-sm-12">
<label class="form-checkbox form-inline">
<input v-model="connection.ask" type="checkbox"><i class="form-icon" /> {{ $t('message.askCredentials') }}
</label>
</div>
</div>
</fieldset>
</form>
</div>
<BaseToast
class="mb-2"
:message="toast.message"
:status="toast.status"
/>
</div>
<div v-if="selectedTab === 'ssl'" class="panel-body py-0">
<div class="container">
<form class="form-horizontal">
<div class="form-group">
<div class="col-4 col-sm-12">
<label class="form-label">
{{ $t('message.enableSsl') }}
</label>
</div>
<div class="col-8 col-sm-12">
<label class="form-switch d-inline-block" @click.prevent="toggleSsl">
<input type="checkbox" :checked="connection.ssl">
<i class="form-icon" />
</label>
</div>
</div> </div>
<div class="col-8 col-sm-12"> <fieldset class="m-0" :disabled="isTesting || !connection.ssl">
<input <div class="form-group">
ref="firstInput" <div class="col-4 col-sm-12">
v-model="connection.name" <label class="form-label">{{ $t('word.privateKey') }}</label>
class="form-input" </div>
type="text" <div class="col-8 col-sm-12">
> <input
</div> class="form-input"
</div> type="file"
<div class="form-group"> @change="pathSelection($event, 'key')"
<div class="col-4 col-sm-12"> >
<label class="form-label">{{ $t('word.client') }}</label> </div>
</div> </div>
<div class="col-8 col-sm-12"> <div class="form-group">
<select <div class="col-4 col-sm-12">
v-model="connection.client" <label class="form-label">{{ $t('word.certificate') }}</label>
class="form-select" </div>
@change="setDefaults" <div class="col-8 col-sm-12">
> <input
<option value="mysql"> class="form-input"
MySQL type="file"
</option> @change="pathSelection($event, 'cert')"
<option value="maria"> >
MariaDB </div>
</option> </div>
<!-- <option value="mssql"> <div class="form-group">
Microsoft SQL <div class="col-4 col-sm-12">
</option> <label class="form-label">{{ $t('word.caCertificate') }}</label>
<option value="pg"> </div>
PostgreSQL <div class="col-8 col-sm-12">
</option> <input
<option value="oracledb"> class="form-input"
Oracle DB type="file"
</option> --> @change="pathSelection($event, 'ca')"
</select> >
</div> </div>
</div> </div>
<div class="form-group">
<div class="col-4 col-sm-12"> <div class="form-group">
<label class="form-label">{{ $t('word.hostName') }}/IP</label> <div class="col-4 col-sm-12">
</div> <label class="form-label">{{ $t('word.ciphers') }}</label>
<div class="col-8 col-sm-12"> </div>
<input <div class="col-8 col-sm-12">
v-model="connection.host" <input
class="form-input" ref="firstInput"
type="text" v-model="connection.ciphers"
> class="form-input"
</div> type="text"
</div> >
<div class="form-group"> </div>
<div class="col-4 col-sm-12"> </div>
<label class="form-label">{{ $t('word.port') }}</label> </fieldset>
</div> </form>
<div class="col-8 col-sm-12"> </div>
<input <BaseToast
v-model="connection.port" class="mb-2"
class="form-input" :message="toast.message"
type="number" :status="toast.status"
min="1" />
max="65535" </div>
>
</div>
</div>
<div class="form-group">
<div class="col-4 col-sm-12">
<label class="form-label">{{ $t('word.user') }}</label>
</div>
<div class="col-8 col-sm-12">
<input
v-model="connection.user"
class="form-input"
type="text"
:disabled="connection.ask"
>
</div>
</div>
<div class="form-group">
<div class="col-4 col-sm-12">
<label class="form-label">{{ $t('word.password') }}</label>
</div>
<div class="col-8 col-sm-12">
<input
v-model="connection.password"
class="form-input"
type="password"
:disabled="connection.ask"
>
</div>
</div>
<div class="form-group">
<div class="col-4 col-sm-12" />
<div class="col-8 col-sm-12">
<label class="form-checkbox form-inline">
<input v-model="connection.ask" type="checkbox"><i class="form-icon" /> {{ $t('message.askCredentials') }}
</label>
</div>
</div>
</fieldset>
</form>
</div> </div>
<BaseToast
class="mb-2"
:message="toast.message"
:status="toast.status"
/>
</div> </div>
<div class="modal-footer text-light"> <div class="modal-footer text-light">
<button <button
@ -171,14 +269,21 @@ export default {
user: 'root', user: 'root',
password: '', password: '',
ask: false, ask: false,
uid: uidGen('C') uid: uidGen('C'),
ssl: false,
cert: '',
key: '',
ca: '',
ciphers: ''
}, },
toast: { toast: {
status: '', status: '',
message: '' message: ''
}, },
isTesting: false, isTesting: false,
isAsking: false isAsking: false,
selectedTab: 'general'
}; };
}, },
created () { created () {
@ -265,6 +370,18 @@ export default {
e.stopPropagation(); e.stopPropagation();
if (e.key === 'Escape') if (e.key === 'Escape')
this.closeModal(); this.closeModal();
},
selectTab (tab) {
this.selectedTab = tab;
},
toggleSsl () {
this.connection.ssl = !this.connection.ssl;
},
pathSelection (event, name) {
const { files } = event.target;
if (!files.length) return;
this.connection[name] = files[0].path;
} }
} }
}; };
@ -272,6 +389,8 @@ export default {
<style scoped> <style scoped>
.modal-container { .modal-container {
position: absolute;
max-width: 450px; max-width: 450px;
top: 17.5vh;
} }
</style> </style>

View File

@ -20,7 +20,7 @@
> >
<a class="tab-link"> <a class="tab-link">
<i class="mdi mdi-18px mdi-tune mr-1" /> <i class="mdi mdi-18px mdi-tune mr-1" />
<span :title="schemaChild">{{ $t('word.properties').toUpperCase() }}: {{ schemaChild }}</span> <span :title="schemaChild">{{ $t('word.settings').toUpperCase() }}: {{ schemaChild }}</span>
</a> </a>
</li> </li>
<li <li

View File

@ -85,7 +85,12 @@ module.exports = {
state: 'State', state: 'State',
execution: 'Execution', execution: 'Execution',
starts: 'Starts', starts: 'Starts',
ends: 'Ends' ends: 'Ends',
ssl: 'SSL',
privateKey: 'Private key',
certificate: 'Certificate',
caCertificate: 'CA certificate',
ciphers: 'Ciphers'
}, },
message: { message: {
appWelcome: 'Welcome to Antares SQL Client!', appWelcome: 'Welcome to Antares SQL Client!',
@ -172,7 +177,8 @@ module.exports = {
schedulerBody: 'Scheduler body', schedulerBody: 'Scheduler body',
createNewScheduler: 'Create new scheduler', createNewScheduler: 'Create new scheduler',
deleteScheduler: 'Delete scheduler', deleteScheduler: 'Delete scheduler',
preserveOnCompletion: 'Preserve on completion' preserveOnCompletion: 'Preserve on completion',
enableSsl: 'Enable SSL'
}, },
// Date and Time // Date and Time
short: { short: {

View File

@ -210,6 +210,10 @@ body {
border-color: $primary-color; border-color: $primary-color;
} }
.form-input[type="file"] {
overflow: hidden;
}
.input-group .input-group-addon { .input-group .input-group-addon {
border-color: #3f3f3f; border-color: #3f3f3f;
z-index: 1; z-index: 1;