encrypting cloud content

This commit is contained in:
SPRINX0\prochazka
2025-05-22 15:48:59 +02:00
parent 1b8bb0c1fd
commit f4a879a452
9 changed files with 89 additions and 34 deletions

View File

@@ -140,8 +140,8 @@ module.exports = {
createCloudLoginSession_meta: true,
async createCloudLoginSession({ client }) {
const res = await createDbGateIdentitySession(client);
startCloudTokenChecking(res.sid, token => {
socket.emit('got-cloud-token', { token });
startCloudTokenChecking(res.sid, tokenHolder => {
socket.emit('got-cloud-token', tokenHolder);
});
return res;
},

View File

@@ -6,6 +6,7 @@ const {
callCloudApiPost,
getCloudFolderEncryptor,
getCloudContent,
putCloudContent,
} = require('../utility/cloudIntf');
const connections = require('./connections');
const socket = require('../utility/socket');
@@ -55,7 +56,7 @@ module.exports = {
putContent_meta: true,
async putContent({ folid, cntid, content, name, type }) {
await callCloudApiPost(`put-content`, { folid, cntid, content, name, type });
putCloudContent(folid, cntid, content, name, type);
socket.emitChanged('cloud-content-changed');
return {
status: 'ok',

View File

@@ -64,7 +64,7 @@ function startCloudTokenChecking(sid, callback) {
if (resp.data.status == 'ok') {
clearInterval(interval);
callback(resp.data.token);
callback(resp.data);
}
} catch (err) {
logger.error(extractErrorLogData(err), 'Error checking cloud token');
@@ -123,17 +123,26 @@ async function collectCloudFilesSearchTags() {
return res;
}
async function getCloudSigninHeaders() {
async function getCloudSigninHolder() {
const settingsValue = await config.getSettings();
const value = settingsValue['cloudSigninToken'];
if (value) {
const holder = settingsValue['cloudSigninTokenHolder'];
return holder;
}
async function getCloudSigninHeaders(holder = null) {
if (!holder) {
holder = await getCloudSigninHolder();
}
if (holder) {
return {
'x-cloud-login': value,
'x-cloud-login': holder.token,
};
}
return null;
}
let cloudFilesWereUpdated = false;
async function updateCloudFiles() {
let lastCloudFilesTags;
try {
@@ -151,7 +160,9 @@ async function updateCloudFiles() {
logger.info({ tags, lastCheckedTm }, 'Downloading cloud files');
const resp = await axios.default.get(
`${DBGATE_CLOUD_URL}/public-cloud-updates?lastCheckedTm=${lastCheckedTm}&tags=${tags}`,
`${DBGATE_CLOUD_URL}/public-cloud-updates?lastCheckedTm=${lastCheckedTm}&tags=${tags}&isRefresh=${
cloudFilesWereUpdated ? 1 : 0
}`,
{
headers: {
...getLicenseHttpHeaders(),
@@ -159,6 +170,7 @@ async function updateCloudFiles() {
},
}
);
cloudFilesWereUpdated = true;
logger.info(`Downloaded ${resp.data.length} cloud files`);
@@ -210,26 +222,33 @@ async function refreshPublicFiles() {
}
}
async function callCloudApiGet(endpoint) {
const signinHeaders = await getCloudSigninHeaders();
if (!signinHeaders) {
async function callCloudApiGet(endpoint, signinHolder = null, additionalHeaders = {}) {
if (!signinHolder) {
signinHolder = await getCloudSigninHolder();
}
if (!signinHolder) {
return null;
}
const signinHeaders = await getCloudSigninHeaders(signinHolder);
const resp = await axios.default.get(`${DBGATE_CLOUD_URL}/${endpoint}`, {
headers: {
...getLicenseHttpHeaders(),
...signinHeaders,
...additionalHeaders,
},
});
return resp.data;
}
async function callCloudApiPost(endpoint, body) {
const signinHeaders = await getCloudSigninHeaders();
if (!signinHeaders) {
async function callCloudApiPost(endpoint, body, signinHolder = null) {
if (!signinHolder) {
signinHolder = await getCloudSigninHolder();
}
if (!signinHolder) {
return null;
}
const signinHeaders = await getCloudSigninHeaders(signinHolder);
const resp = await axios.default.post(`${DBGATE_CLOUD_URL}/${endpoint}`, body, {
headers: {
@@ -249,8 +268,45 @@ async function getCloudFolderEncryptor(folid) {
}
async function getCloudContent(folid, cntid) {
const { content, name, type } = await callCloudApiGet(`content/${folid}/${cntid}`);
return { content, name, type };
const signinHolder = await getCloudSigninHolder();
if (!signinHolder) {
throw new Error('No signed in');
}
const encryptor = simpleEncryptor.createEncryptor(signinHolder.encryptionKey);
const { content, name, type } = await callCloudApiGet(`content/${folid}/${cntid}`, signinHolder, {
'x-kehid': signinHolder.kehid,
});
return {
content: encryptor.decrypt(content),
name,
type,
};
}
async function putCloudContent(folid, cntid, content, name, type) {
const signinHolder = await getCloudSigninHolder();
if (!signinHolder) {
throw new Error('No signed in');
}
const encryptor = simpleEncryptor.createEncryptor(signinHolder.encryptionKey);
await callCloudApiPost(
`put-content`,
{
folid,
cntid,
name,
type,
kehid: signinHolder.kehid,
content: encryptor.encrypt(content),
},
signinHolder
);
socket.emitChanged('cloud-content-changed');
}
const cloudConnectionCache = {};
@@ -278,4 +334,5 @@ module.exports = {
getCloudFolderEncryptor,
getCloudContent,
loadCachedCloudConnection,
putCloudContent,
};

View File

@@ -108,7 +108,7 @@
import _ from 'lodash';
import AppObjectCore from './AppObjectCore.svelte';
import {
cloudSigninToken,
cloudSigninTokenHolder,
currentDatabase,
DEFAULT_CONNECTION_SEARCH_SETTINGS,
expandedConnections,
@@ -334,7 +334,7 @@
onClick: handleDuplicate,
},
!$openedConnections.includes(data._id) &&
$cloudSigninToken &&
$cloudSigninTokenHolder &&
passProps?.cloudContentList?.length > 0 && {
text: _t('connection.moveToCloudFolder', { defaultMessage: 'Move to cloud folder' }),
submenu: passProps?.cloudContentList?.map(fld => ({

View File

@@ -1,5 +1,5 @@
import {
cloudSigninToken,
cloudSigninTokenHolder,
currentDatabase,
currentTheme,
emptyConnectionGroupNames,
@@ -668,7 +668,7 @@ registerCommand({
category: 'Cloud',
name: 'Logout',
onClick: () => {
cloudSigninToken.set(null);
cloudSigninTokenHolder.set(null);
},
});

View File

@@ -182,14 +182,10 @@ export const focusedConnectionOrDatabase = writable<{ conid: string; database?:
export const focusedTreeDbKey = writable<{ key: string; root: string; type: string; text: string }>(null);
export const cloudSigninToken = writableSettingsValue(null, 'cloudSigninToken');
export const cloudSigninTokenHolder = writableSettingsValue(null, 'cloudSigninTokenHolder');
export const cloudConnectionsStore = writable({});
// export const cloudSigninToken = getElectron()
// ? writableSettingsValue(null, 'cloudSigninToken')
// : writableWithStorage(null, 'cloudSigninToken');
export const DEFAULT_OBJECT_SEARCH_SETTINGS = {
pureName: true,
schemaName: false,

View File

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

View File

@@ -16,7 +16,7 @@
import { apiCall } from '../utility/api';
import {
cloudConnectionsStore,
cloudSigninToken,
cloudSigninTokenHolder,
currentDatabase,
expandedConnections,
openedConnections,
@@ -82,7 +82,7 @@
name="privateCloud"
height="50%"
storageName="privateCloudItems"
skip={!$cloudSigninToken}
skip={!$cloudSigninTokenHolder}
>
<WidgetsInnerContainer>
<SearchBoxWrapper>

View File

@@ -9,7 +9,7 @@
visibleHamburgerMenuWidget,
lockedDatabaseMode,
getCurrentConfig,
cloudSigninToken,
cloudSigninTokenHolder,
} from '../stores';
import mainMenuDefinition from '../../../../app/src/mainMenuDefinition';
import hasPermission from '../utility/hasPermission';
@@ -149,7 +149,7 @@
{#each widgets
.filter(x => x && hasPermission(`widgets/${x.name}`))
.filter(x => !x.isPremiumPromo || !isProApp())
.filter(x => x.name != 'cloud-private' || $cloudSigninToken) as item}
.filter(x => x.name != 'cloud-private' || $cloudSigninTokenHolder) as item}
<div
class="wrapper"
class:selected={item.name == $visibleSelectedWidget}
@@ -176,7 +176,7 @@
<FontIcon icon={$lockedDatabaseMode ? 'icon locked-database-mode' : 'icon unlocked-database-mode'} />
</div> -->
{#if $cloudSigninToken}
{#if $cloudSigninTokenHolder}
<div
class="wrapper"
on:click={handleCloudAccountMenu}