SYNC: private cloud UX + fixes

This commit is contained in:
SPRINX0\prochazka
2025-06-20 13:45:32 +02:00
committed by Diflow
parent f2af38da4c
commit d668128a34
4 changed files with 59 additions and 12 deletions

View File

@@ -4,6 +4,7 @@ const { getSshTunnelProxy } = require('./sshTunnelProxy');
const platformInfo = require('../utility/platformInfo'); const platformInfo = require('../utility/platformInfo');
const connections = require('../controllers/connections'); const connections = require('../controllers/connections');
const _ = require('lodash'); const _ = require('lodash');
const { getCloudFolderEncryptor } = require('./cloudIntf');
async function loadConnection(driver, storedConnection, connectionMode) { async function loadConnection(driver, storedConnection, connectionMode) {
const { allowShellConnection, allowConnectionFromEnvVariables } = platformInfo; const { allowShellConnection, allowConnectionFromEnvVariables } = platformInfo;
@@ -88,10 +89,28 @@ async function extractConnectionSslParams(connection) {
return ssl; return ssl;
} }
async function decryptCloudConnection(connection) {
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) { async function connectUtility(driver, storedConnection, connectionMode, additionalOptions = null) {
const connectionLoaded = await loadConnection(driver, storedConnection, connectionMode); const connectionLoaded = await loadConnection(driver, storedConnection, connectionMode);
const connection = { const connection = connectionLoaded?._id?.startsWith('cloud://')
? {
database: connectionLoaded.defaultDatabase,
...(await decryptCloudConnection(connectionLoaded)),
}
: {
database: connectionLoaded.defaultDatabase, database: connectionLoaded.defaultDatabase,
...decryptConnection(connectionLoaded), ...decryptConnection(connectionLoaded),
}; };

View File

@@ -91,11 +91,11 @@ function encryptObjectPasswordField(obj, field, encryptor = null) {
return obj; return obj;
} }
function decryptObjectPasswordField(obj, field) { function decryptObjectPasswordField(obj, field, encryptor = null) {
if (obj && obj[field] && obj[field].startsWith('crypt:')) { if (obj && obj[field] && obj[field].startsWith('crypt:')) {
return { return {
...obj, ...obj,
[field]: getInternalEncryptor().decrypt(obj[field].substring('crypt:'.length)), [field]: (encryptor || getInternalEncryptor()).decrypt(obj[field].substring('crypt:'.length)),
}; };
} }
return obj; return obj;
@@ -115,10 +115,10 @@ function maskConnection(connection) {
return _.omit(connection, ['password', 'sshPassword', 'sshKeyfilePassword']); return _.omit(connection, ['password', 'sshPassword', 'sshKeyfilePassword']);
} }
function decryptConnection(connection) { function decryptConnection(connection, encryptor = null) {
connection = decryptObjectPasswordField(connection, 'password'); connection = decryptObjectPasswordField(connection, 'password', encryptor);
connection = decryptObjectPasswordField(connection, 'sshPassword'); connection = decryptObjectPasswordField(connection, 'sshPassword', encryptor);
connection = decryptObjectPasswordField(connection, 'sshKeyfilePassword'); connection = decryptObjectPasswordField(connection, 'sshKeyfilePassword', encryptor);
return connection; return connection;
} }

View File

@@ -14,7 +14,7 @@ import { batchDispatchCacheTriggers, dispatchCacheChange } from './cache';
import { isAdminPage, isOneOfPage } from './pageDefs'; import { isAdminPage, isOneOfPage } from './pageDefs';
import { openWebLink } from './simpleTools'; import { openWebLink } from './simpleTools';
import { serializeJsTypesReplacer } from 'dbgate-tools'; import { serializeJsTypesReplacer } from 'dbgate-tools';
import { cloudSigninTokenHolder } from '../stores'; import { cloudSigninTokenHolder, selectedWidget } from '../stores';
import LicenseLimitMessageModal from '../modals/LicenseLimitMessageModal.svelte'; import LicenseLimitMessageModal from '../modals/LicenseLimitMessageModal.svelte';
export const strmid = uuidv1(); export const strmid = uuidv1();
@@ -290,8 +290,9 @@ export function installNewVolatileConnectionListener() {
export function installNewCloudTokenListener() { export function installNewCloudTokenListener() {
apiOn('got-cloud-token', async tokenHolder => { apiOn('got-cloud-token', async tokenHolder => {
console.log('HOLDER', tokenHolder); // console.log('HOLDER', tokenHolder);
cloudSigninTokenHolder.set(tokenHolder); cloudSigninTokenHolder.set(tokenHolder);
selectedWidget.set('cloud-private');
}); });
} }

View File

@@ -35,6 +35,9 @@
import { showSnackbarInfo } from '../utility/snackbar'; import { showSnackbarInfo } from '../utility/snackbar';
import { isProApp } from '../utility/proTools'; import { isProApp } from '../utility/proTools';
import { useCloudContentColorFactory, useConnectionColorFactory } from '../utility/useConnectionColor'; import { useCloudContentColorFactory, useConnectionColorFactory } from '../utility/useConnectionColor';
import ErrorInfo from '../elements/ErrorInfo.svelte';
import FormStyledButton from '../buttons/FormStyledButton.svelte';
import runCommand from '../commands/runCommand';
let filter = ''; let filter = '';
let domSqlObjectList = null; let domSqlObjectList = null;
@@ -250,8 +253,32 @@
}} }}
groupContextMenu={createGroupContextMenu} groupContextMenu={createGroupContextMenu}
/> />
{#if !cloudContentFlat?.length}
<ErrorInfo message="You have no content on DbGate cloud" icon="img info" />
<div class="error-info">
<div class="m-1"></div>
<FormStyledButton
value="Create connection on DbGate Cloud"
skipWidth
on:click={() => {
runCommand('new.connectionOnCloud');
}}
/>
</div>
{/if}
</WidgetsInnerContainer> </WidgetsInnerContainer>
</WidgetColumnBarItem> </WidgetColumnBarItem>
<DatabaseWidgetDetailContent bind:domSqlObjectList showCloudConnection={true} /> <DatabaseWidgetDetailContent bind:domSqlObjectList showCloudConnection={true} />
</WidgetColumnBar> </WidgetColumnBar>
<style>
.error-info {
flex: 1;
display: flex;
flex-direction: column;
align-items: stretch;
margin-top: 10px;
}
</style>