UNPKG

dbgate-api

Version:

Allows run DbGate data-manipulation scripts.

143 lines (117 loc) 4.28 kB
const fs = require('fs-extra'); const { decryptConnection } = require('./crypting'); const { getSshTunnelProxy } = require('./sshTunnelProxy'); const platformInfo = require('../utility/platformInfo'); const connections = require('../controllers/connections'); const _ = require('lodash'); async function loadConnection(driver, storedConnection, connectionMode) { const { allowShellConnection, allowConnectionFromEnvVariables } = 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.getCore({ conid: storedConnection._id }); const loadedWithDb = { ...loaded, database: storedConnection.database, }; if (loaded.isReadOnly) { if (connectionMode == 'read') return loadedWithDb; if (connectionMode == 'write') throw new Error('Cannot write readonly connection'); if (connectionMode == 'script') { if (driver.readOnlySessions) return loadedWithDb; throw new Error('Cannot write readonly connection'); } } return loadedWithDb; } if (allowConnectionFromEnvVariables) { return _.mapValues(storedConnection, (value, key) => { if (_.isString(value) && value.startsWith('${') && value.endsWith('}')) { return process.env[value.slice(2, -1)]; } return value; }); } return storedConnection; } async function extractConnectionSslParams(connection) { /** @type {any} */ let ssl = undefined; if (connection.useSsl) { ssl = {}; if (connection.sslCaFile) { ssl.ca = await fs.readFile(connection.sslCaFile); ssl.sslCaFile = connection.sslCaFile; } if (connection.sslCertFile) { ssl.cert = await fs.readFile(connection.sslCertFile); ssl.sslCertFile = connection.sslCertFile; } if (connection.sslKeyFile) { ssl.key = await fs.readFile(connection.sslKeyFile); ssl.sslKeyFile = connection.sslKeyFile; } if (connection.sslCertFilePassword) { ssl.password = connection.sslCertFilePassword; } if (!ssl.key && !ssl.ca && !ssl.cert) { // TODO: provide this as an option in settings // or per-connection as 'reject self-signed certs' // How it works: // if false, cert can be self-signed // if true, has to be from a public CA // Heroku certs are self-signed. // if you provide ca/cert/key files, it overrides this ssl.rejectUnauthorized = false; } else { ssl.rejectUnauthorized = connection.sslRejectUnauthorized; } } return ssl; } async function decryptCloudConnection(connection) { const { getCloudFolderEncryptor } = require('./cloudIntf'); const m = connection?._id?.match(/^cloud\:\/\/(.+)\/(.+)$/); if (!m) { throw new Error('Invalid cloud connection ID format'); } const folid = m[1]; const cntid = m[2]; const folderEncryptor = await getCloudFolderEncryptor(folid); return decryptConnection(connection, folderEncryptor); } async function connectUtility(driver, storedConnection, connectionMode, additionalOptions = null) { const connectionLoaded = await loadConnection(driver, storedConnection, connectionMode); const connection = connectionLoaded?._id?.startsWith('cloud://') ? { database: connectionLoaded.defaultDatabase, ...(await decryptCloudConnection(connectionLoaded)), } : { database: connectionLoaded.defaultDatabase, ...decryptConnection(connectionLoaded), }; if (!connection.port && driver.defaultPort) { connection.port = driver.defaultPort.toString(); } if (connection.useSshTunnel) { const tunnel = await getSshTunnelProxy(connection); if (tunnel.state == 'error') { throw new Error(tunnel.message); } connection.server = tunnel.localHost; connection.port = tunnel.localPort; } connection.ssl = await extractConnectionSslParams(connection); const conn = await driver.connect({ conid: connectionLoaded?._id, ...connection, ...additionalOptions }); return conn; } module.exports = { extractConnectionSslParams, connectUtility, };