diff --git a/packages/api/src/controllers/config.js b/packages/api/src/controllers/config.js index d67046b48..e430b0278 100644 --- a/packages/api/src/controllers/config.js +++ b/packages/api/src/controllers/config.js @@ -33,6 +33,7 @@ module.exports = { runAsPortal: !!connections.portalConnections, singleDatabase: connections.singleDatabase, hideAppEditor: !!process.env.HIDE_APP_EDITOR, + allowShellConnection: platformInfo.allowShellConnection, permissions, ...currentVersion, }; diff --git a/packages/api/src/proc/connectProcess.js b/packages/api/src/proc/connectProcess.js index be08ab51a..91b42a421 100644 --- a/packages/api/src/proc/connectProcess.js +++ b/packages/api/src/proc/connectProcess.js @@ -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) { diff --git a/packages/api/src/proc/databaseConnectionProcess.js b/packages/api/src/proc/databaseConnectionProcess.js index f10ac1874..9f036ded3 100644 --- a/packages/api/src/proc/databaseConnectionProcess.js +++ b/packages/api/src/proc/databaseConnectionProcess.js @@ -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; diff --git a/packages/api/src/proc/serverConnectionProcess.js b/packages/api/src/proc/serverConnectionProcess.js index 08ec935bb..42e5cb8d9 100644 --- a/packages/api/src/proc/serverConnectionProcess.js +++ b/packages/api/src/proc/serverConnectionProcess.js @@ -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); diff --git a/packages/api/src/proc/sessionProcess.js b/packages/api/src/proc/sessionProcess.js index c63b8cdb4..2c179c413 100644 --- a/packages/api/src/proc/sessionProcess.js +++ b/packages/api/src/proc/sessionProcess.js @@ -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(); } diff --git a/packages/api/src/shell/executeQuery.js b/packages/api/src/shell/executeQuery.js index 14d39238a..70398c9c1 100644 --- a/packages/api/src/shell/executeQuery.js +++ b/packages/api/src/shell/executeQuery.js @@ -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); diff --git a/packages/api/src/shell/generateDeploySql.js b/packages/api/src/shell/generateDeploySql.js index 4056428fa..7cdd1b5ad 100644 --- a/packages/api/src/shell/generateDeploySql.js +++ b/packages/api/src/shell/generateDeploySql.js @@ -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); } diff --git a/packages/api/src/shell/queryReader.js b/packages/api/src/shell/queryReader.js index aee708cf4..a92092eb6 100644 --- a/packages/api/src/shell/queryReader.js +++ b/packages/api/src/shell/queryReader.js @@ -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); } diff --git a/packages/api/src/shell/tableReader.js b/packages/api/src/shell/tableReader.js index c0824ee62..954f82055 100644 --- a/packages/api/src/shell/tableReader.js +++ b/packages/api/src/shell/tableReader.js @@ -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 }; diff --git a/packages/api/src/shell/tableWriter.js b/packages/api/src/shell/tableWriter.js index aa9639da2..e38fb9624 100644 --- a/packages/api/src/shell/tableWriter.js +++ b/packages/api/src/shell/tableWriter.js @@ -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); diff --git a/packages/api/src/utility/connectUtility.js b/packages/api/src/utility/connectUtility.js index b0b42c25a..f42889226 100644 --- a/packages/api/src/utility/connectUtility.js +++ b/packages/api/src/utility/connectUtility.js @@ -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(); diff --git a/packages/api/src/utility/platformInfo.js b/packages/api/src/utility/platformInfo.js index 237584f28..ce29d3028 100644 --- a/packages/api/src/utility/platformInfo.js +++ b/packages/api/src/utility/platformInfo.js @@ -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'), }; diff --git a/packages/web/src/appobj/DatabaseObjectAppObject.svelte b/packages/web/src/appobj/DatabaseObjectAppObject.svelte index 3237c18c0..0668a3289 100644 --- a/packages/web/src/appobj/DatabaseObjectAppObject.svelte +++ b/packages/web/src/appobj/DatabaseObjectAppObject.svelte @@ -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; diff --git a/packages/web/src/datagrid/CollectionDataGridCore.svelte b/packages/web/src/datagrid/CollectionDataGridCore.svelte index 9872660c9..8709bc5d5 100644 --- a/packages/web/src/datagrid/CollectionDataGridCore.svelte +++ b/packages/web/src/datagrid/CollectionDataGridCore.svelte @@ -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(), }, }, diff --git a/packages/web/src/datagrid/SqlDataGridCore.svelte b/packages/web/src/datagrid/SqlDataGridCore.svelte index 8f157debb..b7ec864b3 100644 --- a/packages/web/src/datagrid/SqlDataGridCore.svelte +++ b/packages/web/src/datagrid/SqlDataGridCore.svelte @@ -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(), }, }, diff --git a/packages/web/src/impexp/createImpExpScript.ts b/packages/web/src/impexp/createImpExpScript.ts index 197caa9d0..51fd04f4f 100644 --- a/packages/web/src/impexp/createImpExpScript.ts +++ b/packages/web/src/impexp/createImpExpScript.ts @@ -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) {