mirror of
https://github.com/DeNNiiInc/dbgate.git
synced 2026-04-17 22:36:01 +00:00
SYNC: Merge pull request #8 from dbgate/feature/db-table-permissions
This commit is contained in:
@@ -2,6 +2,7 @@ DEVMODE=1
|
||||
SHELL_SCRIPTING=1
|
||||
ALLOW_DBGATE_PRIVATE_CLOUD=1
|
||||
DEVWEB=1
|
||||
LOCAL_AUTH_PROXY=1
|
||||
# LOCAL_AI_GATEWAY=true
|
||||
|
||||
# REDIRECT_TO_DBGATE_CLOUD_LOGIN=1
|
||||
|
||||
@@ -36,12 +36,24 @@ class AuthProviderBase {
|
||||
return !!req?.user || !!req?.auth;
|
||||
}
|
||||
|
||||
getCurrentPermissions(req) {
|
||||
async getCurrentPermissions(req) {
|
||||
const login = this.getCurrentLogin(req);
|
||||
const permissions = process.env[`LOGIN_PERMISSIONS_${login}`];
|
||||
return permissions || process.env.PERMISSIONS;
|
||||
}
|
||||
|
||||
async checkCurrentConnectionPermission(req, conid) {
|
||||
return true;
|
||||
}
|
||||
|
||||
async getCurrentDatabasePermissions(req) {
|
||||
return [];
|
||||
}
|
||||
|
||||
async getCurrentTablePermissions(req) {
|
||||
return [];
|
||||
}
|
||||
|
||||
getLoginPageConnections() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -51,6 +51,7 @@ function authMiddleware(req, res, next) {
|
||||
'/auth/oauth-token',
|
||||
'/auth/login',
|
||||
'/auth/redirect',
|
||||
'/redirect',
|
||||
'/stream',
|
||||
'/storage/get-connections-for-login-page',
|
||||
'/storage/set-admin-password',
|
||||
@@ -139,9 +140,9 @@ module.exports = {
|
||||
const accessToken = jwt.sign(
|
||||
{
|
||||
login: 'superadmin',
|
||||
permissions: await storage.loadSuperadminPermissions(),
|
||||
roleId: -3,
|
||||
licenseUid,
|
||||
amoid: 'superadmin',
|
||||
},
|
||||
getTokenSecret(),
|
||||
{
|
||||
|
||||
@@ -3,7 +3,7 @@ const os = require('os');
|
||||
const path = require('path');
|
||||
const axios = require('axios');
|
||||
const { datadir, getLogsFilePath } = require('../utility/directories');
|
||||
const { hasPermission } = require('../utility/hasPermission');
|
||||
const { hasPermission, loadPermissionsFromRequest } = require('../utility/hasPermission');
|
||||
const socket = require('../utility/socket');
|
||||
const _ = require('lodash');
|
||||
const AsyncLock = require('async-lock');
|
||||
@@ -46,7 +46,7 @@ module.exports = {
|
||||
async get(_params, req) {
|
||||
const authProvider = getAuthProviderFromReq(req);
|
||||
const login = authProvider.getCurrentLogin(req);
|
||||
const permissions = authProvider.getCurrentPermissions(req);
|
||||
const permissions = await authProvider.getCurrentPermissions(req);
|
||||
const isUserLoggedIn = authProvider.isUserLoggedIn(req);
|
||||
|
||||
const singleConid = authProvider.getSingleConnectionId(req);
|
||||
@@ -280,7 +280,8 @@ module.exports = {
|
||||
|
||||
updateSettings_meta: true,
|
||||
async updateSettings(values, req) {
|
||||
if (!hasPermission(`settings/change`, req)) return false;
|
||||
const loadedPermissions = await loadPermissionsFromRequest(req);
|
||||
if (!hasPermission(`settings/change`, loadedPermissions)) return false;
|
||||
cachedSettingsValue = null;
|
||||
|
||||
const res = await lock.acquire('settings', async () => {
|
||||
@@ -392,7 +393,8 @@ module.exports = {
|
||||
|
||||
exportConnectionsAndSettings_meta: true,
|
||||
async exportConnectionsAndSettings(_params, req) {
|
||||
if (!hasPermission(`admin/config`, req)) {
|
||||
const loadedPermissions = await loadPermissionsFromRequest(req);
|
||||
if (!hasPermission(`admin/config`, loadedPermissions)) {
|
||||
throw new Error('Permission denied: admin/config');
|
||||
}
|
||||
|
||||
@@ -416,7 +418,8 @@ module.exports = {
|
||||
|
||||
importConnectionsAndSettings_meta: true,
|
||||
async importConnectionsAndSettings({ db }, req) {
|
||||
if (!hasPermission(`admin/config`, req)) {
|
||||
const loadedPermissions = await loadPermissionsFromRequest(req);
|
||||
if (!hasPermission(`admin/config`, loadedPermissions)) {
|
||||
throw new Error('Permission denied: admin/config');
|
||||
}
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@ const JsonLinesDatabase = require('../utility/JsonLinesDatabase');
|
||||
const processArgs = require('../utility/processArgs');
|
||||
const { safeJsonParse, getLogger, extractErrorLogData } = require('dbgate-tools');
|
||||
const platformInfo = require('../utility/platformInfo');
|
||||
const { connectionHasPermission, testConnectionPermission } = require('../utility/hasPermission');
|
||||
const { connectionHasPermission, testConnectionPermission, loadPermissionsFromRequest } = require('../utility/hasPermission');
|
||||
const pipeForkLogs = require('../utility/pipeForkLogs');
|
||||
const requireEngineDriver = require('../utility/requireEngineDriver');
|
||||
const { getAuthProviderById } = require('../auth/authProvider');
|
||||
@@ -227,6 +227,7 @@ module.exports = {
|
||||
list_meta: true,
|
||||
async list(_params, req) {
|
||||
const storage = require('./storage');
|
||||
const loadedPermissions = await loadPermissionsFromRequest(req);
|
||||
|
||||
const storageConnections = await storage.connections(req);
|
||||
if (storageConnections) {
|
||||
@@ -234,9 +235,9 @@ module.exports = {
|
||||
}
|
||||
if (portalConnections) {
|
||||
if (platformInfo.allowShellConnection) return portalConnections;
|
||||
return portalConnections.map(maskConnection).filter(x => connectionHasPermission(x, req));
|
||||
return portalConnections.map(maskConnection).filter(x => connectionHasPermission(x, loadedPermissions));
|
||||
}
|
||||
return (await this.datastore.find()).filter(x => connectionHasPermission(x, req));
|
||||
return (await this.datastore.find()).filter(x => connectionHasPermission(x, loadedPermissions));
|
||||
},
|
||||
|
||||
async getUsedEngines() {
|
||||
@@ -375,7 +376,7 @@ module.exports = {
|
||||
update_meta: true,
|
||||
async update({ _id, values }, req) {
|
||||
if (portalConnections) return;
|
||||
testConnectionPermission(_id, req);
|
||||
await testConnectionPermission(_id, req);
|
||||
const res = await this.datastore.patch(_id, values);
|
||||
socket.emitChanged('connection-list-changed');
|
||||
return res;
|
||||
@@ -392,7 +393,7 @@ module.exports = {
|
||||
updateDatabase_meta: true,
|
||||
async updateDatabase({ conid, database, values }, req) {
|
||||
if (portalConnections) return;
|
||||
testConnectionPermission(conid, req);
|
||||
await testConnectionPermission(conid, req);
|
||||
const conn = await this.datastore.get(conid);
|
||||
let databases = (conn && conn.databases) || [];
|
||||
if (databases.find(x => x.name == database)) {
|
||||
@@ -410,7 +411,7 @@ module.exports = {
|
||||
delete_meta: true,
|
||||
async delete(connection, req) {
|
||||
if (portalConnections) return;
|
||||
testConnectionPermission(connection, req);
|
||||
await testConnectionPermission(connection, req);
|
||||
const res = await this.datastore.remove(connection._id);
|
||||
socket.emitChanged('connection-list-changed');
|
||||
return res;
|
||||
@@ -452,7 +453,7 @@ module.exports = {
|
||||
_id: '__model',
|
||||
};
|
||||
}
|
||||
testConnectionPermission(conid, req);
|
||||
await testConnectionPermission(conid, req);
|
||||
return this.getCore({ conid, mask: true });
|
||||
},
|
||||
|
||||
|
||||
@@ -29,7 +29,7 @@ const generateDeploySql = require('../shell/generateDeploySql');
|
||||
const { createTwoFilesPatch } = require('diff');
|
||||
const diff2htmlPage = require('../utility/diff2htmlPage');
|
||||
const processArgs = require('../utility/processArgs');
|
||||
const { testConnectionPermission } = require('../utility/hasPermission');
|
||||
const { testConnectionPermission, hasPermission, loadPermissionsFromRequest, loadTablePermissionsFromRequest, getTablePermissionRole, loadDatabasePermissionsFromRequest, getDatabasePermissionRole, getTablePermissionRoleLevelIndex, testDatabaseRolePermission } = require('../utility/hasPermission');
|
||||
const { MissingCredentialsError } = require('../utility/exceptions');
|
||||
const pipeForkLogs = require('../utility/pipeForkLogs');
|
||||
const crypto = require('crypto');
|
||||
@@ -100,7 +100,7 @@ module.exports = {
|
||||
socket.emitChanged(`database-status-changed`, { conid, database });
|
||||
},
|
||||
|
||||
handle_ping() {},
|
||||
handle_ping() { },
|
||||
|
||||
// session event handlers
|
||||
|
||||
@@ -235,7 +235,7 @@ module.exports = {
|
||||
|
||||
queryData_meta: true,
|
||||
async queryData({ conid, database, sql }, req) {
|
||||
testConnectionPermission(conid, req);
|
||||
await testConnectionPermission(conid, req);
|
||||
logger.info({ conid, database, sql }, 'DBGM-00007 Processing query');
|
||||
const opened = await this.ensureOpened(conid, database);
|
||||
// if (opened && opened.status && opened.status.name == 'error') {
|
||||
@@ -247,7 +247,7 @@ module.exports = {
|
||||
|
||||
sqlSelect_meta: true,
|
||||
async sqlSelect({ conid, database, select, auditLogSessionGroup }, req) {
|
||||
testConnectionPermission(conid, req);
|
||||
await testConnectionPermission(conid, req);
|
||||
const opened = await this.ensureOpened(conid, database);
|
||||
const res = await this.sendRequest(
|
||||
opened,
|
||||
@@ -256,24 +256,23 @@ module.exports = {
|
||||
auditLogger:
|
||||
auditLogSessionGroup && select?.from?.name?.pureName
|
||||
? response => {
|
||||
sendToAuditLog(req, {
|
||||
category: 'dbop',
|
||||
component: 'DatabaseConnectionsController',
|
||||
event: 'sql.select',
|
||||
action: 'select',
|
||||
severity: 'info',
|
||||
conid,
|
||||
database,
|
||||
schemaName: select?.from?.name?.schemaName,
|
||||
pureName: select?.from?.name?.pureName,
|
||||
sumint1: response?.rows?.length,
|
||||
sessionParam: `${conid}::${database}::${select?.from?.name?.schemaName || '0'}::${
|
||||
select?.from?.name?.pureName
|
||||
sendToAuditLog(req, {
|
||||
category: 'dbop',
|
||||
component: 'DatabaseConnectionsController',
|
||||
event: 'sql.select',
|
||||
action: 'select',
|
||||
severity: 'info',
|
||||
conid,
|
||||
database,
|
||||
schemaName: select?.from?.name?.schemaName,
|
||||
pureName: select?.from?.name?.pureName,
|
||||
sumint1: response?.rows?.length,
|
||||
sessionParam: `${conid}::${database}::${select?.from?.name?.schemaName || '0'}::${select?.from?.name?.pureName
|
||||
}`,
|
||||
sessionGroup: auditLogSessionGroup,
|
||||
message: `Loaded table data from ${select?.from?.name?.pureName}`,
|
||||
});
|
||||
}
|
||||
sessionGroup: auditLogSessionGroup,
|
||||
message: `Loaded table data from ${select?.from?.name?.pureName}`,
|
||||
});
|
||||
}
|
||||
: null,
|
||||
}
|
||||
);
|
||||
@@ -282,7 +281,9 @@ module.exports = {
|
||||
|
||||
runScript_meta: true,
|
||||
async runScript({ conid, database, sql, useTransaction, logMessage }, req) {
|
||||
testConnectionPermission(conid, req);
|
||||
const loadedPermissions = await loadPermissionsFromRequest(req);
|
||||
await testConnectionPermission(conid, req, loadedPermissions);
|
||||
await testDatabaseRolePermission(conid, database, 'run_script', req);
|
||||
logger.info({ conid, database, sql }, 'DBGM-00008 Processing script');
|
||||
const opened = await this.ensureOpened(conid, database);
|
||||
sendToAuditLog(req, {
|
||||
@@ -303,7 +304,7 @@ module.exports = {
|
||||
|
||||
runOperation_meta: true,
|
||||
async runOperation({ conid, database, operation, useTransaction }, req) {
|
||||
testConnectionPermission(conid, req);
|
||||
await testConnectionPermission(conid, req);
|
||||
logger.info({ conid, database, operation }, 'DBGM-00009 Processing operation');
|
||||
|
||||
sendToAuditLog(req, {
|
||||
@@ -325,7 +326,7 @@ module.exports = {
|
||||
|
||||
collectionData_meta: true,
|
||||
async collectionData({ conid, database, options, auditLogSessionGroup }, req) {
|
||||
testConnectionPermission(conid, req);
|
||||
await testConnectionPermission(conid, req);
|
||||
const opened = await this.ensureOpened(conid, database);
|
||||
const res = await this.sendRequest(
|
||||
opened,
|
||||
@@ -334,21 +335,21 @@ module.exports = {
|
||||
auditLogger:
|
||||
auditLogSessionGroup && options?.pureName
|
||||
? response => {
|
||||
sendToAuditLog(req, {
|
||||
category: 'dbop',
|
||||
component: 'DatabaseConnectionsController',
|
||||
event: 'nosql.collectionData',
|
||||
action: 'select',
|
||||
severity: 'info',
|
||||
conid,
|
||||
database,
|
||||
pureName: options?.pureName,
|
||||
sumint1: response?.result?.rows?.length,
|
||||
sessionParam: `${conid}::${database}::${options?.pureName}`,
|
||||
sessionGroup: auditLogSessionGroup,
|
||||
message: `Loaded collection data ${options?.pureName}`,
|
||||
});
|
||||
}
|
||||
sendToAuditLog(req, {
|
||||
category: 'dbop',
|
||||
component: 'DatabaseConnectionsController',
|
||||
event: 'nosql.collectionData',
|
||||
action: 'select',
|
||||
severity: 'info',
|
||||
conid,
|
||||
database,
|
||||
pureName: options?.pureName,
|
||||
sumint1: response?.result?.rows?.length,
|
||||
sessionParam: `${conid}::${database}::${options?.pureName}`,
|
||||
sessionGroup: auditLogSessionGroup,
|
||||
message: `Loaded collection data ${options?.pureName}`,
|
||||
});
|
||||
}
|
||||
: null,
|
||||
}
|
||||
);
|
||||
@@ -356,7 +357,7 @@ module.exports = {
|
||||
},
|
||||
|
||||
async loadDataCore(msgtype, { conid, database, ...args }, req) {
|
||||
testConnectionPermission(conid, req);
|
||||
await testConnectionPermission(conid, req);
|
||||
const opened = await this.ensureOpened(conid, database);
|
||||
const res = await this.sendRequest(opened, { msgtype, ...args });
|
||||
if (res.errorMessage) {
|
||||
@@ -371,7 +372,7 @@ module.exports = {
|
||||
|
||||
schemaList_meta: true,
|
||||
async schemaList({ conid, database }, req) {
|
||||
testConnectionPermission(conid, req);
|
||||
await testConnectionPermission(conid, req);
|
||||
return this.loadDataCore('schemaList', { conid, database });
|
||||
},
|
||||
|
||||
@@ -383,43 +384,43 @@ module.exports = {
|
||||
|
||||
loadKeys_meta: true,
|
||||
async loadKeys({ conid, database, root, filter, limit }, req) {
|
||||
testConnectionPermission(conid, req);
|
||||
await testConnectionPermission(conid, req);
|
||||
return this.loadDataCore('loadKeys', { conid, database, root, filter, limit });
|
||||
},
|
||||
|
||||
scanKeys_meta: true,
|
||||
async scanKeys({ conid, database, root, pattern, cursor, count }, req) {
|
||||
testConnectionPermission(conid, req);
|
||||
await testConnectionPermission(conid, req);
|
||||
return this.loadDataCore('scanKeys', { conid, database, root, pattern, cursor, count });
|
||||
},
|
||||
|
||||
exportKeys_meta: true,
|
||||
async exportKeys({ conid, database, options }, req) {
|
||||
testConnectionPermission(conid, req);
|
||||
await testConnectionPermission(conid, req);
|
||||
return this.loadDataCore('exportKeys', { conid, database, options });
|
||||
},
|
||||
|
||||
loadKeyInfo_meta: true,
|
||||
async loadKeyInfo({ conid, database, key }, req) {
|
||||
testConnectionPermission(conid, req);
|
||||
await testConnectionPermission(conid, req);
|
||||
return this.loadDataCore('loadKeyInfo', { conid, database, key });
|
||||
},
|
||||
|
||||
loadKeyTableRange_meta: true,
|
||||
async loadKeyTableRange({ conid, database, key, cursor, count }, req) {
|
||||
testConnectionPermission(conid, req);
|
||||
await testConnectionPermission(conid, req);
|
||||
return this.loadDataCore('loadKeyTableRange', { conid, database, key, cursor, count });
|
||||
},
|
||||
|
||||
loadFieldValues_meta: true,
|
||||
async loadFieldValues({ conid, database, schemaName, pureName, field, search, dataType }, req) {
|
||||
testConnectionPermission(conid, req);
|
||||
await testConnectionPermission(conid, req);
|
||||
return this.loadDataCore('loadFieldValues', { conid, database, schemaName, pureName, field, search, dataType });
|
||||
},
|
||||
|
||||
callMethod_meta: true,
|
||||
async callMethod({ conid, database, method, args }, req) {
|
||||
testConnectionPermission(conid, req);
|
||||
await testConnectionPermission(conid, req);
|
||||
return this.loadDataCore('callMethod', { conid, database, method, args });
|
||||
|
||||
// const opened = await this.ensureOpened(conid, database);
|
||||
@@ -432,7 +433,8 @@ module.exports = {
|
||||
|
||||
updateCollection_meta: true,
|
||||
async updateCollection({ conid, database, changeSet }, req) {
|
||||
testConnectionPermission(conid, req);
|
||||
await testConnectionPermission(conid, req);
|
||||
|
||||
const opened = await this.ensureOpened(conid, database);
|
||||
const res = await this.sendRequest(opened, { msgtype: 'updateCollection', changeSet });
|
||||
if (res.errorMessage) {
|
||||
@@ -443,6 +445,36 @@ module.exports = {
|
||||
return res.result || null;
|
||||
},
|
||||
|
||||
saveTableData_meta: true,
|
||||
async saveTableData({ conid, database, changeSet }, req) {
|
||||
await testConnectionPermission(conid, req);
|
||||
|
||||
const databasePermissions = await loadDatabasePermissionsFromRequest(req);
|
||||
const tablePermissions = await loadTablePermissionsFromRequest(req);
|
||||
const fieldsAndRoles = [
|
||||
[changeSet.inserts, 'create_update_delete'],
|
||||
[changeSet.deletes, 'create_update_delete'],
|
||||
[changeSet.updates, 'update_only'],
|
||||
]
|
||||
for (const [operations, requiredRole] of fieldsAndRoles) {
|
||||
for (const operation of operations) {
|
||||
const role = getTablePermissionRole(conid, database, 'tables', operation.schemaName, operation.pureName, tablePermissions, databasePermissions);
|
||||
if (getTablePermissionRoleLevelIndex(role) < getTablePermissionRoleLevelIndex(requiredRole)) {
|
||||
throw new Error('Permission not granted');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const opened = await this.ensureOpened(conid, database);
|
||||
const res = await this.sendRequest(opened, { msgtype: 'saveTableData', changeSet });
|
||||
if (res.errorMessage) {
|
||||
return {
|
||||
errorMessage: res.errorMessage,
|
||||
};
|
||||
}
|
||||
return res.result || null;
|
||||
},
|
||||
|
||||
status_meta: true,
|
||||
async status({ conid, database }, req) {
|
||||
if (!conid) {
|
||||
@@ -451,7 +483,7 @@ module.exports = {
|
||||
message: 'No connection',
|
||||
};
|
||||
}
|
||||
testConnectionPermission(conid, req);
|
||||
await testConnectionPermission(conid, req);
|
||||
const existing = this.opened.find(x => x.conid == conid && x.database == database);
|
||||
if (existing) {
|
||||
return {
|
||||
@@ -474,7 +506,7 @@ module.exports = {
|
||||
|
||||
ping_meta: true,
|
||||
async ping({ conid, database }, req) {
|
||||
testConnectionPermission(conid, req);
|
||||
await testConnectionPermission(conid, req);
|
||||
let existing = this.opened.find(x => x.conid == conid && x.database == database);
|
||||
|
||||
if (existing) {
|
||||
@@ -502,7 +534,7 @@ module.exports = {
|
||||
|
||||
refresh_meta: true,
|
||||
async refresh({ conid, database, keepOpen }, req) {
|
||||
testConnectionPermission(conid, req);
|
||||
await testConnectionPermission(conid, req);
|
||||
if (!keepOpen) this.close(conid, database);
|
||||
|
||||
await this.ensureOpened(conid, database);
|
||||
@@ -516,7 +548,7 @@ module.exports = {
|
||||
return { status: 'ok' };
|
||||
}
|
||||
|
||||
testConnectionPermission(conid, req);
|
||||
await testConnectionPermission(conid, req);
|
||||
const conn = await this.ensureOpened(conid, database);
|
||||
conn.subprocess.send({ msgtype: 'syncModel', isFullRefresh });
|
||||
return { status: 'ok' };
|
||||
@@ -553,7 +585,7 @@ module.exports = {
|
||||
|
||||
disconnect_meta: true,
|
||||
async disconnect({ conid, database }, req) {
|
||||
testConnectionPermission(conid, req);
|
||||
await testConnectionPermission(conid, req);
|
||||
await this.close(conid, database, true);
|
||||
return { status: 'ok' };
|
||||
},
|
||||
@@ -563,8 +595,9 @@ module.exports = {
|
||||
if (!conid || !database) {
|
||||
return {};
|
||||
}
|
||||
const loadedPermissions = await loadPermissionsFromRequest(req);
|
||||
|
||||
testConnectionPermission(conid, req);
|
||||
await testConnectionPermission(conid, req, loadedPermissions);
|
||||
if (conid == '__model') {
|
||||
const model = await importDbModel(database);
|
||||
const trans = await loadModelTransform(modelTransFile);
|
||||
@@ -586,6 +619,38 @@ module.exports = {
|
||||
message: `Loaded database structure for ${database}`,
|
||||
});
|
||||
|
||||
if (!hasPermission(`all-tables`, loadedPermissions)) {
|
||||
// filter databases by permissions
|
||||
const tablePermissions = await loadTablePermissionsFromRequest(req);
|
||||
const databasePermissions = await loadDatabasePermissionsFromRequest(req);
|
||||
const databasePermissionRole = getDatabasePermissionRole(conid, database, databasePermissions);
|
||||
|
||||
function applyTablePermissionRole(list, objectTypeField) {
|
||||
const res = [];
|
||||
for (const item of list ?? []) {
|
||||
const tablePermissionRole = getTablePermissionRole(conid, database, objectTypeField, item.schemaName, item.pureName, tablePermissions, databasePermissionRole);
|
||||
if (tablePermissionRole != 'deny') {
|
||||
res.push({
|
||||
...item,
|
||||
tablePermissionRole,
|
||||
});
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
const res = {
|
||||
...opened.structure,
|
||||
tables: applyTablePermissionRole(opened.structure.tables, 'tables'),
|
||||
views: applyTablePermissionRole(opened.structure.views, 'views'),
|
||||
procedures: applyTablePermissionRole(opened.structure.procedures, 'procedures'),
|
||||
functions: applyTablePermissionRole(opened.structure.functions, 'functions'),
|
||||
triggers: applyTablePermissionRole(opened.structure.triggers, 'triggers'),
|
||||
collections: applyTablePermissionRole(opened.structure.collections, 'collections'),
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
return opened.structure;
|
||||
// const existing = this.opened.find((x) => x.conid == conid && x.database == database);
|
||||
// if (existing) return existing.status;
|
||||
@@ -600,7 +665,7 @@ module.exports = {
|
||||
if (!conid) {
|
||||
return null;
|
||||
}
|
||||
testConnectionPermission(conid, req);
|
||||
await testConnectionPermission(conid, req);
|
||||
if (!conid) return null;
|
||||
const opened = await this.ensureOpened(conid, database);
|
||||
return opened.serverVersion || null;
|
||||
@@ -608,7 +673,7 @@ module.exports = {
|
||||
|
||||
sqlPreview_meta: true,
|
||||
async sqlPreview({ conid, database, objects, options }, req) {
|
||||
testConnectionPermission(conid, req);
|
||||
await testConnectionPermission(conid, req);
|
||||
// wait for structure
|
||||
await this.structure({ conid, database });
|
||||
|
||||
@@ -619,7 +684,7 @@ module.exports = {
|
||||
|
||||
exportModel_meta: true,
|
||||
async exportModel({ conid, database, outputFolder, schema }, req) {
|
||||
testConnectionPermission(conid, req);
|
||||
await testConnectionPermission(conid, req);
|
||||
|
||||
const realFolder = outputFolder.startsWith('archive:')
|
||||
? resolveArchiveFolder(outputFolder.substring('archive:'.length))
|
||||
@@ -637,7 +702,7 @@ module.exports = {
|
||||
|
||||
exportModelSql_meta: true,
|
||||
async exportModelSql({ conid, database, outputFolder, outputFile, schema }, req) {
|
||||
testConnectionPermission(conid, req);
|
||||
await testConnectionPermission(conid, req);
|
||||
|
||||
const connection = await connections.getCore({ conid });
|
||||
const driver = requireEngineDriver(connection);
|
||||
@@ -651,7 +716,7 @@ module.exports = {
|
||||
|
||||
generateDeploySql_meta: true,
|
||||
async generateDeploySql({ conid, database, archiveFolder }, req) {
|
||||
testConnectionPermission(conid, req);
|
||||
await testConnectionPermission(conid, req);
|
||||
const opened = await this.ensureOpened(conid, database);
|
||||
const res = await this.sendRequest(opened, {
|
||||
msgtype: 'generateDeploySql',
|
||||
@@ -816,17 +881,17 @@ module.exports = {
|
||||
return {
|
||||
...(command == 'backup'
|
||||
? driver.backupDatabaseCommand(
|
||||
connection,
|
||||
{ outputFile, database, options, selectedTables, skippedTables, argsFormat },
|
||||
// @ts-ignore
|
||||
externalTools
|
||||
)
|
||||
connection,
|
||||
{ outputFile, database, options, selectedTables, skippedTables, argsFormat },
|
||||
// @ts-ignore
|
||||
externalTools
|
||||
)
|
||||
: driver.restoreDatabaseCommand(
|
||||
connection,
|
||||
{ inputFile, database, options, argsFormat },
|
||||
// @ts-ignore
|
||||
externalTools
|
||||
)),
|
||||
connection,
|
||||
{ inputFile, database, options, argsFormat },
|
||||
// @ts-ignore
|
||||
externalTools
|
||||
)),
|
||||
transformMessage: driver.transformNativeCommandMessage
|
||||
? message => driver.transformNativeCommandMessage(message, command)
|
||||
: null,
|
||||
@@ -923,7 +988,7 @@ module.exports = {
|
||||
|
||||
executeSessionQuery_meta: true,
|
||||
async executeSessionQuery({ sesid, conid, database, sql }, req) {
|
||||
testConnectionPermission(conid, req);
|
||||
await testConnectionPermission(conid, req);
|
||||
logger.info({ sesid, sql }, 'DBGM-00010 Processing query');
|
||||
sessions.dispatchMessage(sesid, 'Query execution started');
|
||||
|
||||
@@ -935,7 +1000,7 @@ module.exports = {
|
||||
|
||||
evalJsonScript_meta: true,
|
||||
async evalJsonScript({ conid, database, script, runid }, req) {
|
||||
testConnectionPermission(conid, req);
|
||||
await testConnectionPermission(conid, req);
|
||||
const opened = await this.ensureOpened(conid, database);
|
||||
|
||||
opened.subprocess.send({ msgtype: 'evalJsonScript', script, runid });
|
||||
|
||||
@@ -3,7 +3,7 @@ const path = require('path');
|
||||
const crypto = require('crypto');
|
||||
const { filesdir, archivedir, resolveArchiveFolder, uploadsdir, appdir, jsldir } = require('../utility/directories');
|
||||
const getChartExport = require('../utility/getChartExport');
|
||||
const { hasPermission } = require('../utility/hasPermission');
|
||||
const { hasPermission, loadPermissionsFromRequest } = require('../utility/hasPermission');
|
||||
const socket = require('../utility/socket');
|
||||
const scheduler = require('./scheduler');
|
||||
const getDiagramExport = require('../utility/getDiagramExport');
|
||||
@@ -31,7 +31,8 @@ function deserialize(format, text) {
|
||||
module.exports = {
|
||||
list_meta: true,
|
||||
async list({ folder }, req) {
|
||||
if (!hasPermission(`files/${folder}/read`, req)) return [];
|
||||
const loadedPermissions = await loadPermissionsFromRequest(req);
|
||||
if (!hasPermission(`files/${folder}/read`, loadedPermissions)) return [];
|
||||
const dir = path.join(filesdir(), folder);
|
||||
if (!(await fs.exists(dir))) return [];
|
||||
const files = (await fs.readdir(dir)).map(file => ({ folder, file }));
|
||||
@@ -40,10 +41,11 @@ module.exports = {
|
||||
|
||||
listAll_meta: true,
|
||||
async listAll(_params, req) {
|
||||
const loadedPermissions = await loadPermissionsFromRequest(req);
|
||||
const folders = await fs.readdir(filesdir());
|
||||
const res = [];
|
||||
for (const folder of folders) {
|
||||
if (!hasPermission(`files/${folder}/read`, req)) continue;
|
||||
if (!hasPermission(`files/${folder}/read`, loadedPermissions)) continue;
|
||||
const dir = path.join(filesdir(), folder);
|
||||
const files = (await fs.readdir(dir)).map(file => ({ folder, file }));
|
||||
res.push(...files);
|
||||
@@ -53,7 +55,8 @@ module.exports = {
|
||||
|
||||
delete_meta: true,
|
||||
async delete({ folder, file }, req) {
|
||||
if (!hasPermission(`files/${folder}/write`, req)) return false;
|
||||
const loadedPermissions = await loadPermissionsFromRequest(req);
|
||||
if (!hasPermission(`files/${folder}/write`, loadedPermissions)) return false;
|
||||
if (!checkSecureFilePathsWithoutDirectory(folder, file)) {
|
||||
return false;
|
||||
}
|
||||
@@ -65,7 +68,8 @@ module.exports = {
|
||||
|
||||
rename_meta: true,
|
||||
async rename({ folder, file, newFile }, req) {
|
||||
if (!hasPermission(`files/${folder}/write`, req)) return false;
|
||||
const loadedPermissions = await loadPermissionsFromRequest(req);
|
||||
if (!hasPermission(`files/${folder}/write`, loadedPermissions)) return false;
|
||||
if (!checkSecureFilePathsWithoutDirectory(folder, file, newFile)) {
|
||||
return false;
|
||||
}
|
||||
@@ -86,10 +90,11 @@ module.exports = {
|
||||
|
||||
copy_meta: true,
|
||||
async copy({ folder, file, newFile }, req) {
|
||||
const loadedPermissions = await loadPermissionsFromRequest(req);
|
||||
if (!checkSecureFilePathsWithoutDirectory(folder, file, newFile)) {
|
||||
return false;
|
||||
}
|
||||
if (!hasPermission(`files/${folder}/write`, req)) return false;
|
||||
if (!hasPermission(`files/${folder}/write`, loadedPermissions)) return false;
|
||||
await fs.copyFile(path.join(filesdir(), folder, file), path.join(filesdir(), folder, newFile));
|
||||
socket.emitChanged(`files-changed`, { folder });
|
||||
socket.emitChanged(`all-files-changed`);
|
||||
@@ -113,7 +118,8 @@ module.exports = {
|
||||
});
|
||||
return deserialize(format, text);
|
||||
} else {
|
||||
if (!hasPermission(`files/${folder}/read`, req)) return null;
|
||||
const loadedPermissions = await loadPermissionsFromRequest(req);
|
||||
if (!hasPermission(`files/${folder}/read`, loadedPermissions)) return null;
|
||||
const text = await fs.readFile(path.join(filesdir(), folder, file), { encoding: 'utf-8' });
|
||||
return deserialize(format, text);
|
||||
}
|
||||
@@ -131,18 +137,19 @@ module.exports = {
|
||||
|
||||
save_meta: true,
|
||||
async save({ folder, file, data, format }, req) {
|
||||
const loadedPermissions = await loadPermissionsFromRequest(req);
|
||||
if (!checkSecureFilePathsWithoutDirectory(folder, file)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (folder.startsWith('archive:')) {
|
||||
if (!hasPermission(`archive/write`, req)) return false;
|
||||
if (!hasPermission(`archive/write`, loadedPermissions)) return false;
|
||||
const dir = resolveArchiveFolder(folder.substring('archive:'.length));
|
||||
await fs.writeFile(path.join(dir, file), serialize(format, data));
|
||||
socket.emitChanged(`archive-files-changed`, { folder: folder.substring('archive:'.length) });
|
||||
return true;
|
||||
} else if (folder.startsWith('app:')) {
|
||||
if (!hasPermission(`apps/write`, req)) return false;
|
||||
if (!hasPermission(`apps/write`, loadedPermissions)) return false;
|
||||
const app = folder.substring('app:'.length);
|
||||
await fs.writeFile(path.join(appdir(), app, file), serialize(format, data));
|
||||
socket.emitChanged(`app-files-changed`, { app });
|
||||
@@ -150,7 +157,7 @@ module.exports = {
|
||||
apps.emitChangedDbApp(folder);
|
||||
return true;
|
||||
} else {
|
||||
if (!hasPermission(`files/${folder}/write`, req)) return false;
|
||||
if (!hasPermission(`files/${folder}/write`, loadedPermissions)) return false;
|
||||
const dir = path.join(filesdir(), folder);
|
||||
if (!(await fs.exists(dir))) {
|
||||
await fs.mkdir(dir);
|
||||
@@ -177,7 +184,8 @@ module.exports = {
|
||||
|
||||
favorites_meta: true,
|
||||
async favorites(_params, req) {
|
||||
if (!hasPermission(`files/favorites/read`, req)) return [];
|
||||
const loadedPermissions = await loadPermissionsFromRequest(req);
|
||||
if (!hasPermission(`files/favorites/read`, loadedPermissions)) return [];
|
||||
const dir = path.join(filesdir(), 'favorites');
|
||||
if (!(await fs.exists(dir))) return [];
|
||||
const files = await fs.readdir(dir);
|
||||
@@ -234,16 +242,17 @@ module.exports = {
|
||||
|
||||
getFileRealPath_meta: true,
|
||||
async getFileRealPath({ folder, file }, req) {
|
||||
const loadedPermissions = await loadPermissionsFromRequest(req);
|
||||
if (folder.startsWith('archive:')) {
|
||||
if (!hasPermission(`archive/write`, req)) return false;
|
||||
if (!hasPermission(`archive/write`, loadedPermissions)) return false;
|
||||
const dir = resolveArchiveFolder(folder.substring('archive:'.length));
|
||||
return path.join(dir, file);
|
||||
} else if (folder.startsWith('app:')) {
|
||||
if (!hasPermission(`apps/write`, req)) return false;
|
||||
if (!hasPermission(`apps/write`, loadedPermissions)) return false;
|
||||
const app = folder.substring('app:'.length);
|
||||
return path.join(appdir(), app, file);
|
||||
} else {
|
||||
if (!hasPermission(`files/${folder}/write`, req)) return false;
|
||||
if (!hasPermission(`files/${folder}/write`, loadedPermissions)) return false;
|
||||
const dir = path.join(filesdir(), folder);
|
||||
if (!(await fs.exists(dir))) {
|
||||
await fs.mkdir(dir);
|
||||
@@ -297,7 +306,8 @@ module.exports = {
|
||||
|
||||
exportFile_meta: true,
|
||||
async exportFile({ folder, file, filePath }, req) {
|
||||
if (!hasPermission(`files/${folder}/read`, req)) return false;
|
||||
const loadedPermissions = await loadPermissionsFromRequest(req);
|
||||
if (!hasPermission(`files/${folder}/read`, loadedPermissions)) return false;
|
||||
await fs.copyFile(path.join(filesdir(), folder, file), filePath);
|
||||
return true;
|
||||
},
|
||||
|
||||
@@ -7,7 +7,7 @@ const socket = require('../utility/socket');
|
||||
const compareVersions = require('compare-versions');
|
||||
const requirePlugin = require('../shell/requirePlugin');
|
||||
const downloadPackage = require('../utility/downloadPackage');
|
||||
const { hasPermission } = require('../utility/hasPermission');
|
||||
const { hasPermission, loadPermissionsFromRequest } = require('../utility/hasPermission');
|
||||
const _ = require('lodash');
|
||||
const packagedPluginsContent = require('../packagedPluginsContent');
|
||||
|
||||
@@ -118,7 +118,8 @@ module.exports = {
|
||||
|
||||
install_meta: true,
|
||||
async install({ packageName }, req) {
|
||||
if (!hasPermission(`plugins/install`, req)) return;
|
||||
const loadedPermissions = await loadPermissionsFromRequest(req);
|
||||
if (!hasPermission(`plugins/install`, loadedPermissions)) return;
|
||||
const dir = path.join(pluginsdir(), packageName);
|
||||
// @ts-ignore
|
||||
if (!(await fs.exists(dir))) {
|
||||
@@ -132,7 +133,8 @@ module.exports = {
|
||||
|
||||
uninstall_meta: true,
|
||||
async uninstall({ packageName }, req) {
|
||||
if (!hasPermission(`plugins/install`, req)) return;
|
||||
const loadedPermissions = await loadPermissionsFromRequest(req);
|
||||
if (!hasPermission(`plugins/install`, loadedPermissions)) return;
|
||||
const dir = path.join(pluginsdir(), packageName);
|
||||
await fs.rmdir(dir, { recursive: true });
|
||||
socket.emitChanged(`installed-plugins-changed`);
|
||||
@@ -143,7 +145,8 @@ module.exports = {
|
||||
|
||||
upgrade_meta: true,
|
||||
async upgrade({ packageName }, req) {
|
||||
if (!hasPermission(`plugins/install`, req)) return;
|
||||
const loadedPermissions = await loadPermissionsFromRequest(req);
|
||||
if (!hasPermission(`plugins/install`, loadedPermissions)) return;
|
||||
const dir = path.join(pluginsdir(), packageName);
|
||||
// @ts-ignore
|
||||
if (await fs.exists(dir)) {
|
||||
|
||||
@@ -21,6 +21,7 @@ const processArgs = require('../utility/processArgs');
|
||||
const platformInfo = require('../utility/platformInfo');
|
||||
const { checkSecureDirectories, checkSecureDirectoriesInScript } = require('../utility/security');
|
||||
const { sendToAuditLog, logJsonRunnerScript } = require('../utility/auditlog');
|
||||
const { testStandardPermission } = require('../utility/hasPermission');
|
||||
const logger = getLogger('runners');
|
||||
|
||||
function extractPlugins(script) {
|
||||
@@ -273,6 +274,8 @@ module.exports = {
|
||||
|
||||
start_meta: true,
|
||||
async start({ script }, req) {
|
||||
await testStandardPermission('run-shell-script', req);
|
||||
|
||||
const runid = crypto.randomUUID();
|
||||
|
||||
if (script.type == 'json') {
|
||||
|
||||
@@ -3,7 +3,7 @@ const fs = require('fs-extra');
|
||||
const path = require('path');
|
||||
const cron = require('node-cron');
|
||||
const runners = require('./runners');
|
||||
const { hasPermission } = require('../utility/hasPermission');
|
||||
const { hasPermission, loadPermissionsFromRequest } = require('../utility/hasPermission');
|
||||
const { getLogger } = require('dbgate-tools');
|
||||
|
||||
const logger = getLogger('scheduler');
|
||||
@@ -30,7 +30,8 @@ module.exports = {
|
||||
},
|
||||
|
||||
async reload(_params, req) {
|
||||
if (!hasPermission('files/shell/read', req)) return;
|
||||
const loadedPermissions = await loadPermissionsFromRequest(req);
|
||||
if (!hasPermission('files/shell/read', loadedPermissions)) return;
|
||||
const shellDir = path.join(filesdir(), 'shell');
|
||||
await this.unload();
|
||||
if (!(await fs.exists(shellDir))) return;
|
||||
|
||||
@@ -8,7 +8,13 @@ const { handleProcessCommunication } = require('../utility/processComm');
|
||||
const lock = new AsyncLock();
|
||||
const config = require('./config');
|
||||
const processArgs = require('../utility/processArgs');
|
||||
const { testConnectionPermission } = require('../utility/hasPermission');
|
||||
const {
|
||||
testConnectionPermission,
|
||||
loadPermissionsFromRequest,
|
||||
hasPermission,
|
||||
loadDatabasePermissionsFromRequest,
|
||||
getDatabasePermissionRole,
|
||||
} = require('../utility/hasPermission');
|
||||
const { MissingCredentialsError } = require('../utility/exceptions');
|
||||
const pipeForkLogs = require('../utility/pipeForkLogs');
|
||||
const { getLogger, extractErrorLogData } = require('dbgate-tools');
|
||||
@@ -40,7 +46,7 @@ module.exports = {
|
||||
existing.status = status;
|
||||
socket.emitChanged(`server-status-changed`);
|
||||
},
|
||||
handle_ping() {},
|
||||
handle_ping() { },
|
||||
handle_response(conid, { msgid, ...response }) {
|
||||
const [resolve, reject] = this.requests[msgid];
|
||||
resolve(response);
|
||||
@@ -135,7 +141,7 @@ module.exports = {
|
||||
|
||||
disconnect_meta: true,
|
||||
async disconnect({ conid }, req) {
|
||||
testConnectionPermission(conid, req);
|
||||
await testConnectionPermission(conid, req);
|
||||
await this.close(conid, true);
|
||||
return { status: 'ok' };
|
||||
},
|
||||
@@ -144,7 +150,9 @@ module.exports = {
|
||||
async listDatabases({ conid }, req) {
|
||||
if (!conid) return [];
|
||||
if (conid == '__model') return [];
|
||||
testConnectionPermission(conid, req);
|
||||
const loadedPermissions = await loadPermissionsFromRequest(req);
|
||||
|
||||
await testConnectionPermission(conid, req, loadedPermissions);
|
||||
const opened = await this.ensureOpened(conid);
|
||||
sendToAuditLog(req, {
|
||||
category: 'serverop',
|
||||
@@ -157,12 +165,29 @@ module.exports = {
|
||||
sessionGroup: 'listDatabases',
|
||||
message: `Loaded databases for connection`,
|
||||
});
|
||||
|
||||
if (!hasPermission(`all-databases`, loadedPermissions)) {
|
||||
// filter databases by permissions
|
||||
const databasePermissions = await loadDatabasePermissionsFromRequest(req);
|
||||
const res = [];
|
||||
for (const db of opened?.databases ?? []) {
|
||||
const databasePermissionRole = getDatabasePermissionRole(db.id, db.name, databasePermissions);
|
||||
if (databasePermissionRole != 'deny') {
|
||||
res.push({
|
||||
...db,
|
||||
databasePermissionRole,
|
||||
});
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
return opened?.databases ?? [];
|
||||
},
|
||||
|
||||
version_meta: true,
|
||||
async version({ conid }, req) {
|
||||
testConnectionPermission(conid, req);
|
||||
await testConnectionPermission(conid, req);
|
||||
const opened = await this.ensureOpened(conid);
|
||||
return opened?.version ?? null;
|
||||
},
|
||||
@@ -202,7 +227,7 @@ module.exports = {
|
||||
|
||||
refresh_meta: true,
|
||||
async refresh({ conid, keepOpen }, req) {
|
||||
testConnectionPermission(conid, req);
|
||||
await testConnectionPermission(conid, req);
|
||||
if (!keepOpen) this.close(conid);
|
||||
|
||||
await this.ensureOpened(conid);
|
||||
@@ -210,7 +235,7 @@ module.exports = {
|
||||
},
|
||||
|
||||
async sendDatabaseOp({ conid, msgtype, name }, req) {
|
||||
testConnectionPermission(conid, req);
|
||||
await testConnectionPermission(conid, req);
|
||||
const opened = await this.ensureOpened(conid);
|
||||
if (!opened) {
|
||||
return null;
|
||||
@@ -252,7 +277,7 @@ module.exports = {
|
||||
},
|
||||
|
||||
async loadDataCore(msgtype, { conid, ...args }, req) {
|
||||
testConnectionPermission(conid, req);
|
||||
await testConnectionPermission(conid, req);
|
||||
const opened = await this.ensureOpened(conid);
|
||||
if (!opened) {
|
||||
return null;
|
||||
@@ -270,8 +295,8 @@ module.exports = {
|
||||
|
||||
serverSummary_meta: true,
|
||||
async serverSummary({ conid }, req) {
|
||||
await testConnectionPermission(conid, req);
|
||||
logger.info({ conid }, 'DBGM-00260 Processing server summary');
|
||||
testConnectionPermission(conid, req);
|
||||
return this.loadDataCore('serverSummary', { conid });
|
||||
},
|
||||
|
||||
@@ -306,7 +331,7 @@ module.exports = {
|
||||
|
||||
summaryCommand_meta: true,
|
||||
async summaryCommand({ conid, command, row }, req) {
|
||||
testConnectionPermission(conid, req);
|
||||
await testConnectionPermission(conid, req);
|
||||
const opened = await this.ensureOpened(conid);
|
||||
if (!opened) {
|
||||
return null;
|
||||
|
||||
@@ -12,6 +12,7 @@ const { getLogger, extractErrorLogData } = require('dbgate-tools');
|
||||
const pipeForkLogs = require('../utility/pipeForkLogs');
|
||||
const config = require('./config');
|
||||
const { sendToAuditLog } = require('../utility/auditlog');
|
||||
const { testStandardPermission, testDatabaseRolePermission } = require('../utility/hasPermission');
|
||||
|
||||
const logger = getLogger('sessions');
|
||||
|
||||
@@ -94,7 +95,7 @@ module.exports = {
|
||||
socket.emit(`session-initialize-file-${jslid}`);
|
||||
},
|
||||
|
||||
handle_ping() {},
|
||||
handle_ping() { },
|
||||
|
||||
create_meta: true,
|
||||
async create({ conid, database }) {
|
||||
@@ -148,10 +149,12 @@ module.exports = {
|
||||
|
||||
executeQuery_meta: true,
|
||||
async executeQuery({ sesid, sql, autoCommit, autoDetectCharts, limitRows, frontMatter }, req) {
|
||||
await testStandardPermission('dbops/query', req);
|
||||
const session = this.opened.find(x => x.sesid == sesid);
|
||||
if (!session) {
|
||||
throw new Error('Invalid session');
|
||||
}
|
||||
await testDatabaseRolePermission(session.conid, session.database, 'run_script', req);
|
||||
|
||||
sendToAuditLog(req, {
|
||||
category: 'dbop',
|
||||
|
||||
@@ -17,13 +17,14 @@ const requireEngineDriver = require('../utility/requireEngineDriver');
|
||||
const { connectUtility } = require('../utility/connectUtility');
|
||||
const { handleProcessCommunication } = require('../utility/processComm');
|
||||
const generateDeploySql = require('../shell/generateDeploySql');
|
||||
const { dumpSqlSelect } = require('dbgate-sqltree');
|
||||
const { dumpSqlSelect, scriptToSql } = require('dbgate-sqltree');
|
||||
const { allowExecuteCustomScript, handleQueryStream } = require('../utility/handleQueryStream');
|
||||
const dbgateApi = require('../shell');
|
||||
const requirePlugin = require('../shell/requirePlugin');
|
||||
const path = require('path');
|
||||
const { rundir } = require('../utility/directories');
|
||||
const fs = require('fs-extra');
|
||||
const { changeSetToSql } = require('dbgate-datalib');
|
||||
|
||||
const logger = getLogger('dbconnProcess');
|
||||
|
||||
@@ -348,6 +349,27 @@ async function handleUpdateCollection({ msgid, changeSet }) {
|
||||
}
|
||||
}
|
||||
|
||||
async function handleSaveTableData({ msgid, changeSet }) {
|
||||
await waitStructure();
|
||||
try {
|
||||
const driver = requireEngineDriver(storedConnection);
|
||||
const script = driver.createSaveChangeSetScript(changeSet, analysedStructure, () =>
|
||||
changeSetToSql(changeSet, analysedStructure, driver.dialect)
|
||||
);
|
||||
const sql = scriptToSql(driver, script);
|
||||
await driver.script(dbhan, sql, { useTransaction: true });
|
||||
process.send({ msgtype: 'response', msgid });
|
||||
} catch (err) {
|
||||
process.send({
|
||||
msgtype: 'response',
|
||||
msgid,
|
||||
errorMessage: extractErrorMessage(err, 'Error executing SQL script'),
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
async function handleSqlPreview({ msgid, objects, options }) {
|
||||
await waitStructure();
|
||||
const driver = requireEngineDriver(storedConnection);
|
||||
@@ -464,6 +486,7 @@ const messageHandlers = {
|
||||
runScript: handleRunScript,
|
||||
runOperation: handleRunOperation,
|
||||
updateCollection: handleUpdateCollection,
|
||||
saveTableData: handleSaveTableData,
|
||||
collectionData: handleCollectionData,
|
||||
loadKeys: handleLoadKeys,
|
||||
scanKeys: handleScanKeys,
|
||||
|
||||
@@ -695,27 +695,27 @@ module.exports = {
|
||||
}
|
||||
},
|
||||
{
|
||||
"pureName": "roles",
|
||||
"pureName": "database_permission_roles",
|
||||
"columns": [
|
||||
{
|
||||
"pureName": "roles",
|
||||
"pureName": "database_permission_roles",
|
||||
"columnName": "id",
|
||||
"dataType": "int",
|
||||
"autoIncrement": true,
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"pureName": "roles",
|
||||
"pureName": "database_permission_roles",
|
||||
"columnName": "name",
|
||||
"dataType": "varchar(250)",
|
||||
"notNull": false
|
||||
"dataType": "varchar(100)",
|
||||
"notNull": true
|
||||
}
|
||||
],
|
||||
"foreignKeys": [],
|
||||
"primaryKey": {
|
||||
"pureName": "roles",
|
||||
"pureName": "database_permission_roles",
|
||||
"constraintType": "primaryKey",
|
||||
"constraintName": "PK_roles",
|
||||
"constraintName": "PK_database_permission_roles",
|
||||
"columns": [
|
||||
{
|
||||
"columnName": "id"
|
||||
@@ -725,15 +725,23 @@ module.exports = {
|
||||
"preloadedRows": [
|
||||
{
|
||||
"id": -1,
|
||||
"name": "anonymous-user"
|
||||
"name": "view"
|
||||
},
|
||||
{
|
||||
"id": -2,
|
||||
"name": "logged-user"
|
||||
"name": "read_content"
|
||||
},
|
||||
{
|
||||
"id": -3,
|
||||
"name": "superadmin"
|
||||
"name": "write_data"
|
||||
},
|
||||
{
|
||||
"id": -4,
|
||||
"name": "run_script"
|
||||
},
|
||||
{
|
||||
"id": -5,
|
||||
"name": "deny"
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -799,6 +807,98 @@ module.exports = {
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"pureName": "role_databases",
|
||||
"columns": [
|
||||
{
|
||||
"pureName": "role_databases",
|
||||
"columnName": "id",
|
||||
"dataType": "int",
|
||||
"autoIncrement": true,
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"pureName": "role_databases",
|
||||
"columnName": "role_id",
|
||||
"dataType": "int",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"pureName": "role_databases",
|
||||
"columnName": "connection_id",
|
||||
"dataType": "int",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"pureName": "role_databases",
|
||||
"columnName": "database_names_list",
|
||||
"dataType": "varchar(1000)",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"pureName": "role_databases",
|
||||
"columnName": "database_names_regex",
|
||||
"dataType": "varchar(1000)",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"pureName": "role_databases",
|
||||
"columnName": "database_permission_role_id",
|
||||
"dataType": "int",
|
||||
"notNull": true
|
||||
}
|
||||
],
|
||||
"foreignKeys": [
|
||||
{
|
||||
"constraintType": "foreignKey",
|
||||
"constraintName": "FK_role_databases_role_id",
|
||||
"pureName": "role_databases",
|
||||
"refTableName": "roles",
|
||||
"deleteAction": "CASCADE",
|
||||
"columns": [
|
||||
{
|
||||
"columnName": "role_id",
|
||||
"refColumnName": "id"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"constraintType": "foreignKey",
|
||||
"constraintName": "FK_role_databases_connection_id",
|
||||
"pureName": "role_databases",
|
||||
"refTableName": "connections",
|
||||
"deleteAction": "CASCADE",
|
||||
"columns": [
|
||||
{
|
||||
"columnName": "connection_id",
|
||||
"refColumnName": "id"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"constraintType": "foreignKey",
|
||||
"constraintName": "FK_role_databases_database_permission_role_id",
|
||||
"pureName": "role_databases",
|
||||
"refTableName": "database_permission_roles",
|
||||
"columns": [
|
||||
{
|
||||
"columnName": "database_permission_role_id",
|
||||
"refColumnName": "id"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"primaryKey": {
|
||||
"pureName": "role_databases",
|
||||
"constraintType": "primaryKey",
|
||||
"constraintName": "PK_role_databases",
|
||||
"columns": [
|
||||
{
|
||||
"columnName": "id"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"pureName": "role_permissions",
|
||||
"columns": [
|
||||
@@ -849,39 +949,132 @@ module.exports = {
|
||||
}
|
||||
},
|
||||
{
|
||||
"pureName": "users",
|
||||
"pureName": "role_tables",
|
||||
"columns": [
|
||||
{
|
||||
"pureName": "users",
|
||||
"pureName": "role_tables",
|
||||
"columnName": "id",
|
||||
"dataType": "int",
|
||||
"autoIncrement": true,
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"pureName": "users",
|
||||
"columnName": "login",
|
||||
"dataType": "varchar(250)",
|
||||
"pureName": "role_tables",
|
||||
"columnName": "role_id",
|
||||
"dataType": "int",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"pureName": "role_tables",
|
||||
"columnName": "connection_id",
|
||||
"dataType": "int",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"pureName": "users",
|
||||
"columnName": "password",
|
||||
"dataType": "varchar(250)",
|
||||
"pureName": "role_tables",
|
||||
"columnName": "database_names_list",
|
||||
"dataType": "varchar(1000)",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"pureName": "users",
|
||||
"columnName": "email",
|
||||
"dataType": "varchar(250)",
|
||||
"pureName": "role_tables",
|
||||
"columnName": "database_names_regex",
|
||||
"dataType": "varchar(1000)",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"pureName": "role_tables",
|
||||
"columnName": "schema_names_list",
|
||||
"dataType": "varchar(1000)",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"pureName": "role_tables",
|
||||
"columnName": "schema_names_regex",
|
||||
"dataType": "varchar(1000)",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"pureName": "role_tables",
|
||||
"columnName": "table_names_list",
|
||||
"dataType": "varchar(1000)",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"pureName": "role_tables",
|
||||
"columnName": "table_names_regex",
|
||||
"dataType": "varchar(1000)",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"pureName": "role_tables",
|
||||
"columnName": "table_permission_role_id",
|
||||
"dataType": "int",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"pureName": "role_tables",
|
||||
"columnName": "table_permission_scope_id",
|
||||
"dataType": "int",
|
||||
"notNull": true
|
||||
}
|
||||
],
|
||||
"foreignKeys": [
|
||||
{
|
||||
"constraintType": "foreignKey",
|
||||
"constraintName": "FK_role_tables_role_id",
|
||||
"pureName": "role_tables",
|
||||
"refTableName": "roles",
|
||||
"deleteAction": "CASCADE",
|
||||
"columns": [
|
||||
{
|
||||
"columnName": "role_id",
|
||||
"refColumnName": "id"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"constraintType": "foreignKey",
|
||||
"constraintName": "FK_role_tables_connection_id",
|
||||
"pureName": "role_tables",
|
||||
"refTableName": "connections",
|
||||
"deleteAction": "CASCADE",
|
||||
"columns": [
|
||||
{
|
||||
"columnName": "connection_id",
|
||||
"refColumnName": "id"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"constraintType": "foreignKey",
|
||||
"constraintName": "FK_role_tables_table_permission_role_id",
|
||||
"pureName": "role_tables",
|
||||
"refTableName": "table_permission_roles",
|
||||
"columns": [
|
||||
{
|
||||
"columnName": "table_permission_role_id",
|
||||
"refColumnName": "id"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"constraintType": "foreignKey",
|
||||
"constraintName": "FK_role_tables_table_permission_scope_id",
|
||||
"pureName": "role_tables",
|
||||
"refTableName": "table_permission_scopes",
|
||||
"columns": [
|
||||
{
|
||||
"columnName": "table_permission_scope_id",
|
||||
"refColumnName": "id"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"foreignKeys": [],
|
||||
"primaryKey": {
|
||||
"pureName": "users",
|
||||
"pureName": "role_tables",
|
||||
"constraintType": "primaryKey",
|
||||
"constraintName": "PK_users",
|
||||
"constraintName": "PK_role_tables",
|
||||
"columns": [
|
||||
{
|
||||
"columnName": "id"
|
||||
@@ -889,6 +1082,167 @@ module.exports = {
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"pureName": "roles",
|
||||
"columns": [
|
||||
{
|
||||
"pureName": "roles",
|
||||
"columnName": "id",
|
||||
"dataType": "int",
|
||||
"autoIncrement": true,
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"pureName": "roles",
|
||||
"columnName": "name",
|
||||
"dataType": "varchar(250)",
|
||||
"notNull": false
|
||||
}
|
||||
],
|
||||
"foreignKeys": [],
|
||||
"primaryKey": {
|
||||
"pureName": "roles",
|
||||
"constraintType": "primaryKey",
|
||||
"constraintName": "PK_roles",
|
||||
"columns": [
|
||||
{
|
||||
"columnName": "id"
|
||||
}
|
||||
]
|
||||
},
|
||||
"preloadedRows": [
|
||||
{
|
||||
"id": -1,
|
||||
"name": "anonymous-user"
|
||||
},
|
||||
{
|
||||
"id": -2,
|
||||
"name": "logged-user"
|
||||
},
|
||||
{
|
||||
"id": -3,
|
||||
"name": "superadmin"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"pureName": "table_permission_roles",
|
||||
"columns": [
|
||||
{
|
||||
"pureName": "table_permission_roles",
|
||||
"columnName": "id",
|
||||
"dataType": "int",
|
||||
"autoIncrement": true,
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"pureName": "table_permission_roles",
|
||||
"columnName": "name",
|
||||
"dataType": "varchar(100)",
|
||||
"notNull": true
|
||||
}
|
||||
],
|
||||
"foreignKeys": [],
|
||||
"primaryKey": {
|
||||
"pureName": "table_permission_roles",
|
||||
"constraintType": "primaryKey",
|
||||
"constraintName": "PK_table_permission_roles",
|
||||
"columns": [
|
||||
{
|
||||
"columnName": "id"
|
||||
}
|
||||
]
|
||||
},
|
||||
"preloadedRows": [
|
||||
{
|
||||
"id": -1,
|
||||
"name": "read"
|
||||
},
|
||||
{
|
||||
"id": -2,
|
||||
"name": "update_only"
|
||||
},
|
||||
{
|
||||
"id": -3,
|
||||
"name": "create_update_delete"
|
||||
},
|
||||
{
|
||||
"id": -4,
|
||||
"name": "run_script"
|
||||
},
|
||||
{
|
||||
"id": -5,
|
||||
"name": "deny"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"pureName": "table_permission_scopes",
|
||||
"columns": [
|
||||
{
|
||||
"pureName": "table_permission_scopes",
|
||||
"columnName": "id",
|
||||
"dataType": "int",
|
||||
"autoIncrement": true,
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"pureName": "table_permission_scopes",
|
||||
"columnName": "name",
|
||||
"dataType": "varchar(100)",
|
||||
"notNull": true
|
||||
}
|
||||
],
|
||||
"foreignKeys": [],
|
||||
"primaryKey": {
|
||||
"pureName": "table_permission_scopes",
|
||||
"constraintType": "primaryKey",
|
||||
"constraintName": "PK_table_permission_scopes",
|
||||
"columns": [
|
||||
{
|
||||
"columnName": "id"
|
||||
}
|
||||
]
|
||||
},
|
||||
"preloadedRows": [
|
||||
{
|
||||
"id": -1,
|
||||
"name": "all_objects"
|
||||
},
|
||||
{
|
||||
"id": -2,
|
||||
"name": "tables"
|
||||
},
|
||||
{
|
||||
"id": -3,
|
||||
"name": "views"
|
||||
},
|
||||
{
|
||||
"id": -4,
|
||||
"name": "tables_views_collections"
|
||||
},
|
||||
{
|
||||
"id": -5,
|
||||
"name": "procedures"
|
||||
},
|
||||
{
|
||||
"id": -6,
|
||||
"name": "functions"
|
||||
},
|
||||
{
|
||||
"id": -7,
|
||||
"name": "triggers"
|
||||
},
|
||||
{
|
||||
"id": -8,
|
||||
"name": "sql_objects"
|
||||
},
|
||||
{
|
||||
"id": -9,
|
||||
"name": "collections"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"pureName": "user_connections",
|
||||
"columns": [
|
||||
@@ -951,6 +1305,98 @@ module.exports = {
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"pureName": "user_databases",
|
||||
"columns": [
|
||||
{
|
||||
"pureName": "user_databases",
|
||||
"columnName": "id",
|
||||
"dataType": "int",
|
||||
"autoIncrement": true,
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"pureName": "user_databases",
|
||||
"columnName": "user_id",
|
||||
"dataType": "int",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"pureName": "user_databases",
|
||||
"columnName": "connection_id",
|
||||
"dataType": "int",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"pureName": "user_databases",
|
||||
"columnName": "database_names_list",
|
||||
"dataType": "varchar(1000)",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"pureName": "user_databases",
|
||||
"columnName": "database_names_regex",
|
||||
"dataType": "varchar(1000)",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"pureName": "user_databases",
|
||||
"columnName": "database_permission_role_id",
|
||||
"dataType": "int",
|
||||
"notNull": true
|
||||
}
|
||||
],
|
||||
"foreignKeys": [
|
||||
{
|
||||
"constraintType": "foreignKey",
|
||||
"constraintName": "FK_user_databases_user_id",
|
||||
"pureName": "user_databases",
|
||||
"refTableName": "users",
|
||||
"deleteAction": "CASCADE",
|
||||
"columns": [
|
||||
{
|
||||
"columnName": "user_id",
|
||||
"refColumnName": "id"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"constraintType": "foreignKey",
|
||||
"constraintName": "FK_user_databases_connection_id",
|
||||
"pureName": "user_databases",
|
||||
"refTableName": "connections",
|
||||
"deleteAction": "CASCADE",
|
||||
"columns": [
|
||||
{
|
||||
"columnName": "connection_id",
|
||||
"refColumnName": "id"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"constraintType": "foreignKey",
|
||||
"constraintName": "FK_user_databases_database_permission_role_id",
|
||||
"pureName": "user_databases",
|
||||
"refTableName": "database_permission_roles",
|
||||
"columns": [
|
||||
{
|
||||
"columnName": "database_permission_role_id",
|
||||
"refColumnName": "id"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"primaryKey": {
|
||||
"pureName": "user_databases",
|
||||
"constraintType": "primaryKey",
|
||||
"constraintName": "PK_user_databases",
|
||||
"columns": [
|
||||
{
|
||||
"columnName": "id"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"pureName": "user_permissions",
|
||||
"columns": [
|
||||
@@ -1061,6 +1507,181 @@ module.exports = {
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"pureName": "user_tables",
|
||||
"columns": [
|
||||
{
|
||||
"pureName": "user_tables",
|
||||
"columnName": "id",
|
||||
"dataType": "int",
|
||||
"autoIncrement": true,
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"pureName": "user_tables",
|
||||
"columnName": "user_id",
|
||||
"dataType": "int",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"pureName": "user_tables",
|
||||
"columnName": "connection_id",
|
||||
"dataType": "int",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"pureName": "user_tables",
|
||||
"columnName": "database_names_list",
|
||||
"dataType": "varchar(1000)",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"pureName": "user_tables",
|
||||
"columnName": "database_names_regex",
|
||||
"dataType": "varchar(1000)",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"pureName": "user_tables",
|
||||
"columnName": "schema_names_list",
|
||||
"dataType": "varchar(1000)",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"pureName": "user_tables",
|
||||
"columnName": "schema_names_regex",
|
||||
"dataType": "varchar(1000)",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"pureName": "user_tables",
|
||||
"columnName": "table_names_list",
|
||||
"dataType": "varchar(1000)",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"pureName": "user_tables",
|
||||
"columnName": "table_names_regex",
|
||||
"dataType": "varchar(1000)",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"pureName": "user_tables",
|
||||
"columnName": "table_permission_role_id",
|
||||
"dataType": "int",
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"pureName": "user_tables",
|
||||
"columnName": "table_permission_scope_id",
|
||||
"dataType": "int",
|
||||
"notNull": true
|
||||
}
|
||||
],
|
||||
"foreignKeys": [
|
||||
{
|
||||
"constraintType": "foreignKey",
|
||||
"constraintName": "FK_user_tables_user_id",
|
||||
"pureName": "user_tables",
|
||||
"refTableName": "users",
|
||||
"deleteAction": "CASCADE",
|
||||
"columns": [
|
||||
{
|
||||
"columnName": "user_id",
|
||||
"refColumnName": "id"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"constraintType": "foreignKey",
|
||||
"constraintName": "FK_user_tables_connection_id",
|
||||
"pureName": "user_tables",
|
||||
"refTableName": "connections",
|
||||
"deleteAction": "CASCADE",
|
||||
"columns": [
|
||||
{
|
||||
"columnName": "connection_id",
|
||||
"refColumnName": "id"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"constraintType": "foreignKey",
|
||||
"constraintName": "FK_user_tables_table_permission_role_id",
|
||||
"pureName": "user_tables",
|
||||
"refTableName": "table_permission_roles",
|
||||
"columns": [
|
||||
{
|
||||
"columnName": "table_permission_role_id",
|
||||
"refColumnName": "id"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"constraintType": "foreignKey",
|
||||
"constraintName": "FK_user_tables_table_permission_scope_id",
|
||||
"pureName": "user_tables",
|
||||
"refTableName": "table_permission_scopes",
|
||||
"columns": [
|
||||
{
|
||||
"columnName": "table_permission_scope_id",
|
||||
"refColumnName": "id"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"primaryKey": {
|
||||
"pureName": "user_tables",
|
||||
"constraintType": "primaryKey",
|
||||
"constraintName": "PK_user_tables",
|
||||
"columns": [
|
||||
{
|
||||
"columnName": "id"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"pureName": "users",
|
||||
"columns": [
|
||||
{
|
||||
"pureName": "users",
|
||||
"columnName": "id",
|
||||
"dataType": "int",
|
||||
"autoIncrement": true,
|
||||
"notNull": true
|
||||
},
|
||||
{
|
||||
"pureName": "users",
|
||||
"columnName": "login",
|
||||
"dataType": "varchar(250)",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"pureName": "users",
|
||||
"columnName": "password",
|
||||
"dataType": "varchar(250)",
|
||||
"notNull": false
|
||||
},
|
||||
{
|
||||
"pureName": "users",
|
||||
"columnName": "email",
|
||||
"dataType": "varchar(250)",
|
||||
"notNull": false
|
||||
}
|
||||
],
|
||||
"foreignKeys": [],
|
||||
"primaryKey": {
|
||||
"pureName": "users",
|
||||
"constraintType": "primaryKey",
|
||||
"constraintName": "PK_users",
|
||||
"columns": [
|
||||
{
|
||||
"columnName": "id"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
],
|
||||
"collections": [],
|
||||
|
||||
@@ -1,101 +1,302 @@
|
||||
const { compilePermissions, testPermission } = require('dbgate-tools');
|
||||
const { compilePermissions, testPermission, getPermissionsCacheKey } = require('dbgate-tools');
|
||||
const _ = require('lodash');
|
||||
const { getAuthProviderFromReq } = require('../auth/authProvider');
|
||||
|
||||
const cachedPermissions = {};
|
||||
|
||||
function hasPermission(tested, req) {
|
||||
async function loadPermissionsFromRequest(req) {
|
||||
const authProvider = getAuthProviderFromReq(req);
|
||||
if (!req) {
|
||||
// request object not available, allow all
|
||||
return null;
|
||||
}
|
||||
|
||||
const loadedPermissions = await authProvider.getCurrentPermissions(req);
|
||||
return loadedPermissions;
|
||||
}
|
||||
|
||||
function hasPermission(tested, loadedPermissions) {
|
||||
if (!loadedPermissions) {
|
||||
// not available, allow all
|
||||
return true;
|
||||
}
|
||||
|
||||
const permissions = getAuthProviderFromReq(req).getCurrentPermissions(req);
|
||||
|
||||
if (!cachedPermissions[permissions]) {
|
||||
cachedPermissions[permissions] = compilePermissions(permissions);
|
||||
const permissionsKey = getPermissionsCacheKey(loadedPermissions);
|
||||
if (!cachedPermissions[permissionsKey]) {
|
||||
cachedPermissions[permissionsKey] = compilePermissions(loadedPermissions);
|
||||
}
|
||||
|
||||
return testPermission(tested, cachedPermissions[permissions]);
|
||||
|
||||
// const { user } = (req && req.auth) || {};
|
||||
// const { login } = (process.env.OAUTH_PERMISSIONS && req && req.user) || {};
|
||||
// const key = user || login || '';
|
||||
// const logins = getLogins();
|
||||
|
||||
// if (!userPermissions[key]) {
|
||||
// if (logins) {
|
||||
// const login = logins.find(x => x.login == user);
|
||||
// userPermissions[key] = compilePermissions(login ? login.permissions : null);
|
||||
// } else {
|
||||
// userPermissions[key] = compilePermissions(process.env.PERMISSIONS);
|
||||
// }
|
||||
// }
|
||||
// return testPermission(tested, userPermissions[key]);
|
||||
return testPermission(tested, cachedPermissions[permissionsKey]);
|
||||
}
|
||||
|
||||
// let loginsCache = null;
|
||||
// let loginsLoaded = false;
|
||||
|
||||
// function getLogins() {
|
||||
// if (loginsLoaded) {
|
||||
// return loginsCache;
|
||||
// }
|
||||
|
||||
// const res = [];
|
||||
// if (process.env.LOGIN && process.env.PASSWORD) {
|
||||
// res.push({
|
||||
// login: process.env.LOGIN,
|
||||
// password: process.env.PASSWORD,
|
||||
// permissions: process.env.PERMISSIONS,
|
||||
// });
|
||||
// }
|
||||
// if (process.env.LOGINS) {
|
||||
// const logins = _.compact(process.env.LOGINS.split(',').map(x => x.trim()));
|
||||
// for (const login of logins) {
|
||||
// const password = process.env[`LOGIN_PASSWORD_${login}`];
|
||||
// const permissions = process.env[`LOGIN_PERMISSIONS_${login}`];
|
||||
// if (password) {
|
||||
// res.push({
|
||||
// login,
|
||||
// password,
|
||||
// permissions,
|
||||
// });
|
||||
// }
|
||||
// }
|
||||
// } else if (process.env.OAUTH_PERMISSIONS) {
|
||||
// const login_permission_keys = Object.keys(process.env).filter(key => _.startsWith(key, 'LOGIN_PERMISSIONS_'));
|
||||
// for (const permissions_key of login_permission_keys) {
|
||||
// const login = permissions_key.replace('LOGIN_PERMISSIONS_', '');
|
||||
// const permissions = process.env[permissions_key];
|
||||
// userPermissions[login] = compilePermissions(permissions);
|
||||
// }
|
||||
// }
|
||||
|
||||
// loginsCache = res.length > 0 ? res : null;
|
||||
// loginsLoaded = true;
|
||||
// return loginsCache;
|
||||
// }
|
||||
|
||||
function connectionHasPermission(connection, req) {
|
||||
function connectionHasPermission(connection, loadedPermissions) {
|
||||
if (!connection) {
|
||||
return true;
|
||||
}
|
||||
if (_.isString(connection)) {
|
||||
return hasPermission(`connections/${connection}`, req);
|
||||
return hasPermission(`connections/${connection}`, loadedPermissions);
|
||||
} else {
|
||||
return hasPermission(`connections/${connection._id}`, req);
|
||||
return hasPermission(`connections/${connection._id}`, loadedPermissions);
|
||||
}
|
||||
}
|
||||
|
||||
function testConnectionPermission(connection, req) {
|
||||
if (!connectionHasPermission(connection, req)) {
|
||||
throw new Error('Connection permission not granted');
|
||||
async function testConnectionPermission(connection, req, loadedPermissions) {
|
||||
if (!loadedPermissions) {
|
||||
loadedPermissions = await loadPermissionsFromRequest(req);
|
||||
}
|
||||
if (process.env.STORAGE_DATABASE) {
|
||||
if (hasPermission(`all-connections`, loadedPermissions)) {
|
||||
return;
|
||||
}
|
||||
const conid = _.isString(connection) ? connection : connection?._id;
|
||||
const authProvider = getAuthProviderFromReq(req);
|
||||
if (!req) {
|
||||
return;
|
||||
}
|
||||
if (!await authProvider.checkCurrentConnectionPermission(req, conid)) {
|
||||
throw new Error('Connection permission not granted');
|
||||
}
|
||||
} else {
|
||||
if (!connectionHasPermission(connection, loadedPermissions)) {
|
||||
throw new Error('Connection permission not granted');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function loadDatabasePermissionsFromRequest(req) {
|
||||
const authProvider = getAuthProviderFromReq(req);
|
||||
if (!req) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const databasePermissions = await authProvider.getCurrentDatabasePermissions(req);
|
||||
return databasePermissions;
|
||||
}
|
||||
|
||||
async function loadTablePermissionsFromRequest(req) {
|
||||
const authProvider = getAuthProviderFromReq(req);
|
||||
if (!req) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const tablePermissions = await authProvider.getCurrentTablePermissions(req);
|
||||
return tablePermissions;
|
||||
}
|
||||
|
||||
function matchDatabasePermissionRow(conid, database, permissionRow) {
|
||||
if (permissionRow.connection_id) {
|
||||
if (conid != permissionRow.connection_id) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (permissionRow.database_names_list) {
|
||||
const items = permissionRow.database_names_list.split('\n');
|
||||
if (!items.find(item => item.trim()?.toLowerCase() === database?.toLowerCase())) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (permissionRow.database_names_regex) {
|
||||
const regex = new RegExp(permissionRow.database_names_regex, 'i');
|
||||
if (!regex.test(database)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
function matchTablePermissionRow(objectTypeField, schemaName, pureName, permissionRow) {
|
||||
if (permissionRow.table_names_list) {
|
||||
const items = permissionRow.table_names_list.split('\n');
|
||||
if (!items.find(item => item.trim()?.toLowerCase() === pureName?.toLowerCase())) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (permissionRow.table_names_regex) {
|
||||
const regex = new RegExp(permissionRow.table_names_regex, 'i');
|
||||
if (!regex.test(pureName)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (permissionRow.schema_names_list) {
|
||||
const items = permissionRow.schema_names_list.split('\n');
|
||||
if (!items.find(item => item.trim()?.toLowerCase() === schemaName?.toLowerCase())) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (permissionRow.schema_names_regex) {
|
||||
const regex = new RegExp(permissionRow.schema_names_regex, 'i');
|
||||
if (!regex.test(schemaName)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
const DATABASE_ROLE_ID_NAMES = {
|
||||
'-1': 'view',
|
||||
'-2': 'read_content',
|
||||
'-3': 'write_data',
|
||||
'-4': 'run_script',
|
||||
'-5': 'deny',
|
||||
};
|
||||
|
||||
function getDatabaseRoleLevelIndex(roleName) {
|
||||
if (!roleName) {
|
||||
return 6;
|
||||
}
|
||||
if (roleName == 'run_script') {
|
||||
return 5;
|
||||
}
|
||||
if (roleName == 'write_data') {
|
||||
return 4;
|
||||
}
|
||||
if (roleName == 'read_content') {
|
||||
return 3;
|
||||
}
|
||||
if (roleName == 'view') {
|
||||
return 2;
|
||||
}
|
||||
if (roleName == 'deny') {
|
||||
return 1;
|
||||
}
|
||||
return 6;
|
||||
}
|
||||
|
||||
function getTablePermissionRoleLevelIndex(roleName) {
|
||||
if (!roleName) {
|
||||
return 6;
|
||||
}
|
||||
if (roleName == 'run_script') {
|
||||
return 5;
|
||||
}
|
||||
if (roleName == 'create_update_delete') {
|
||||
return 4;
|
||||
}
|
||||
if (roleName == 'update_only') {
|
||||
return 3;
|
||||
}
|
||||
if (roleName == 'read') {
|
||||
return 2;
|
||||
}
|
||||
if (roleName == 'deny') {
|
||||
return 1;
|
||||
}
|
||||
return 6;
|
||||
}
|
||||
|
||||
function getDatabasePermissionRole(conid, database, loadedDatabasePermissions) {
|
||||
let res = 'deny';
|
||||
for (const permissionRow of loadedDatabasePermissions) {
|
||||
if (!matchDatabasePermissionRow(conid, database, permissionRow)) {
|
||||
continue;
|
||||
}
|
||||
res = DATABASE_ROLE_ID_NAMES[permissionRow.database_permission_role_id];
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
const TABLE_ROLE_ID_NAMES = {
|
||||
'-1': 'read',
|
||||
'-2': 'update_only',
|
||||
'-3': 'create_update_delete',
|
||||
'-4': 'run_script',
|
||||
'-5': 'deny',
|
||||
};
|
||||
|
||||
const TABLE_SCOPE_ID_NAMES = {
|
||||
'-1': 'all_objects',
|
||||
'-2': 'tables',
|
||||
'-3': 'views',
|
||||
'-4': 'tables_views_collections',
|
||||
'-5': 'procedures',
|
||||
'-6': 'functions',
|
||||
'-7': 'triggers',
|
||||
'-8': 'sql_objects',
|
||||
'-9': 'collections',
|
||||
};
|
||||
|
||||
function getTablePermissionRole(conid, database, objectTypeField, schemaName, pureName, loadedTablePermissions, databasePermissionRole) {
|
||||
let res = databasePermissionRole == 'read_content' ? 'read' :
|
||||
databasePermissionRole == 'write_data' ? 'create_update_delete' :
|
||||
databasePermissionRole == 'run_script' ? 'run_script' :
|
||||
'deny';
|
||||
for (const permissionRow of loadedTablePermissions) {
|
||||
if (!matchDatabasePermissionRow(conid, database, permissionRow)) {
|
||||
continue;
|
||||
}
|
||||
if (!matchTablePermissionRow(objectTypeField, schemaName, pureName, permissionRow)) {
|
||||
continue;
|
||||
}
|
||||
const scope = TABLE_SCOPE_ID_NAMES[permissionRow.table_permission_scope_id];
|
||||
switch (scope) {
|
||||
case 'tables':
|
||||
if (objectTypeField != 'tables') continue;
|
||||
break;
|
||||
case 'views':
|
||||
if (objectTypeField != 'views') continue;
|
||||
break;
|
||||
case 'tables_views_collections':
|
||||
if (objectTypeField != 'tables' && objectTypeField != 'views' && objectTypeField != 'collections') continue;
|
||||
break;
|
||||
case 'procedures':
|
||||
if (objectTypeField != 'procedures') continue;
|
||||
break;
|
||||
case 'functions':
|
||||
if (objectTypeField != 'functions') continue;
|
||||
break;
|
||||
case 'triggers':
|
||||
if (objectTypeField != 'triggers') continue;
|
||||
break;
|
||||
case 'sql_objects':
|
||||
if (objectTypeField != 'procedures' && objectTypeField != 'functions' && objectTypeField != 'triggers')
|
||||
continue;
|
||||
break;
|
||||
case 'collections':
|
||||
if (objectTypeField != 'collections') continue;
|
||||
break;
|
||||
}
|
||||
res = TABLE_ROLE_ID_NAMES[permissionRow.table_permission_role_id];
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
async function testStandardPermission(permission, req, loadedPermissions) {
|
||||
if (!loadedPermissions) {
|
||||
loadedPermissions = await loadPermissionsFromRequest(req);
|
||||
}
|
||||
if (!hasPermission(permission, loadedPermissions)) {
|
||||
throw new Error('Permission not granted');
|
||||
}
|
||||
}
|
||||
|
||||
async function testDatabaseRolePermission(conid, database, requiredRole, req) {
|
||||
if (!process.env.STORAGE_DATABASE) {
|
||||
return;
|
||||
}
|
||||
const loadedPermissions = await loadPermissionsFromRequest(req);
|
||||
if (hasPermission(`all-databases`, loadedPermissions)) {
|
||||
return;
|
||||
}
|
||||
const databasePermissions = await loadDatabasePermissionsFromRequest(req);
|
||||
const role = getDatabasePermissionRole(conid, database, databasePermissions);
|
||||
const requiredIndex = getDatabaseRoleLevelIndex(requiredRole);
|
||||
const roleIndex = getDatabaseRoleLevelIndex(role);
|
||||
if (roleIndex < requiredIndex) {
|
||||
throw new Error('Permission not granted');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
module.exports = {
|
||||
hasPermission,
|
||||
connectionHasPermission,
|
||||
testConnectionPermission,
|
||||
loadPermissionsFromRequest,
|
||||
loadDatabasePermissionsFromRequest,
|
||||
loadTablePermissionsFromRequest,
|
||||
getDatabasePermissionRole,
|
||||
getTablePermissionRole,
|
||||
testStandardPermission,
|
||||
testDatabaseRolePermission,
|
||||
getTablePermissionRoleLevelIndex
|
||||
};
|
||||
|
||||
@@ -57,6 +57,12 @@ export function compilePermissions(permissions: string[] | string): CompiledPerm
|
||||
return res;
|
||||
}
|
||||
|
||||
export function getPermissionsCacheKey(permissions: string[] | string) {
|
||||
if (!permissions) return null;
|
||||
if (_isString(permissions)) return permissions;
|
||||
return permissions.join('|');
|
||||
}
|
||||
|
||||
export function testPermission(tested: string, permissions: CompiledPermissions) {
|
||||
let allow = true;
|
||||
|
||||
@@ -103,9 +109,9 @@ export function getPredefinedPermissions(predefinedRoleName: string) {
|
||||
case 'superadmin':
|
||||
return ['*', '~widgets/*', 'widgets/admin', 'widgets/database', '~all-connections'];
|
||||
case 'logged-user':
|
||||
return ['*', '~widgets/admin', '~admin/*', '~internal-storage', '~all-connections'];
|
||||
return ['*', '~widgets/admin', '~admin/*', '~internal-storage', '~all-connections', '~run-shell-script'];
|
||||
case 'anonymous-user':
|
||||
return ['*', '~widgets/admin', '~admin/*', '~internal-storage', '~all-connections'];
|
||||
return ['*', '~widgets/admin', '~admin/*', '~internal-storage', '~all-connections', '~run-shell-script'];
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
|
||||
29
packages/types/dbinfo.d.ts
vendored
29
packages/types/dbinfo.d.ts
vendored
@@ -22,7 +22,7 @@ export interface ColumnsConstraintInfo extends ConstraintInfo {
|
||||
columns: ColumnReference[];
|
||||
}
|
||||
|
||||
export interface PrimaryKeyInfo extends ColumnsConstraintInfo {}
|
||||
export interface PrimaryKeyInfo extends ColumnsConstraintInfo { }
|
||||
|
||||
export interface ForeignKeyInfo extends ColumnsConstraintInfo {
|
||||
refSchemaName?: string;
|
||||
@@ -39,7 +39,7 @@ export interface IndexInfo extends ColumnsConstraintInfo {
|
||||
filterDefinition?: string;
|
||||
}
|
||||
|
||||
export interface UniqueInfo extends ColumnsConstraintInfo {}
|
||||
export interface UniqueInfo extends ColumnsConstraintInfo { }
|
||||
|
||||
export interface CheckInfo extends ConstraintInfo {
|
||||
definition: string;
|
||||
@@ -77,6 +77,7 @@ export interface DatabaseObjectInfo extends NamedObjectInfo {
|
||||
hashCode?: string;
|
||||
objectTypeField?: string;
|
||||
objectComment?: string;
|
||||
tablePermissionRole?: 'read' | 'update_only' | 'create_update_delete' | 'deny';
|
||||
}
|
||||
|
||||
export interface SqlObjectInfo extends DatabaseObjectInfo {
|
||||
@@ -134,7 +135,7 @@ export interface CallableObjectInfo extends SqlObjectInfo {
|
||||
parameters?: ParameterInfo[];
|
||||
}
|
||||
|
||||
export interface ProcedureInfo extends CallableObjectInfo {}
|
||||
export interface ProcedureInfo extends CallableObjectInfo { }
|
||||
|
||||
export interface FunctionInfo extends CallableObjectInfo {
|
||||
returnType?: string;
|
||||
@@ -145,17 +146,17 @@ export interface TriggerInfo extends SqlObjectInfo {
|
||||
functionName?: string;
|
||||
tableName?: string;
|
||||
triggerTiming?:
|
||||
| 'BEFORE'
|
||||
| 'AFTER'
|
||||
| 'INSTEAD OF'
|
||||
| 'BEFORE EACH ROW'
|
||||
| 'INSTEAD OF'
|
||||
| 'AFTER EACH ROW'
|
||||
| 'AFTER STATEMENT'
|
||||
| 'BEFORE STATEMENT'
|
||||
| 'AFTER EVENT'
|
||||
| 'BEFORE EVENT'
|
||||
| null;
|
||||
| 'BEFORE'
|
||||
| 'AFTER'
|
||||
| 'INSTEAD OF'
|
||||
| 'BEFORE EACH ROW'
|
||||
| 'INSTEAD OF'
|
||||
| 'AFTER EACH ROW'
|
||||
| 'AFTER STATEMENT'
|
||||
| 'BEFORE STATEMENT'
|
||||
| 'AFTER EVENT'
|
||||
| 'BEFORE EVENT'
|
||||
| null;
|
||||
triggerLevel?: 'ROW' | 'STATEMENT';
|
||||
eventType?: 'INSERT' | 'UPDATE' | 'DELETE' | 'TRUNCATE';
|
||||
}
|
||||
|
||||
@@ -167,7 +167,7 @@ await dbgateApi.deployDb(${JSON.stringify(
|
||||
isProApp() && { text: 'Data deployer', onClick: handleOpenDataDeployTab },
|
||||
$currentDatabase && [
|
||||
{ text: 'Generate deploy DB SQL', onClick: handleGenerateDeploySql },
|
||||
{ text: 'Shell: Deploy DB', onClick: handleGenerateDeployScript },
|
||||
hasPermission(`run-shell-script`) && { text: 'Shell: Deploy DB', onClick: handleGenerateDeployScript },
|
||||
],
|
||||
data.name != 'default' &&
|
||||
isProApp() &&
|
||||
|
||||
@@ -382,7 +382,8 @@
|
||||
$extensions,
|
||||
$currentDatabase,
|
||||
$apps,
|
||||
$openedSingleDatabaseConnections
|
||||
$openedSingleDatabaseConnections,
|
||||
data.databasePermissionRole,
|
||||
),
|
||||
],
|
||||
|
||||
|
||||
@@ -46,7 +46,8 @@
|
||||
$extensions,
|
||||
$currentDatabase,
|
||||
$apps,
|
||||
$openedSingleDatabaseConnections
|
||||
$openedSingleDatabaseConnections,
|
||||
databasePermissionRole
|
||||
) {
|
||||
const apps = filterAppsForDatabase(connection, name, $apps);
|
||||
const handleNewQuery = () => {
|
||||
@@ -412,11 +413,12 @@ await dbgateApi.executeQuery(${JSON.stringify(
|
||||
driver?.databaseEngineTypes?.includes('sql') || driver?.databaseEngineTypes?.includes('document');
|
||||
|
||||
return [
|
||||
hasPermission(`dbops/query`) && {
|
||||
onClick: handleNewQuery,
|
||||
text: _t('database.newQuery', { defaultMessage: 'New query' }),
|
||||
isNewQuery: true,
|
||||
},
|
||||
hasPermission(`dbops/query`) &&
|
||||
isAllowedDatabaseRunScript(databasePermissionRole) && {
|
||||
onClick: handleNewQuery,
|
||||
text: _t('database.newQuery', { defaultMessage: 'New query' }),
|
||||
isNewQuery: true,
|
||||
},
|
||||
hasPermission(`dbops/model/edit`) &&
|
||||
!connection.isReadOnly &&
|
||||
driver?.databaseEngineTypes?.includes('sql') && {
|
||||
@@ -545,12 +547,13 @@ await dbgateApi.executeQuery(${JSON.stringify(
|
||||
{ divider: true },
|
||||
|
||||
driver?.databaseEngineTypes?.includes('sql') &&
|
||||
hasPermission(`run-shell-script`) &&
|
||||
hasPermission(`dbops/dropdb`) && {
|
||||
onClick: handleGenerateDropAllObjectsScript,
|
||||
text: _t('database.shellDropAllObjects', { defaultMessage: 'Shell: Drop all objects' }),
|
||||
},
|
||||
|
||||
{
|
||||
hasPermission(`run-shell-script`) && {
|
||||
onClick: handleGenerateRunScript,
|
||||
text: _t('database.shellRunScript', { defaultMessage: 'Shell: Run script' }),
|
||||
},
|
||||
@@ -625,7 +628,7 @@ await dbgateApi.executeQuery(${JSON.stringify(
|
||||
import ConfirmModal from '../modals/ConfirmModal.svelte';
|
||||
import { closeMultipleTabs } from '../tabpanel/TabsPanel.svelte';
|
||||
import NewCollectionModal from '../modals/NewCollectionModal.svelte';
|
||||
import hasPermission from '../utility/hasPermission';
|
||||
import hasPermission, { isAllowedDatabaseRunScript } from '../utility/hasPermission';
|
||||
import { openImportExportTab } from '../utility/importExportTools';
|
||||
import newTable from '../tableeditor/newTable';
|
||||
import { loadSchemaList, switchCurrentDatabase } from '../utility/common';
|
||||
@@ -636,6 +639,7 @@ await dbgateApi.executeQuery(${JSON.stringify(
|
||||
import { getNumberIcon } from '../icons/FontIcon.svelte';
|
||||
import { getDatabaseClickActionSetting } from '../settings/settingsTools';
|
||||
import { _t } from '../translations';
|
||||
import { dataGridRowHeight } from '../datagrid/DataGridRowHeightMeter.svelte';
|
||||
|
||||
export let data;
|
||||
export let passProps;
|
||||
@@ -647,7 +651,8 @@ await dbgateApi.executeQuery(${JSON.stringify(
|
||||
$extensions,
|
||||
$currentDatabase,
|
||||
$apps,
|
||||
$openedSingleDatabaseConnections
|
||||
$openedSingleDatabaseConnections,
|
||||
data.databasePermissionRole
|
||||
);
|
||||
}
|
||||
|
||||
@@ -697,6 +702,9 @@ await dbgateApi.executeQuery(${JSON.stringify(
|
||||
).length
|
||||
)
|
||||
: ''}
|
||||
statusIconBefore={data.databasePermissionRole == 'read_content' || data.databasePermissionRole == 'view'
|
||||
? 'icon lock'
|
||||
: null}
|
||||
menu={createMenu}
|
||||
showPinnedInsteadOfUnpin={passProps?.showPinnedInsteadOfUnpin}
|
||||
onPin={isPinned ? null : () => pinnedDatabases.update(list => [...list, data])}
|
||||
|
||||
@@ -703,15 +703,29 @@
|
||||
}
|
||||
|
||||
function createMenus(objectTypeField, driver, data): ReturnType<typeof createMenusCore> {
|
||||
return createMenusCore(objectTypeField, driver, data).filter(x => {
|
||||
if (x.scriptTemplate) {
|
||||
return hasPermission(`dbops/sql-template/${x.scriptTemplate}`);
|
||||
const coreMenus = createMenusCore(objectTypeField, driver, data);
|
||||
|
||||
const filteredSumenus = coreMenus.map(item => {
|
||||
if (!item.submenu) {
|
||||
return item;
|
||||
}
|
||||
if (x.sqlGeneratorProps) {
|
||||
return hasPermission(`dbops/sql-generator`);
|
||||
}
|
||||
return true;
|
||||
return {
|
||||
...item,
|
||||
submenu: item.submenu.filter(x => {
|
||||
if (x.scriptTemplate) {
|
||||
return hasPermission(`dbops/sql-template/${x.scriptTemplate}`);
|
||||
}
|
||||
if (x.sqlGeneratorProps) {
|
||||
return hasPermission(`dbops/sql-generator`);
|
||||
}
|
||||
return true;
|
||||
}),
|
||||
};
|
||||
});
|
||||
|
||||
const filteredNoEmptySubmenus = filteredSumenus.filter(x => !x.submenu || x.submenu.length > 0);
|
||||
|
||||
return filteredNoEmptySubmenus;
|
||||
}
|
||||
|
||||
function getObjectTitle(connection, schemaName, pureName) {
|
||||
@@ -1062,6 +1076,7 @@
|
||||
: null}
|
||||
extInfo={getExtInfo(data)}
|
||||
isChoosed={matchDatabaseObjectAppObject($selectedDatabaseObjectAppObject, data)}
|
||||
statusIconBefore={data.tablePermissionRole == 'read' ? 'icon lock' : null}
|
||||
on:click={() => handleObjectClick(data, 'leftClick')}
|
||||
on:middleclick={() => handleObjectClick(data, 'middleClick')}
|
||||
on:dblclick={() => handleObjectClick(data, 'dblClick')}
|
||||
|
||||
@@ -322,6 +322,7 @@ registerCommand({
|
||||
toolbar: true,
|
||||
toolbarName: 'New table',
|
||||
testEnabled: () => {
|
||||
if (!hasPermission('dbops/model/edit')) return false;
|
||||
const driver = findEngineDriver(get(currentDatabase)?.connection, getExtensions());
|
||||
return !!get(currentDatabase) && driver?.databaseEngineTypes?.includes('sql');
|
||||
},
|
||||
@@ -671,7 +672,7 @@ registerCommand({
|
||||
name: 'Export database',
|
||||
toolbar: true,
|
||||
icon: 'icon export',
|
||||
testEnabled: () => getCurrentDatabase() != null,
|
||||
testEnabled: () => getCurrentDatabase() != null && hasPermission(`dbops/export`),
|
||||
onClick: () => {
|
||||
openImportExportTab({
|
||||
targetStorageType: getDefaultFileFormat(getExtensions()).storageType,
|
||||
@@ -691,7 +692,8 @@ if (isProApp()) {
|
||||
icon: 'icon compare',
|
||||
testEnabled: () =>
|
||||
getCurrentDatabase() != null &&
|
||||
findEngineDriver(getCurrentDatabase()?.connection, getExtensions())?.databaseEngineTypes?.includes('sql'),
|
||||
findEngineDriver(getCurrentDatabase()?.connection, getExtensions())?.databaseEngineTypes?.includes('sql')
|
||||
&& hasPermission(`dbops/export`),
|
||||
onClick: () => {
|
||||
openNewTab(
|
||||
{
|
||||
|
||||
@@ -77,7 +77,10 @@
|
||||
{ showHintColumns: getBoolSettingsValue('dataGrid.showHintColumns', true) },
|
||||
$serverVersion,
|
||||
table => getDictionaryDescription(table, conid, database, $apps, $connections),
|
||||
forceReadOnly || $connection?.isReadOnly,
|
||||
forceReadOnly ||
|
||||
$connection?.isReadOnly ||
|
||||
extendedDbInfo?.tables?.find(x => x.pureName == pureName && x.schemaName == schemaName)
|
||||
?.tablePermissionRole == 'read',
|
||||
isRawMode,
|
||||
$settingsValue
|
||||
)
|
||||
|
||||
@@ -74,6 +74,8 @@
|
||||
'icon arrow-link': 'mdi mdi-arrow-top-right-thick',
|
||||
'icon reset': 'mdi mdi-cancel',
|
||||
'icon send': 'mdi mdi-send',
|
||||
'icon regex': 'mdi mdi-regex',
|
||||
'icon list': 'mdi mdi-format-list-bulleted-triangle',
|
||||
|
||||
'icon window-restore': 'mdi mdi-window-restore',
|
||||
'icon window-maximize': 'mdi mdi-window-maximize',
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
import runCommand from '../commands/runCommand';
|
||||
import newQuery from '../query/newQuery';
|
||||
import { commandsCustomized, selectedWidget } from '../stores';
|
||||
import hasPermission from '../utility/hasPermission';
|
||||
import { isProApp } from '../utility/proTools';
|
||||
import ModalBase from './ModalBase.svelte';
|
||||
import { closeCurrentModal } from './modalTools';
|
||||
@@ -19,6 +20,7 @@
|
||||
newQuery({ multiTabIndex });
|
||||
},
|
||||
testid: 'NewObjectModal_query',
|
||||
testEnabled: () => hasPermission('dbops/query'),
|
||||
},
|
||||
{
|
||||
icon: 'icon connection',
|
||||
@@ -114,7 +116,7 @@
|
||||
isProFeature: true,
|
||||
disabledMessage: 'Database chat is not available for current database',
|
||||
testid: 'NewObjectModal_databaseChat',
|
||||
}
|
||||
},
|
||||
];
|
||||
</script>
|
||||
|
||||
@@ -122,7 +124,11 @@
|
||||
<div class="create-header">Create new</div>
|
||||
<div class="wrapper">
|
||||
{#each NEW_ITEMS as item}
|
||||
{@const enabled = item.command ? $commandsCustomized[item.command]?.enabled : true}
|
||||
{@const enabled = item.command
|
||||
? $commandsCustomized[item.command]?.enabled
|
||||
: item.testEnabled
|
||||
? item.testEnabled()
|
||||
: true}
|
||||
<NewObjectButton
|
||||
icon={item.icon}
|
||||
title={item.title}
|
||||
|
||||
@@ -40,7 +40,7 @@
|
||||
execute: true,
|
||||
toggleComment: true,
|
||||
findReplace: true,
|
||||
executeAdditionalCondition: () => getCurrentEditor()?.hasConnection(),
|
||||
executeAdditionalCondition: () => getCurrentEditor()?.hasConnection() && hasPermission('dbops/query'),
|
||||
copyPaste: true,
|
||||
});
|
||||
registerCommand({
|
||||
|
||||
@@ -80,7 +80,7 @@
|
||||
import invalidateCommands from '../commands/invalidateCommands';
|
||||
import { showModal } from '../modals/modalTools';
|
||||
import ErrorMessageModal from '../modals/ErrorMessageModal.svelte';
|
||||
import { useConnectionInfo, useDatabaseInfo } from '../utility/metadataLoaders';
|
||||
import { getTableInfo, useConnectionInfo, useDatabaseInfo } from '../utility/metadataLoaders';
|
||||
import { scriptToSql } from 'dbgate-sqltree';
|
||||
import { extensions, lastUsedDefaultActions } from '../stores';
|
||||
import ConfirmSqlModal from '../modals/ConfirmSqlModal.svelte';
|
||||
@@ -156,30 +156,47 @@
|
||||
}
|
||||
}
|
||||
|
||||
export function save() {
|
||||
export async function save() {
|
||||
const driver = findEngineDriver($connection, $extensions);
|
||||
const tablePermissionRole = (await getTableInfo({ conid, database, schemaName, pureName }))?.tablePermissionRole;
|
||||
|
||||
const script = driver.createSaveChangeSetScript($changeSetStore?.value, $dbinfo, () =>
|
||||
changeSetToSql($changeSetStore?.value, $dbinfo, driver.dialect)
|
||||
);
|
||||
|
||||
const deleteCascades = getDeleteCascades($changeSetStore?.value, $dbinfo);
|
||||
const sql = scriptToSql(driver, script);
|
||||
const deleteCascadesScripts = _.map(deleteCascades, ({ title, commands }) => ({
|
||||
title,
|
||||
script: scriptToSql(driver, commands),
|
||||
}));
|
||||
// console.log('deleteCascadesScripts', deleteCascadesScripts);
|
||||
if (getBoolSettingsValue('skipConfirm.tableDataSave', false) && !deleteCascadesScripts?.length) {
|
||||
handleConfirmSql(sql);
|
||||
} else {
|
||||
showModal(ConfirmSqlModal, {
|
||||
sql,
|
||||
onConfirm: confirmedSql => handleConfirmSql(confirmedSql),
|
||||
engine: driver.engine,
|
||||
deleteCascadesScripts,
|
||||
skipConfirmSettingKey: deleteCascadesScripts?.length ? null : 'skipConfirm.tableDataSave',
|
||||
if (tablePermissionRole == 'create_update_delete' || tablePermissionRole == 'update_only') {
|
||||
const resp = await apiCall('database-connections/save-table-data', {
|
||||
conid,
|
||||
database,
|
||||
changeSet: $changeSetStore?.value,
|
||||
});
|
||||
const { errorMessage } = resp || {};
|
||||
if (errorMessage) {
|
||||
showModal(ErrorMessageModal, { title: 'Error when saving', message: errorMessage });
|
||||
} else {
|
||||
dispatchChangeSet({ type: 'reset', value: createChangeSet() });
|
||||
cache.update(reloadDataCacheFunc);
|
||||
showSnackbarSuccess('Saved to database');
|
||||
}
|
||||
} else {
|
||||
const script = driver.createSaveChangeSetScript($changeSetStore?.value, $dbinfo, () =>
|
||||
changeSetToSql($changeSetStore?.value, $dbinfo, driver.dialect)
|
||||
);
|
||||
|
||||
const deleteCascades = getDeleteCascades($changeSetStore?.value, $dbinfo);
|
||||
const sql = scriptToSql(driver, script);
|
||||
const deleteCascadesScripts = _.map(deleteCascades, ({ title, commands }) => ({
|
||||
title,
|
||||
script: scriptToSql(driver, commands),
|
||||
}));
|
||||
// console.log('deleteCascadesScripts', deleteCascadesScripts);
|
||||
if (getBoolSettingsValue('skipConfirm.tableDataSave', false) && !deleteCascadesScripts?.length) {
|
||||
handleConfirmSql(sql);
|
||||
} else {
|
||||
showModal(ConfirmSqlModal, {
|
||||
sql,
|
||||
onConfirm: confirmedSql => handleConfirmSql(confirmedSql),
|
||||
engine: driver.engine,
|
||||
deleteCascadesScripts,
|
||||
skipConfirmSettingKey: deleteCascadesScripts?.length ? null : 'skipConfirm.tableDataSave',
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -22,3 +22,8 @@ export function subscribePermissionCompiler() {
|
||||
export function setConfigForPermissions(config) {
|
||||
compiled = compilePermissions(config?.permissions || []);
|
||||
}
|
||||
|
||||
export function isAllowedDatabaseRunScript(databasePermissionRole) {
|
||||
return !databasePermissionRole || databasePermissionRole == 'run_script';
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user