diff --git a/packages/api/src/controllers/cloud.js b/packages/api/src/controllers/cloud.js
index 7541ef023..9561ca71e 100644
--- a/packages/api/src/controllers/cloud.js
+++ b/packages/api/src/controllers/cloud.js
@@ -4,8 +4,13 @@ const {
refreshPublicFiles,
callCloudApiGet,
callCloudApiPost,
+ getCloudFolderEncryptor,
} = require('../utility/cloudIntf');
+const connections = require('./connections');
const socket = require('../utility/socket');
+const { decryptConnection, recryptConnection, getInternalEncryptor } = require('../utility/crypting');
+const { getConnectionLabel, getLogger, extractErrorLogData } = require('dbgate-tools');
+const logger = getLogger('cloud');
module.exports = {
publicFiles_meta: true,
@@ -30,9 +35,14 @@ module.exports = {
contentList_meta: true,
async contentList() {
- const resp = callCloudApiGet('content-list');
- console.log('contentList', resp);
- return resp;
+ try {
+ const resp = await callCloudApiGet('content-list');
+ return resp;
+ } catch (err) {
+ logger.error(extractErrorLogData(err), 'Error getting cloud content list');
+
+ return [];
+ }
},
getContent_meta: true,
@@ -79,4 +89,21 @@ module.exports = {
status: 'ok',
};
},
+
+ moveConnectionCloud_meta: true,
+ async moveConnectionCloud({ conid, folid }) {
+ const conn = await connections.getCore({ conid });
+ const folderEncryptor = getCloudFolderEncryptor(folid);
+ const recryptedConn = recryptConnection(conn, getInternalEncryptor(), folderEncryptor);
+ await this.putContent({
+ folid,
+ cntid: conid,
+ content: JSON.stringify(recryptedConn),
+ name: getConnectionLabel(conn),
+ type: 'connection',
+ });
+ return {
+ status: 'ok',
+ };
+ },
};
diff --git a/packages/api/src/utility/cloudIntf.js b/packages/api/src/utility/cloudIntf.js
index 4398c20c5..a1ad374a6 100644
--- a/packages/api/src/utility/cloudIntf.js
+++ b/packages/api/src/utility/cloudIntf.js
@@ -10,6 +10,7 @@ const connections = require('../controllers/connections');
const { isProApp } = require('./checkLicense');
const socket = require('./socket');
const config = require('../controllers/config');
+const simpleEncryptor = require('simple-encryptor');
const logger = getLogger('cloudIntf');
@@ -239,6 +240,14 @@ async function callCloudApiPost(endpoint, body) {
return resp.data;
}
+async function getCloudFolderEncryptor(folid) {
+ const { encryptionKey } = await callCloudApiGet(`folder-key/${folid}`);
+ if (!encryptionKey) {
+ throw new Error('No encryption key');
+ }
+ return simpleEncryptor.createEncryptor(encryptionKey);
+}
+
module.exports = {
createDbGateIdentitySession,
startCloudTokenChecking,
@@ -248,4 +257,5 @@ module.exports = {
refreshPublicFiles,
callCloudApiGet,
callCloudApiPost,
+ getCloudFolderEncryptor,
};
diff --git a/packages/web/src/appobj/CloudContentAppObject.svelte b/packages/web/src/appobj/CloudContentAppObject.svelte
new file mode 100644
index 000000000..9a9b75a62
--- /dev/null
+++ b/packages/web/src/appobj/CloudContentAppObject.svelte
@@ -0,0 +1,30 @@
+
+
+
+
+
+
+
diff --git a/packages/web/src/appobj/ConnectionAppObject.svelte b/packages/web/src/appobj/ConnectionAppObject.svelte
index 43a9a4663..d6fedd9ab 100644
--- a/packages/web/src/appobj/ConnectionAppObject.svelte
+++ b/packages/web/src/appobj/ConnectionAppObject.svelte
@@ -108,6 +108,7 @@
import _ from 'lodash';
import AppObjectCore from './AppObjectCore.svelte';
import {
+ cloudSigninToken,
currentDatabase,
DEFAULT_CONNECTION_SEARCH_SETTINGS,
expandedConnections,
@@ -332,6 +333,17 @@
text: _t('connection.duplicate', { defaultMessage: 'Duplicate' }),
onClick: handleDuplicate,
},
+ !$openedConnections.includes(data._id) &&
+ $cloudSigninToken &&
+ passProps?.cloudContentList?.length > 0 && {
+ text: _t('connection.moveToCloudFolder', { defaultMessage: 'Move to cloud folder' }),
+ submenu: passProps?.cloudContentList?.map(fld => ({
+ text: fld.name,
+ onClick: () => {
+ apiCall('cloud/move-connection-cloud', { conid: data._id, folid: fld.folid });
+ },
+ })),
+ },
],
{ divider: true },
!data.singleDatabase && [
diff --git a/packages/web/src/appobj/CloudFileAppObject.svelte b/packages/web/src/appobj/PublicCloudFileAppObject.svelte
similarity index 100%
rename from packages/web/src/appobj/CloudFileAppObject.svelte
rename to packages/web/src/appobj/PublicCloudFileAppObject.svelte
diff --git a/packages/web/src/stores.ts b/packages/web/src/stores.ts
index c0857d36e..3e351ee19 100644
--- a/packages/web/src/stores.ts
+++ b/packages/web/src/stores.ts
@@ -183,7 +183,6 @@ 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 cloudEncryptKeysByFolder = writableSettingsValue({}, 'cloudEncryptKeysByFolder');
// export const cloudSigninToken = getElectron()
// ? writableSettingsValue(null, 'cloudSigninToken')
diff --git a/packages/web/src/widgets/CloudItemsWidget.svelte b/packages/web/src/widgets/CloudItemsWidget.svelte
index 439a0376c..4e7ef3b36 100644
--- a/packages/web/src/widgets/CloudItemsWidget.svelte
+++ b/packages/web/src/widgets/CloudItemsWidget.svelte
@@ -5,7 +5,8 @@
import WidgetColumnBarItem from './WidgetColumnBarItem.svelte';
import AppObjectList from '../appobj/AppObjectList.svelte';
- import * as cloudFileAppObject from '../appobj/CloudFileAppObject.svelte';
+ import * as publicCloudFileAppObject from '../appobj/PublicCloudFileAppObject.svelte';
+ import * as cloudContentAppObject from '../appobj/CloudContentAppObject.svelte';
import { useCloudContentList, usePublicCloudFiles } from '../utility/metadataLoaders';
import { _t } from '../translations';
@@ -26,7 +27,7 @@
$: cloudContentList = useCloudContentList();
$: emptyCloudContent = ($cloudContentList || []).filter(x => !x.items?.length).map(x => x.folid);
- $: cloudContentFlat = ($cloudContentList || []).flatMap(fld => fld.items ?? []).map(x => x.folid);
+ $: cloudContentFlat = ($cloudContentList || []).flatMap(fld => fld.items ?? []);
$: contentGroupTitleMap = _.fromPairs(($cloudContentList || []).map(x => [x.folid, x.name]));
async function handleRefreshPublic() {
@@ -61,7 +62,7 @@
data.folid}
mapGroupTitle={folid => contentGroupTitleMap[folid]}
@@ -86,7 +87,7 @@
data.folder || undefined}
filter={publicFilter}
/>
diff --git a/packages/web/src/widgets/ConnectionList.svelte b/packages/web/src/widgets/ConnectionList.svelte
index 463e46e23..0e9227335 100644
--- a/packages/web/src/widgets/ConnectionList.svelte
+++ b/packages/web/src/widgets/ConnectionList.svelte
@@ -351,6 +351,7 @@
isExpandable={data => $openedConnections.includes(data._id) && !data.singleDatabase}
{filter}
passProps={{
+ ...passProps,
connectionColorFactory: $connectionColorFactory,
showPinnedInsteadOfUnpin: true,
searchSettings: $connectionAppObjectSearchSettings,
diff --git a/packages/web/src/widgets/DatabaseWidget.svelte b/packages/web/src/widgets/DatabaseWidget.svelte
index 7e525c090..cce04923d 100644
--- a/packages/web/src/widgets/DatabaseWidget.svelte
+++ b/packages/web/src/widgets/DatabaseWidget.svelte
@@ -1,7 +1,7 @@
@@ -45,7 +46,12 @@
height="35%"
storageName="connectionsWidget"
>
- domSqlObjectList.focus() }} />
+ domSqlObjectList.focus(),
+ cloudContentList: $cloudContentList,
+ }}
+ />
{/if}