safe read-only when using shell scripts

This commit is contained in:
Jan Prochazka 2022-03-19 10:09:27 +01:00
parent ff661ec89b
commit 8824262395
16 changed files with 80 additions and 34 deletions

View File

@ -33,6 +33,7 @@ module.exports = {
runAsPortal: !!connections.portalConnections,
singleDatabase: connections.singleDatabase,
hideAppEditor: !!process.env.HIDE_APP_EDITOR,
allowShellConnection: platformInfo.allowShellConnection,
permissions,
...currentVersion,
};

View File

@ -20,7 +20,7 @@ function start() {
if (handleProcessCommunication(connection)) return;
try {
const driver = requireEngineDriver(connection);
const conn = await connectUtility(driver, connection);
const conn = await connectUtility(driver, connection, 'app');
const res = await driver.getVersion(conn);
process.send({ msgtype: 'connected', ...res });
} catch (e) {

View File

@ -108,7 +108,7 @@ async function handleConnect({ connection, structure, globalSettings }) {
if (!structure) setStatusName('pending');
const driver = requireEngineDriver(storedConnection);
systemConnection = await checkedAsyncCall(connectUtility(driver, storedConnection));
systemConnection = await checkedAsyncCall(connectUtility(driver, storedConnection, 'app'));
await checkedAsyncCall(readVersion());
if (structure) {
analysedStructure = structure;

View File

@ -58,11 +58,14 @@ async function handleConnect(connection) {
const driver = requireEngineDriver(storedConnection);
try {
systemConnection = await connectUtility(driver, storedConnection);
systemConnection = await connectUtility(driver, storedConnection, 'app');
readVersion();
handleRefresh();
if (extractBoolSettingsValue(globalSettings, 'connection.autoRefresh', false)) {
setInterval(handleRefresh, extractIntSettingsValue(globalSettings, 'connection.autoRefreshInterval', 30, 5, 3600) * 1000);
setInterval(
handleRefresh,
extractIntSettingsValue(globalSettings, 'connection.autoRefreshInterval', 30, 5, 3600) * 1000
);
}
} catch (err) {
setStatus({
@ -80,7 +83,7 @@ function handlePing() {
async function handleCreateDatabase({ name }) {
const driver = requireEngineDriver(storedConnection);
systemConnection = await connectUtility(driver, storedConnection);
systemConnection = await connectUtility(driver, storedConnection, 'app');
console.log(`RUNNING SCRIPT: CREATE DATABASE ${driver.dialect.quoteIdentifier(name)}`);
if (driver.createDatabase) {
await driver.createDatabase(systemConnection, name);

View File

@ -181,7 +181,7 @@ async function handleConnect(connection) {
storedConnection = connection;
const driver = requireEngineDriver(storedConnection);
systemConnection = await connectUtility(driver, storedConnection);
systemConnection = await connectUtility(driver, storedConnection, 'app');
for (const [resolve] of afterConnectCallbacks) {
resolve();
}

View File

@ -5,7 +5,7 @@ async function executeQuery({ connection = undefined, systemConnection = undefin
console.log(`Execute query ${sql}`);
if (!driver) driver = requireEngineDriver(connection);
const pool = systemConnection || (await connectUtility(driver, connection));
const pool = systemConnection || (await connectUtility(driver, connection, 'write'));
console.log(`Connected.`);
await driver.script(pool, sql);

View File

@ -21,7 +21,7 @@ async function generateDeploySql({
}) {
if (!driver) driver = requireEngineDriver(connection);
const pool = systemConnection || (await connectUtility(driver, connection));
const pool = systemConnection || (await connectUtility(driver, connection, 'read'));
if (!analysedStructure) {
analysedStructure = await driver.analyseFull(pool);
}

View File

@ -6,7 +6,7 @@ async function queryReader({ connection, sql }) {
console.log(`Reading query ${sql}`);
const driver = requireEngineDriver(connection);
const pool = await connectUtility(driver, connection);
const pool = await connectUtility(driver, connection, 'script');
console.log(`Connected.`);
return await driver.readQuery(pool, sql);
}

View File

@ -4,7 +4,7 @@ const connectUtility = require('../utility/connectUtility');
async function tableReader({ connection, pureName, schemaName }) {
const driver = requireEngineDriver(connection);
const pool = await connectUtility(driver, connection);
const pool = await connectUtility(driver, connection, 'read');
console.log(`Connected.`);
const fullName = { pureName, schemaName };

View File

@ -8,7 +8,7 @@ async function tableWriter({ connection, schemaName, pureName, driver, systemCon
if (!driver) {
driver = requireEngineDriver(connection);
}
const pool = systemConnection || (await connectUtility(driver, connection));
const pool = systemConnection || (await connectUtility(driver, connection, 'write'));
console.log(`Connected.`);
return await driver.writeTable(pool, { schemaName, pureName }, options);

View File

@ -4,11 +4,47 @@ const fs = require('fs-extra');
const { decryptConnection } = require('./crypting');
const { getSshTunnel } = require('./sshTunnel');
const { getSshTunnelProxy } = require('./sshTunnelProxy');
const platformInfo = require('../utility/platformInfo');
const connections = require('../controllers/connections');
async function loadConnection(driver, storedConnection, connectionMode) {
const { allowShellConnection } = platformInfo;
if (connectionMode == 'app') {
return storedConnection;
}
if (storedConnection._id || !allowShellConnection) {
if (!storedConnection._id) {
throw new Error('Missing connection _id');
}
await connections._init();
const loaded = await connections.get({ conid: storedConnection._id });
const loadedWithDb = {
...loaded,
database: storedConnection.database,
};
if (loaded.isReadOnly) {
if (connectionMode == 'read') return loadedWithDb;
if (connectionMode == 'write') throw new Error('Cannot wwrite readonly connection');
if (connectionMode == 'script') {
if (driver.readOnlySessions) return loadedWithDb;
throw new Error('Cannot wwrite readonly connection');
}
}
return loadedWithDb;
}
return storedConnection;
}
async function connectUtility(driver, storedConnection, connectionMode) {
const connectionLoaded = await loadConnection(driver, storedConnection, connectionMode);
async function connectUtility(driver, storedConnection) {
const connection = {
database: storedConnection.defaultDatabase,
...decryptConnection(storedConnection),
database: connectionLoaded.defaultDatabase,
...decryptConnection(connectionLoaded),
};
if (!connection.port && driver.defaultPort) connection.port = driver.defaultPort.toString();

View File

@ -39,6 +39,7 @@ const platformInfo = {
environment: process.env.NODE_ENV,
platform,
runningInWebpack: !!process.env.WEBPACK_DEV_SERVER_URL,
allowShellConnection: !!process.env.SHELL_CONNECTION || !!isElectron(),
defaultKeyfile: path.join(os.homedir(), '.ssh/id_rsa'),
};

View File

@ -417,10 +417,7 @@
{
functionName: menu.functionName,
props: {
connection: {
..._.omit(coninfo, ['_id', 'displayName']),
..._.pick(data, ['database']),
},
connection: extractShellConnection(coninfo, data.database),
..._.pick(data, ['pureName', 'schemaName']),
},
},
@ -629,6 +626,7 @@
import ConfirmModal from '../modals/ConfirmModal.svelte';
import { apiCall } from '../utility/api';
import InputTextModal from '../modals/InputTextModal.svelte';
import { extractShellConnection } from '../impexp/createImpExpScript';
export let data;
export let passProps;

View File

@ -112,6 +112,7 @@
import { registerQuickExportHandler } from '../buttons/ToolStripExportButton.svelte';
import registerCommand from '../commands/registerCommand';
import ErrorInfo from '../elements/ErrorInfo.svelte';
import { extractShellConnection } from '../impexp/createImpExpScript';
import ConfirmNoSqlModal from '../modals/ConfirmNoSqlModal.svelte';
import ErrorMessageModal from '../modals/ErrorMessageModal.svelte';
import ImportExportModal from '../modals/ImportExportModal.svelte';
@ -202,10 +203,7 @@
{
functionName: 'queryReader',
props: {
connection: {
..._.omit(coninfo, ['_id', 'displayName']),
database,
},
connection: extractShellConnection(coninfo, database),
sql: getExportQuery(),
},
},

View File

@ -69,6 +69,7 @@
import { registerQuickExportHandler } from '../buttons/ToolStripExportButton.svelte';
import registerCommand from '../commands/registerCommand';
import { extractShellConnection } from '../impexp/createImpExpScript';
import ImportExportModal from '../modals/ImportExportModal.svelte';
import { showModal } from '../modals/modalTools';
import { apiCall } from '../utility/api';
@ -187,10 +188,7 @@
{
functionName: 'queryReader',
props: {
connection: {
..._.omit(coninfo, ['_id', 'displayName']),
database,
},
connection: extractShellConnection(coninfo, database),
sql: display.getExportQuery(),
},
},

View File

@ -4,6 +4,7 @@ import getAsArray from '../utility/getAsArray';
import { getConnectionInfo } from '../utility/metadataLoaders';
import { findEngineDriver, findObjectLike } from 'dbgate-tools';
import { findFileFormat } from '../plugins/fileformats';
import { getCurrentConfig } from '../stores';
export function getTargetName(extensions, source, values) {
const key = `targetName_${source}`;
@ -33,17 +34,27 @@ function extractDriverApiParameters(values, direction, driver) {
return _.fromPairs(pairs);
}
export function extractShellConnection(connection, database) {
const config = getCurrentConfig();
return config.allowShellConnection
? {
..._.omit(connection, ['_id', 'displayName', 'databases', 'connectionColor']),
database,
}
: {
_id: connection._id,
engine: connection.engine,
database,
};
}
async function getConnection(extensions, storageType, conid, database) {
if (storageType == 'database' || storageType == 'query') {
const conn = await getConnectionInfo({ conid });
const driver = findEngineDriver(conn, extensions);
return [
{
..._.omit(conn, ['_id', 'displayName']),
database,
},
driver,
];
const connection = extractShellConnection(conn, database);
return [connection, driver];
}
return [null, null];
}
@ -201,7 +212,7 @@ export default async function createImpExpScript(extensions, values, addEditorIn
// @ts-ignore
script.assign(targetVar, ...getTargetExpr(extensions, sourceName, values, targetConnection, targetDriver));
const colmap = normalizeExportColumnMap(values[`columns_${sourceName}`] );
const colmap = normalizeExportColumnMap(values[`columns_${sourceName}`]);
let colmapVar = null;
if (colmap) {