mirror of
https://github.com/DeNNiiInc/dbgate.git
synced 2026-04-18 02:06: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
|
SHELL_SCRIPTING=1
|
||||||
ALLOW_DBGATE_PRIVATE_CLOUD=1
|
ALLOW_DBGATE_PRIVATE_CLOUD=1
|
||||||
DEVWEB=1
|
DEVWEB=1
|
||||||
|
LOCAL_AUTH_PROXY=1
|
||||||
# LOCAL_AI_GATEWAY=true
|
# LOCAL_AI_GATEWAY=true
|
||||||
|
|
||||||
# REDIRECT_TO_DBGATE_CLOUD_LOGIN=1
|
# REDIRECT_TO_DBGATE_CLOUD_LOGIN=1
|
||||||
|
|||||||
@@ -36,12 +36,24 @@ class AuthProviderBase {
|
|||||||
return !!req?.user || !!req?.auth;
|
return !!req?.user || !!req?.auth;
|
||||||
}
|
}
|
||||||
|
|
||||||
getCurrentPermissions(req) {
|
async getCurrentPermissions(req) {
|
||||||
const login = this.getCurrentLogin(req);
|
const login = this.getCurrentLogin(req);
|
||||||
const permissions = process.env[`LOGIN_PERMISSIONS_${login}`];
|
const permissions = process.env[`LOGIN_PERMISSIONS_${login}`];
|
||||||
return permissions || process.env.PERMISSIONS;
|
return permissions || process.env.PERMISSIONS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async checkCurrentConnectionPermission(req, conid) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
async getCurrentDatabasePermissions(req) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
async getCurrentTablePermissions(req) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
getLoginPageConnections() {
|
getLoginPageConnections() {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -51,6 +51,7 @@ function authMiddleware(req, res, next) {
|
|||||||
'/auth/oauth-token',
|
'/auth/oauth-token',
|
||||||
'/auth/login',
|
'/auth/login',
|
||||||
'/auth/redirect',
|
'/auth/redirect',
|
||||||
|
'/redirect',
|
||||||
'/stream',
|
'/stream',
|
||||||
'/storage/get-connections-for-login-page',
|
'/storage/get-connections-for-login-page',
|
||||||
'/storage/set-admin-password',
|
'/storage/set-admin-password',
|
||||||
@@ -139,9 +140,9 @@ module.exports = {
|
|||||||
const accessToken = jwt.sign(
|
const accessToken = jwt.sign(
|
||||||
{
|
{
|
||||||
login: 'superadmin',
|
login: 'superadmin',
|
||||||
permissions: await storage.loadSuperadminPermissions(),
|
|
||||||
roleId: -3,
|
roleId: -3,
|
||||||
licenseUid,
|
licenseUid,
|
||||||
|
amoid: 'superadmin',
|
||||||
},
|
},
|
||||||
getTokenSecret(),
|
getTokenSecret(),
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ const os = require('os');
|
|||||||
const path = require('path');
|
const path = require('path');
|
||||||
const axios = require('axios');
|
const axios = require('axios');
|
||||||
const { datadir, getLogsFilePath } = require('../utility/directories');
|
const { datadir, getLogsFilePath } = require('../utility/directories');
|
||||||
const { hasPermission } = require('../utility/hasPermission');
|
const { hasPermission, loadPermissionsFromRequest } = require('../utility/hasPermission');
|
||||||
const socket = require('../utility/socket');
|
const socket = require('../utility/socket');
|
||||||
const _ = require('lodash');
|
const _ = require('lodash');
|
||||||
const AsyncLock = require('async-lock');
|
const AsyncLock = require('async-lock');
|
||||||
@@ -46,7 +46,7 @@ module.exports = {
|
|||||||
async get(_params, req) {
|
async get(_params, req) {
|
||||||
const authProvider = getAuthProviderFromReq(req);
|
const authProvider = getAuthProviderFromReq(req);
|
||||||
const login = authProvider.getCurrentLogin(req);
|
const login = authProvider.getCurrentLogin(req);
|
||||||
const permissions = authProvider.getCurrentPermissions(req);
|
const permissions = await authProvider.getCurrentPermissions(req);
|
||||||
const isUserLoggedIn = authProvider.isUserLoggedIn(req);
|
const isUserLoggedIn = authProvider.isUserLoggedIn(req);
|
||||||
|
|
||||||
const singleConid = authProvider.getSingleConnectionId(req);
|
const singleConid = authProvider.getSingleConnectionId(req);
|
||||||
@@ -280,7 +280,8 @@ module.exports = {
|
|||||||
|
|
||||||
updateSettings_meta: true,
|
updateSettings_meta: true,
|
||||||
async updateSettings(values, req) {
|
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;
|
cachedSettingsValue = null;
|
||||||
|
|
||||||
const res = await lock.acquire('settings', async () => {
|
const res = await lock.acquire('settings', async () => {
|
||||||
@@ -392,7 +393,8 @@ module.exports = {
|
|||||||
|
|
||||||
exportConnectionsAndSettings_meta: true,
|
exportConnectionsAndSettings_meta: true,
|
||||||
async exportConnectionsAndSettings(_params, req) {
|
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');
|
throw new Error('Permission denied: admin/config');
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -416,7 +418,8 @@ module.exports = {
|
|||||||
|
|
||||||
importConnectionsAndSettings_meta: true,
|
importConnectionsAndSettings_meta: true,
|
||||||
async importConnectionsAndSettings({ db }, req) {
|
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');
|
throw new Error('Permission denied: admin/config');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ const JsonLinesDatabase = require('../utility/JsonLinesDatabase');
|
|||||||
const processArgs = require('../utility/processArgs');
|
const processArgs = require('../utility/processArgs');
|
||||||
const { safeJsonParse, getLogger, extractErrorLogData } = require('dbgate-tools');
|
const { safeJsonParse, getLogger, extractErrorLogData } = require('dbgate-tools');
|
||||||
const platformInfo = require('../utility/platformInfo');
|
const platformInfo = require('../utility/platformInfo');
|
||||||
const { connectionHasPermission, testConnectionPermission } = require('../utility/hasPermission');
|
const { connectionHasPermission, testConnectionPermission, loadPermissionsFromRequest } = require('../utility/hasPermission');
|
||||||
const pipeForkLogs = require('../utility/pipeForkLogs');
|
const pipeForkLogs = require('../utility/pipeForkLogs');
|
||||||
const requireEngineDriver = require('../utility/requireEngineDriver');
|
const requireEngineDriver = require('../utility/requireEngineDriver');
|
||||||
const { getAuthProviderById } = require('../auth/authProvider');
|
const { getAuthProviderById } = require('../auth/authProvider');
|
||||||
@@ -227,6 +227,7 @@ module.exports = {
|
|||||||
list_meta: true,
|
list_meta: true,
|
||||||
async list(_params, req) {
|
async list(_params, req) {
|
||||||
const storage = require('./storage');
|
const storage = require('./storage');
|
||||||
|
const loadedPermissions = await loadPermissionsFromRequest(req);
|
||||||
|
|
||||||
const storageConnections = await storage.connections(req);
|
const storageConnections = await storage.connections(req);
|
||||||
if (storageConnections) {
|
if (storageConnections) {
|
||||||
@@ -234,9 +235,9 @@ module.exports = {
|
|||||||
}
|
}
|
||||||
if (portalConnections) {
|
if (portalConnections) {
|
||||||
if (platformInfo.allowShellConnection) return 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() {
|
async getUsedEngines() {
|
||||||
@@ -375,7 +376,7 @@ module.exports = {
|
|||||||
update_meta: true,
|
update_meta: true,
|
||||||
async update({ _id, values }, req) {
|
async update({ _id, values }, req) {
|
||||||
if (portalConnections) return;
|
if (portalConnections) return;
|
||||||
testConnectionPermission(_id, req);
|
await testConnectionPermission(_id, req);
|
||||||
const res = await this.datastore.patch(_id, values);
|
const res = await this.datastore.patch(_id, values);
|
||||||
socket.emitChanged('connection-list-changed');
|
socket.emitChanged('connection-list-changed');
|
||||||
return res;
|
return res;
|
||||||
@@ -392,7 +393,7 @@ module.exports = {
|
|||||||
updateDatabase_meta: true,
|
updateDatabase_meta: true,
|
||||||
async updateDatabase({ conid, database, values }, req) {
|
async updateDatabase({ conid, database, values }, req) {
|
||||||
if (portalConnections) return;
|
if (portalConnections) return;
|
||||||
testConnectionPermission(conid, req);
|
await testConnectionPermission(conid, req);
|
||||||
const conn = await this.datastore.get(conid);
|
const conn = await this.datastore.get(conid);
|
||||||
let databases = (conn && conn.databases) || [];
|
let databases = (conn && conn.databases) || [];
|
||||||
if (databases.find(x => x.name == database)) {
|
if (databases.find(x => x.name == database)) {
|
||||||
@@ -410,7 +411,7 @@ module.exports = {
|
|||||||
delete_meta: true,
|
delete_meta: true,
|
||||||
async delete(connection, req) {
|
async delete(connection, req) {
|
||||||
if (portalConnections) return;
|
if (portalConnections) return;
|
||||||
testConnectionPermission(connection, req);
|
await testConnectionPermission(connection, req);
|
||||||
const res = await this.datastore.remove(connection._id);
|
const res = await this.datastore.remove(connection._id);
|
||||||
socket.emitChanged('connection-list-changed');
|
socket.emitChanged('connection-list-changed');
|
||||||
return res;
|
return res;
|
||||||
@@ -452,7 +453,7 @@ module.exports = {
|
|||||||
_id: '__model',
|
_id: '__model',
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
testConnectionPermission(conid, req);
|
await testConnectionPermission(conid, req);
|
||||||
return this.getCore({ conid, mask: true });
|
return this.getCore({ conid, mask: true });
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ const generateDeploySql = require('../shell/generateDeploySql');
|
|||||||
const { createTwoFilesPatch } = require('diff');
|
const { createTwoFilesPatch } = require('diff');
|
||||||
const diff2htmlPage = require('../utility/diff2htmlPage');
|
const diff2htmlPage = require('../utility/diff2htmlPage');
|
||||||
const processArgs = require('../utility/processArgs');
|
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 { MissingCredentialsError } = require('../utility/exceptions');
|
||||||
const pipeForkLogs = require('../utility/pipeForkLogs');
|
const pipeForkLogs = require('../utility/pipeForkLogs');
|
||||||
const crypto = require('crypto');
|
const crypto = require('crypto');
|
||||||
@@ -235,7 +235,7 @@ module.exports = {
|
|||||||
|
|
||||||
queryData_meta: true,
|
queryData_meta: true,
|
||||||
async queryData({ conid, database, sql }, req) {
|
async queryData({ conid, database, sql }, req) {
|
||||||
testConnectionPermission(conid, req);
|
await testConnectionPermission(conid, req);
|
||||||
logger.info({ conid, database, sql }, 'DBGM-00007 Processing query');
|
logger.info({ conid, database, sql }, 'DBGM-00007 Processing query');
|
||||||
const opened = await this.ensureOpened(conid, database);
|
const opened = await this.ensureOpened(conid, database);
|
||||||
// if (opened && opened.status && opened.status.name == 'error') {
|
// if (opened && opened.status && opened.status.name == 'error') {
|
||||||
@@ -247,7 +247,7 @@ module.exports = {
|
|||||||
|
|
||||||
sqlSelect_meta: true,
|
sqlSelect_meta: true,
|
||||||
async sqlSelect({ conid, database, select, auditLogSessionGroup }, req) {
|
async sqlSelect({ conid, database, select, auditLogSessionGroup }, req) {
|
||||||
testConnectionPermission(conid, req);
|
await testConnectionPermission(conid, req);
|
||||||
const opened = await this.ensureOpened(conid, database);
|
const opened = await this.ensureOpened(conid, database);
|
||||||
const res = await this.sendRequest(
|
const res = await this.sendRequest(
|
||||||
opened,
|
opened,
|
||||||
@@ -267,8 +267,7 @@ module.exports = {
|
|||||||
schemaName: select?.from?.name?.schemaName,
|
schemaName: select?.from?.name?.schemaName,
|
||||||
pureName: select?.from?.name?.pureName,
|
pureName: select?.from?.name?.pureName,
|
||||||
sumint1: response?.rows?.length,
|
sumint1: response?.rows?.length,
|
||||||
sessionParam: `${conid}::${database}::${select?.from?.name?.schemaName || '0'}::${
|
sessionParam: `${conid}::${database}::${select?.from?.name?.schemaName || '0'}::${select?.from?.name?.pureName
|
||||||
select?.from?.name?.pureName
|
|
||||||
}`,
|
}`,
|
||||||
sessionGroup: auditLogSessionGroup,
|
sessionGroup: auditLogSessionGroup,
|
||||||
message: `Loaded table data from ${select?.from?.name?.pureName}`,
|
message: `Loaded table data from ${select?.from?.name?.pureName}`,
|
||||||
@@ -282,7 +281,9 @@ module.exports = {
|
|||||||
|
|
||||||
runScript_meta: true,
|
runScript_meta: true,
|
||||||
async runScript({ conid, database, sql, useTransaction, logMessage }, req) {
|
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');
|
logger.info({ conid, database, sql }, 'DBGM-00008 Processing script');
|
||||||
const opened = await this.ensureOpened(conid, database);
|
const opened = await this.ensureOpened(conid, database);
|
||||||
sendToAuditLog(req, {
|
sendToAuditLog(req, {
|
||||||
@@ -303,7 +304,7 @@ module.exports = {
|
|||||||
|
|
||||||
runOperation_meta: true,
|
runOperation_meta: true,
|
||||||
async runOperation({ conid, database, operation, useTransaction }, req) {
|
async runOperation({ conid, database, operation, useTransaction }, req) {
|
||||||
testConnectionPermission(conid, req);
|
await testConnectionPermission(conid, req);
|
||||||
logger.info({ conid, database, operation }, 'DBGM-00009 Processing operation');
|
logger.info({ conid, database, operation }, 'DBGM-00009 Processing operation');
|
||||||
|
|
||||||
sendToAuditLog(req, {
|
sendToAuditLog(req, {
|
||||||
@@ -325,7 +326,7 @@ module.exports = {
|
|||||||
|
|
||||||
collectionData_meta: true,
|
collectionData_meta: true,
|
||||||
async collectionData({ conid, database, options, auditLogSessionGroup }, req) {
|
async collectionData({ conid, database, options, auditLogSessionGroup }, req) {
|
||||||
testConnectionPermission(conid, req);
|
await testConnectionPermission(conid, req);
|
||||||
const opened = await this.ensureOpened(conid, database);
|
const opened = await this.ensureOpened(conid, database);
|
||||||
const res = await this.sendRequest(
|
const res = await this.sendRequest(
|
||||||
opened,
|
opened,
|
||||||
@@ -356,7 +357,7 @@ module.exports = {
|
|||||||
},
|
},
|
||||||
|
|
||||||
async loadDataCore(msgtype, { conid, database, ...args }, req) {
|
async loadDataCore(msgtype, { conid, database, ...args }, req) {
|
||||||
testConnectionPermission(conid, req);
|
await testConnectionPermission(conid, req);
|
||||||
const opened = await this.ensureOpened(conid, database);
|
const opened = await this.ensureOpened(conid, database);
|
||||||
const res = await this.sendRequest(opened, { msgtype, ...args });
|
const res = await this.sendRequest(opened, { msgtype, ...args });
|
||||||
if (res.errorMessage) {
|
if (res.errorMessage) {
|
||||||
@@ -371,7 +372,7 @@ module.exports = {
|
|||||||
|
|
||||||
schemaList_meta: true,
|
schemaList_meta: true,
|
||||||
async schemaList({ conid, database }, req) {
|
async schemaList({ conid, database }, req) {
|
||||||
testConnectionPermission(conid, req);
|
await testConnectionPermission(conid, req);
|
||||||
return this.loadDataCore('schemaList', { conid, database });
|
return this.loadDataCore('schemaList', { conid, database });
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -383,43 +384,43 @@ module.exports = {
|
|||||||
|
|
||||||
loadKeys_meta: true,
|
loadKeys_meta: true,
|
||||||
async loadKeys({ conid, database, root, filter, limit }, req) {
|
async loadKeys({ conid, database, root, filter, limit }, req) {
|
||||||
testConnectionPermission(conid, req);
|
await testConnectionPermission(conid, req);
|
||||||
return this.loadDataCore('loadKeys', { conid, database, root, filter, limit });
|
return this.loadDataCore('loadKeys', { conid, database, root, filter, limit });
|
||||||
},
|
},
|
||||||
|
|
||||||
scanKeys_meta: true,
|
scanKeys_meta: true,
|
||||||
async scanKeys({ conid, database, root, pattern, cursor, count }, req) {
|
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 });
|
return this.loadDataCore('scanKeys', { conid, database, root, pattern, cursor, count });
|
||||||
},
|
},
|
||||||
|
|
||||||
exportKeys_meta: true,
|
exportKeys_meta: true,
|
||||||
async exportKeys({ conid, database, options }, req) {
|
async exportKeys({ conid, database, options }, req) {
|
||||||
testConnectionPermission(conid, req);
|
await testConnectionPermission(conid, req);
|
||||||
return this.loadDataCore('exportKeys', { conid, database, options });
|
return this.loadDataCore('exportKeys', { conid, database, options });
|
||||||
},
|
},
|
||||||
|
|
||||||
loadKeyInfo_meta: true,
|
loadKeyInfo_meta: true,
|
||||||
async loadKeyInfo({ conid, database, key }, req) {
|
async loadKeyInfo({ conid, database, key }, req) {
|
||||||
testConnectionPermission(conid, req);
|
await testConnectionPermission(conid, req);
|
||||||
return this.loadDataCore('loadKeyInfo', { conid, database, key });
|
return this.loadDataCore('loadKeyInfo', { conid, database, key });
|
||||||
},
|
},
|
||||||
|
|
||||||
loadKeyTableRange_meta: true,
|
loadKeyTableRange_meta: true,
|
||||||
async loadKeyTableRange({ conid, database, key, cursor, count }, req) {
|
async loadKeyTableRange({ conid, database, key, cursor, count }, req) {
|
||||||
testConnectionPermission(conid, req);
|
await testConnectionPermission(conid, req);
|
||||||
return this.loadDataCore('loadKeyTableRange', { conid, database, key, cursor, count });
|
return this.loadDataCore('loadKeyTableRange', { conid, database, key, cursor, count });
|
||||||
},
|
},
|
||||||
|
|
||||||
loadFieldValues_meta: true,
|
loadFieldValues_meta: true,
|
||||||
async loadFieldValues({ conid, database, schemaName, pureName, field, search, dataType }, req) {
|
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 });
|
return this.loadDataCore('loadFieldValues', { conid, database, schemaName, pureName, field, search, dataType });
|
||||||
},
|
},
|
||||||
|
|
||||||
callMethod_meta: true,
|
callMethod_meta: true,
|
||||||
async callMethod({ conid, database, method, args }, req) {
|
async callMethod({ conid, database, method, args }, req) {
|
||||||
testConnectionPermission(conid, req);
|
await testConnectionPermission(conid, req);
|
||||||
return this.loadDataCore('callMethod', { conid, database, method, args });
|
return this.loadDataCore('callMethod', { conid, database, method, args });
|
||||||
|
|
||||||
// const opened = await this.ensureOpened(conid, database);
|
// const opened = await this.ensureOpened(conid, database);
|
||||||
@@ -432,7 +433,8 @@ module.exports = {
|
|||||||
|
|
||||||
updateCollection_meta: true,
|
updateCollection_meta: true,
|
||||||
async updateCollection({ conid, database, changeSet }, req) {
|
async updateCollection({ conid, database, changeSet }, req) {
|
||||||
testConnectionPermission(conid, req);
|
await testConnectionPermission(conid, req);
|
||||||
|
|
||||||
const opened = await this.ensureOpened(conid, database);
|
const opened = await this.ensureOpened(conid, database);
|
||||||
const res = await this.sendRequest(opened, { msgtype: 'updateCollection', changeSet });
|
const res = await this.sendRequest(opened, { msgtype: 'updateCollection', changeSet });
|
||||||
if (res.errorMessage) {
|
if (res.errorMessage) {
|
||||||
@@ -443,6 +445,36 @@ module.exports = {
|
|||||||
return res.result || null;
|
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,
|
status_meta: true,
|
||||||
async status({ conid, database }, req) {
|
async status({ conid, database }, req) {
|
||||||
if (!conid) {
|
if (!conid) {
|
||||||
@@ -451,7 +483,7 @@ module.exports = {
|
|||||||
message: 'No connection',
|
message: 'No connection',
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
testConnectionPermission(conid, req);
|
await testConnectionPermission(conid, req);
|
||||||
const existing = this.opened.find(x => x.conid == conid && x.database == database);
|
const existing = this.opened.find(x => x.conid == conid && x.database == database);
|
||||||
if (existing) {
|
if (existing) {
|
||||||
return {
|
return {
|
||||||
@@ -474,7 +506,7 @@ module.exports = {
|
|||||||
|
|
||||||
ping_meta: true,
|
ping_meta: true,
|
||||||
async ping({ conid, database }, req) {
|
async ping({ conid, database }, req) {
|
||||||
testConnectionPermission(conid, req);
|
await testConnectionPermission(conid, req);
|
||||||
let existing = this.opened.find(x => x.conid == conid && x.database == database);
|
let existing = this.opened.find(x => x.conid == conid && x.database == database);
|
||||||
|
|
||||||
if (existing) {
|
if (existing) {
|
||||||
@@ -502,7 +534,7 @@ module.exports = {
|
|||||||
|
|
||||||
refresh_meta: true,
|
refresh_meta: true,
|
||||||
async refresh({ conid, database, keepOpen }, req) {
|
async refresh({ conid, database, keepOpen }, req) {
|
||||||
testConnectionPermission(conid, req);
|
await testConnectionPermission(conid, req);
|
||||||
if (!keepOpen) this.close(conid, database);
|
if (!keepOpen) this.close(conid, database);
|
||||||
|
|
||||||
await this.ensureOpened(conid, database);
|
await this.ensureOpened(conid, database);
|
||||||
@@ -516,7 +548,7 @@ module.exports = {
|
|||||||
return { status: 'ok' };
|
return { status: 'ok' };
|
||||||
}
|
}
|
||||||
|
|
||||||
testConnectionPermission(conid, req);
|
await testConnectionPermission(conid, req);
|
||||||
const conn = await this.ensureOpened(conid, database);
|
const conn = await this.ensureOpened(conid, database);
|
||||||
conn.subprocess.send({ msgtype: 'syncModel', isFullRefresh });
|
conn.subprocess.send({ msgtype: 'syncModel', isFullRefresh });
|
||||||
return { status: 'ok' };
|
return { status: 'ok' };
|
||||||
@@ -553,7 +585,7 @@ module.exports = {
|
|||||||
|
|
||||||
disconnect_meta: true,
|
disconnect_meta: true,
|
||||||
async disconnect({ conid, database }, req) {
|
async disconnect({ conid, database }, req) {
|
||||||
testConnectionPermission(conid, req);
|
await testConnectionPermission(conid, req);
|
||||||
await this.close(conid, database, true);
|
await this.close(conid, database, true);
|
||||||
return { status: 'ok' };
|
return { status: 'ok' };
|
||||||
},
|
},
|
||||||
@@ -563,8 +595,9 @@ module.exports = {
|
|||||||
if (!conid || !database) {
|
if (!conid || !database) {
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
const loadedPermissions = await loadPermissionsFromRequest(req);
|
||||||
|
|
||||||
testConnectionPermission(conid, req);
|
await testConnectionPermission(conid, req, loadedPermissions);
|
||||||
if (conid == '__model') {
|
if (conid == '__model') {
|
||||||
const model = await importDbModel(database);
|
const model = await importDbModel(database);
|
||||||
const trans = await loadModelTransform(modelTransFile);
|
const trans = await loadModelTransform(modelTransFile);
|
||||||
@@ -586,6 +619,38 @@ module.exports = {
|
|||||||
message: `Loaded database structure for ${database}`,
|
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;
|
return opened.structure;
|
||||||
// const existing = this.opened.find((x) => x.conid == conid && x.database == database);
|
// const existing = this.opened.find((x) => x.conid == conid && x.database == database);
|
||||||
// if (existing) return existing.status;
|
// if (existing) return existing.status;
|
||||||
@@ -600,7 +665,7 @@ module.exports = {
|
|||||||
if (!conid) {
|
if (!conid) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
testConnectionPermission(conid, req);
|
await testConnectionPermission(conid, req);
|
||||||
if (!conid) return null;
|
if (!conid) return null;
|
||||||
const opened = await this.ensureOpened(conid, database);
|
const opened = await this.ensureOpened(conid, database);
|
||||||
return opened.serverVersion || null;
|
return opened.serverVersion || null;
|
||||||
@@ -608,7 +673,7 @@ module.exports = {
|
|||||||
|
|
||||||
sqlPreview_meta: true,
|
sqlPreview_meta: true,
|
||||||
async sqlPreview({ conid, database, objects, options }, req) {
|
async sqlPreview({ conid, database, objects, options }, req) {
|
||||||
testConnectionPermission(conid, req);
|
await testConnectionPermission(conid, req);
|
||||||
// wait for structure
|
// wait for structure
|
||||||
await this.structure({ conid, database });
|
await this.structure({ conid, database });
|
||||||
|
|
||||||
@@ -619,7 +684,7 @@ module.exports = {
|
|||||||
|
|
||||||
exportModel_meta: true,
|
exportModel_meta: true,
|
||||||
async exportModel({ conid, database, outputFolder, schema }, req) {
|
async exportModel({ conid, database, outputFolder, schema }, req) {
|
||||||
testConnectionPermission(conid, req);
|
await testConnectionPermission(conid, req);
|
||||||
|
|
||||||
const realFolder = outputFolder.startsWith('archive:')
|
const realFolder = outputFolder.startsWith('archive:')
|
||||||
? resolveArchiveFolder(outputFolder.substring('archive:'.length))
|
? resolveArchiveFolder(outputFolder.substring('archive:'.length))
|
||||||
@@ -637,7 +702,7 @@ module.exports = {
|
|||||||
|
|
||||||
exportModelSql_meta: true,
|
exportModelSql_meta: true,
|
||||||
async exportModelSql({ conid, database, outputFolder, outputFile, schema }, req) {
|
async exportModelSql({ conid, database, outputFolder, outputFile, schema }, req) {
|
||||||
testConnectionPermission(conid, req);
|
await testConnectionPermission(conid, req);
|
||||||
|
|
||||||
const connection = await connections.getCore({ conid });
|
const connection = await connections.getCore({ conid });
|
||||||
const driver = requireEngineDriver(connection);
|
const driver = requireEngineDriver(connection);
|
||||||
@@ -651,7 +716,7 @@ module.exports = {
|
|||||||
|
|
||||||
generateDeploySql_meta: true,
|
generateDeploySql_meta: true,
|
||||||
async generateDeploySql({ conid, database, archiveFolder }, req) {
|
async generateDeploySql({ conid, database, archiveFolder }, req) {
|
||||||
testConnectionPermission(conid, req);
|
await testConnectionPermission(conid, req);
|
||||||
const opened = await this.ensureOpened(conid, database);
|
const opened = await this.ensureOpened(conid, database);
|
||||||
const res = await this.sendRequest(opened, {
|
const res = await this.sendRequest(opened, {
|
||||||
msgtype: 'generateDeploySql',
|
msgtype: 'generateDeploySql',
|
||||||
@@ -923,7 +988,7 @@ module.exports = {
|
|||||||
|
|
||||||
executeSessionQuery_meta: true,
|
executeSessionQuery_meta: true,
|
||||||
async executeSessionQuery({ sesid, conid, database, sql }, req) {
|
async executeSessionQuery({ sesid, conid, database, sql }, req) {
|
||||||
testConnectionPermission(conid, req);
|
await testConnectionPermission(conid, req);
|
||||||
logger.info({ sesid, sql }, 'DBGM-00010 Processing query');
|
logger.info({ sesid, sql }, 'DBGM-00010 Processing query');
|
||||||
sessions.dispatchMessage(sesid, 'Query execution started');
|
sessions.dispatchMessage(sesid, 'Query execution started');
|
||||||
|
|
||||||
@@ -935,7 +1000,7 @@ module.exports = {
|
|||||||
|
|
||||||
evalJsonScript_meta: true,
|
evalJsonScript_meta: true,
|
||||||
async evalJsonScript({ conid, database, script, runid }, req) {
|
async evalJsonScript({ conid, database, script, runid }, req) {
|
||||||
testConnectionPermission(conid, req);
|
await testConnectionPermission(conid, req);
|
||||||
const opened = await this.ensureOpened(conid, database);
|
const opened = await this.ensureOpened(conid, database);
|
||||||
|
|
||||||
opened.subprocess.send({ msgtype: 'evalJsonScript', script, runid });
|
opened.subprocess.send({ msgtype: 'evalJsonScript', script, runid });
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ const path = require('path');
|
|||||||
const crypto = require('crypto');
|
const crypto = require('crypto');
|
||||||
const { filesdir, archivedir, resolveArchiveFolder, uploadsdir, appdir, jsldir } = require('../utility/directories');
|
const { filesdir, archivedir, resolveArchiveFolder, uploadsdir, appdir, jsldir } = require('../utility/directories');
|
||||||
const getChartExport = require('../utility/getChartExport');
|
const getChartExport = require('../utility/getChartExport');
|
||||||
const { hasPermission } = require('../utility/hasPermission');
|
const { hasPermission, loadPermissionsFromRequest } = require('../utility/hasPermission');
|
||||||
const socket = require('../utility/socket');
|
const socket = require('../utility/socket');
|
||||||
const scheduler = require('./scheduler');
|
const scheduler = require('./scheduler');
|
||||||
const getDiagramExport = require('../utility/getDiagramExport');
|
const getDiagramExport = require('../utility/getDiagramExport');
|
||||||
@@ -31,7 +31,8 @@ function deserialize(format, text) {
|
|||||||
module.exports = {
|
module.exports = {
|
||||||
list_meta: true,
|
list_meta: true,
|
||||||
async list({ folder }, req) {
|
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);
|
const dir = path.join(filesdir(), folder);
|
||||||
if (!(await fs.exists(dir))) return [];
|
if (!(await fs.exists(dir))) return [];
|
||||||
const files = (await fs.readdir(dir)).map(file => ({ folder, file }));
|
const files = (await fs.readdir(dir)).map(file => ({ folder, file }));
|
||||||
@@ -40,10 +41,11 @@ module.exports = {
|
|||||||
|
|
||||||
listAll_meta: true,
|
listAll_meta: true,
|
||||||
async listAll(_params, req) {
|
async listAll(_params, req) {
|
||||||
|
const loadedPermissions = await loadPermissionsFromRequest(req);
|
||||||
const folders = await fs.readdir(filesdir());
|
const folders = await fs.readdir(filesdir());
|
||||||
const res = [];
|
const res = [];
|
||||||
for (const folder of folders) {
|
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 dir = path.join(filesdir(), folder);
|
||||||
const files = (await fs.readdir(dir)).map(file => ({ folder, file }));
|
const files = (await fs.readdir(dir)).map(file => ({ folder, file }));
|
||||||
res.push(...files);
|
res.push(...files);
|
||||||
@@ -53,7 +55,8 @@ module.exports = {
|
|||||||
|
|
||||||
delete_meta: true,
|
delete_meta: true,
|
||||||
async delete({ folder, file }, req) {
|
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)) {
|
if (!checkSecureFilePathsWithoutDirectory(folder, file)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -65,7 +68,8 @@ module.exports = {
|
|||||||
|
|
||||||
rename_meta: true,
|
rename_meta: true,
|
||||||
async rename({ folder, file, newFile }, req) {
|
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)) {
|
if (!checkSecureFilePathsWithoutDirectory(folder, file, newFile)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -86,10 +90,11 @@ module.exports = {
|
|||||||
|
|
||||||
copy_meta: true,
|
copy_meta: true,
|
||||||
async copy({ folder, file, newFile }, req) {
|
async copy({ folder, file, newFile }, req) {
|
||||||
|
const loadedPermissions = await loadPermissionsFromRequest(req);
|
||||||
if (!checkSecureFilePathsWithoutDirectory(folder, file, newFile)) {
|
if (!checkSecureFilePathsWithoutDirectory(folder, file, newFile)) {
|
||||||
return false;
|
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));
|
await fs.copyFile(path.join(filesdir(), folder, file), path.join(filesdir(), folder, newFile));
|
||||||
socket.emitChanged(`files-changed`, { folder });
|
socket.emitChanged(`files-changed`, { folder });
|
||||||
socket.emitChanged(`all-files-changed`);
|
socket.emitChanged(`all-files-changed`);
|
||||||
@@ -113,7 +118,8 @@ module.exports = {
|
|||||||
});
|
});
|
||||||
return deserialize(format, text);
|
return deserialize(format, text);
|
||||||
} else {
|
} 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' });
|
const text = await fs.readFile(path.join(filesdir(), folder, file), { encoding: 'utf-8' });
|
||||||
return deserialize(format, text);
|
return deserialize(format, text);
|
||||||
}
|
}
|
||||||
@@ -131,18 +137,19 @@ module.exports = {
|
|||||||
|
|
||||||
save_meta: true,
|
save_meta: true,
|
||||||
async save({ folder, file, data, format }, req) {
|
async save({ folder, file, data, format }, req) {
|
||||||
|
const loadedPermissions = await loadPermissionsFromRequest(req);
|
||||||
if (!checkSecureFilePathsWithoutDirectory(folder, file)) {
|
if (!checkSecureFilePathsWithoutDirectory(folder, file)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (folder.startsWith('archive:')) {
|
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));
|
const dir = resolveArchiveFolder(folder.substring('archive:'.length));
|
||||||
await fs.writeFile(path.join(dir, file), serialize(format, data));
|
await fs.writeFile(path.join(dir, file), serialize(format, data));
|
||||||
socket.emitChanged(`archive-files-changed`, { folder: folder.substring('archive:'.length) });
|
socket.emitChanged(`archive-files-changed`, { folder: folder.substring('archive:'.length) });
|
||||||
return true;
|
return true;
|
||||||
} else if (folder.startsWith('app:')) {
|
} 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);
|
const app = folder.substring('app:'.length);
|
||||||
await fs.writeFile(path.join(appdir(), app, file), serialize(format, data));
|
await fs.writeFile(path.join(appdir(), app, file), serialize(format, data));
|
||||||
socket.emitChanged(`app-files-changed`, { app });
|
socket.emitChanged(`app-files-changed`, { app });
|
||||||
@@ -150,7 +157,7 @@ module.exports = {
|
|||||||
apps.emitChangedDbApp(folder);
|
apps.emitChangedDbApp(folder);
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
if (!hasPermission(`files/${folder}/write`, req)) return false;
|
if (!hasPermission(`files/${folder}/write`, loadedPermissions)) return false;
|
||||||
const dir = path.join(filesdir(), folder);
|
const dir = path.join(filesdir(), folder);
|
||||||
if (!(await fs.exists(dir))) {
|
if (!(await fs.exists(dir))) {
|
||||||
await fs.mkdir(dir);
|
await fs.mkdir(dir);
|
||||||
@@ -177,7 +184,8 @@ module.exports = {
|
|||||||
|
|
||||||
favorites_meta: true,
|
favorites_meta: true,
|
||||||
async favorites(_params, req) {
|
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');
|
const dir = path.join(filesdir(), 'favorites');
|
||||||
if (!(await fs.exists(dir))) return [];
|
if (!(await fs.exists(dir))) return [];
|
||||||
const files = await fs.readdir(dir);
|
const files = await fs.readdir(dir);
|
||||||
@@ -234,16 +242,17 @@ module.exports = {
|
|||||||
|
|
||||||
getFileRealPath_meta: true,
|
getFileRealPath_meta: true,
|
||||||
async getFileRealPath({ folder, file }, req) {
|
async getFileRealPath({ folder, file }, req) {
|
||||||
|
const loadedPermissions = await loadPermissionsFromRequest(req);
|
||||||
if (folder.startsWith('archive:')) {
|
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));
|
const dir = resolveArchiveFolder(folder.substring('archive:'.length));
|
||||||
return path.join(dir, file);
|
return path.join(dir, file);
|
||||||
} else if (folder.startsWith('app:')) {
|
} 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);
|
const app = folder.substring('app:'.length);
|
||||||
return path.join(appdir(), app, file);
|
return path.join(appdir(), app, file);
|
||||||
} else {
|
} else {
|
||||||
if (!hasPermission(`files/${folder}/write`, req)) return false;
|
if (!hasPermission(`files/${folder}/write`, loadedPermissions)) return false;
|
||||||
const dir = path.join(filesdir(), folder);
|
const dir = path.join(filesdir(), folder);
|
||||||
if (!(await fs.exists(dir))) {
|
if (!(await fs.exists(dir))) {
|
||||||
await fs.mkdir(dir);
|
await fs.mkdir(dir);
|
||||||
@@ -297,7 +306,8 @@ module.exports = {
|
|||||||
|
|
||||||
exportFile_meta: true,
|
exportFile_meta: true,
|
||||||
async exportFile({ folder, file, filePath }, req) {
|
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);
|
await fs.copyFile(path.join(filesdir(), folder, file), filePath);
|
||||||
return true;
|
return true;
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ const socket = require('../utility/socket');
|
|||||||
const compareVersions = require('compare-versions');
|
const compareVersions = require('compare-versions');
|
||||||
const requirePlugin = require('../shell/requirePlugin');
|
const requirePlugin = require('../shell/requirePlugin');
|
||||||
const downloadPackage = require('../utility/downloadPackage');
|
const downloadPackage = require('../utility/downloadPackage');
|
||||||
const { hasPermission } = require('../utility/hasPermission');
|
const { hasPermission, loadPermissionsFromRequest } = require('../utility/hasPermission');
|
||||||
const _ = require('lodash');
|
const _ = require('lodash');
|
||||||
const packagedPluginsContent = require('../packagedPluginsContent');
|
const packagedPluginsContent = require('../packagedPluginsContent');
|
||||||
|
|
||||||
@@ -118,7 +118,8 @@ module.exports = {
|
|||||||
|
|
||||||
install_meta: true,
|
install_meta: true,
|
||||||
async install({ packageName }, req) {
|
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);
|
const dir = path.join(pluginsdir(), packageName);
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
if (!(await fs.exists(dir))) {
|
if (!(await fs.exists(dir))) {
|
||||||
@@ -132,7 +133,8 @@ module.exports = {
|
|||||||
|
|
||||||
uninstall_meta: true,
|
uninstall_meta: true,
|
||||||
async uninstall({ packageName }, req) {
|
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);
|
const dir = path.join(pluginsdir(), packageName);
|
||||||
await fs.rmdir(dir, { recursive: true });
|
await fs.rmdir(dir, { recursive: true });
|
||||||
socket.emitChanged(`installed-plugins-changed`);
|
socket.emitChanged(`installed-plugins-changed`);
|
||||||
@@ -143,7 +145,8 @@ module.exports = {
|
|||||||
|
|
||||||
upgrade_meta: true,
|
upgrade_meta: true,
|
||||||
async upgrade({ packageName }, req) {
|
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);
|
const dir = path.join(pluginsdir(), packageName);
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
if (await fs.exists(dir)) {
|
if (await fs.exists(dir)) {
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ const processArgs = require('../utility/processArgs');
|
|||||||
const platformInfo = require('../utility/platformInfo');
|
const platformInfo = require('../utility/platformInfo');
|
||||||
const { checkSecureDirectories, checkSecureDirectoriesInScript } = require('../utility/security');
|
const { checkSecureDirectories, checkSecureDirectoriesInScript } = require('../utility/security');
|
||||||
const { sendToAuditLog, logJsonRunnerScript } = require('../utility/auditlog');
|
const { sendToAuditLog, logJsonRunnerScript } = require('../utility/auditlog');
|
||||||
|
const { testStandardPermission } = require('../utility/hasPermission');
|
||||||
const logger = getLogger('runners');
|
const logger = getLogger('runners');
|
||||||
|
|
||||||
function extractPlugins(script) {
|
function extractPlugins(script) {
|
||||||
@@ -273,6 +274,8 @@ module.exports = {
|
|||||||
|
|
||||||
start_meta: true,
|
start_meta: true,
|
||||||
async start({ script }, req) {
|
async start({ script }, req) {
|
||||||
|
await testStandardPermission('run-shell-script', req);
|
||||||
|
|
||||||
const runid = crypto.randomUUID();
|
const runid = crypto.randomUUID();
|
||||||
|
|
||||||
if (script.type == 'json') {
|
if (script.type == 'json') {
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ const fs = require('fs-extra');
|
|||||||
const path = require('path');
|
const path = require('path');
|
||||||
const cron = require('node-cron');
|
const cron = require('node-cron');
|
||||||
const runners = require('./runners');
|
const runners = require('./runners');
|
||||||
const { hasPermission } = require('../utility/hasPermission');
|
const { hasPermission, loadPermissionsFromRequest } = require('../utility/hasPermission');
|
||||||
const { getLogger } = require('dbgate-tools');
|
const { getLogger } = require('dbgate-tools');
|
||||||
|
|
||||||
const logger = getLogger('scheduler');
|
const logger = getLogger('scheduler');
|
||||||
@@ -30,7 +30,8 @@ module.exports = {
|
|||||||
},
|
},
|
||||||
|
|
||||||
async reload(_params, req) {
|
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');
|
const shellDir = path.join(filesdir(), 'shell');
|
||||||
await this.unload();
|
await this.unload();
|
||||||
if (!(await fs.exists(shellDir))) return;
|
if (!(await fs.exists(shellDir))) return;
|
||||||
|
|||||||
@@ -8,7 +8,13 @@ const { handleProcessCommunication } = require('../utility/processComm');
|
|||||||
const lock = new AsyncLock();
|
const lock = new AsyncLock();
|
||||||
const config = require('./config');
|
const config = require('./config');
|
||||||
const processArgs = require('../utility/processArgs');
|
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 { MissingCredentialsError } = require('../utility/exceptions');
|
||||||
const pipeForkLogs = require('../utility/pipeForkLogs');
|
const pipeForkLogs = require('../utility/pipeForkLogs');
|
||||||
const { getLogger, extractErrorLogData } = require('dbgate-tools');
|
const { getLogger, extractErrorLogData } = require('dbgate-tools');
|
||||||
@@ -135,7 +141,7 @@ module.exports = {
|
|||||||
|
|
||||||
disconnect_meta: true,
|
disconnect_meta: true,
|
||||||
async disconnect({ conid }, req) {
|
async disconnect({ conid }, req) {
|
||||||
testConnectionPermission(conid, req);
|
await testConnectionPermission(conid, req);
|
||||||
await this.close(conid, true);
|
await this.close(conid, true);
|
||||||
return { status: 'ok' };
|
return { status: 'ok' };
|
||||||
},
|
},
|
||||||
@@ -144,7 +150,9 @@ module.exports = {
|
|||||||
async listDatabases({ conid }, req) {
|
async listDatabases({ conid }, req) {
|
||||||
if (!conid) return [];
|
if (!conid) return [];
|
||||||
if (conid == '__model') return [];
|
if (conid == '__model') return [];
|
||||||
testConnectionPermission(conid, req);
|
const loadedPermissions = await loadPermissionsFromRequest(req);
|
||||||
|
|
||||||
|
await testConnectionPermission(conid, req, loadedPermissions);
|
||||||
const opened = await this.ensureOpened(conid);
|
const opened = await this.ensureOpened(conid);
|
||||||
sendToAuditLog(req, {
|
sendToAuditLog(req, {
|
||||||
category: 'serverop',
|
category: 'serverop',
|
||||||
@@ -157,12 +165,29 @@ module.exports = {
|
|||||||
sessionGroup: 'listDatabases',
|
sessionGroup: 'listDatabases',
|
||||||
message: `Loaded databases for connection`,
|
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 ?? [];
|
return opened?.databases ?? [];
|
||||||
},
|
},
|
||||||
|
|
||||||
version_meta: true,
|
version_meta: true,
|
||||||
async version({ conid }, req) {
|
async version({ conid }, req) {
|
||||||
testConnectionPermission(conid, req);
|
await testConnectionPermission(conid, req);
|
||||||
const opened = await this.ensureOpened(conid);
|
const opened = await this.ensureOpened(conid);
|
||||||
return opened?.version ?? null;
|
return opened?.version ?? null;
|
||||||
},
|
},
|
||||||
@@ -202,7 +227,7 @@ module.exports = {
|
|||||||
|
|
||||||
refresh_meta: true,
|
refresh_meta: true,
|
||||||
async refresh({ conid, keepOpen }, req) {
|
async refresh({ conid, keepOpen }, req) {
|
||||||
testConnectionPermission(conid, req);
|
await testConnectionPermission(conid, req);
|
||||||
if (!keepOpen) this.close(conid);
|
if (!keepOpen) this.close(conid);
|
||||||
|
|
||||||
await this.ensureOpened(conid);
|
await this.ensureOpened(conid);
|
||||||
@@ -210,7 +235,7 @@ module.exports = {
|
|||||||
},
|
},
|
||||||
|
|
||||||
async sendDatabaseOp({ conid, msgtype, name }, req) {
|
async sendDatabaseOp({ conid, msgtype, name }, req) {
|
||||||
testConnectionPermission(conid, req);
|
await testConnectionPermission(conid, req);
|
||||||
const opened = await this.ensureOpened(conid);
|
const opened = await this.ensureOpened(conid);
|
||||||
if (!opened) {
|
if (!opened) {
|
||||||
return null;
|
return null;
|
||||||
@@ -252,7 +277,7 @@ module.exports = {
|
|||||||
},
|
},
|
||||||
|
|
||||||
async loadDataCore(msgtype, { conid, ...args }, req) {
|
async loadDataCore(msgtype, { conid, ...args }, req) {
|
||||||
testConnectionPermission(conid, req);
|
await testConnectionPermission(conid, req);
|
||||||
const opened = await this.ensureOpened(conid);
|
const opened = await this.ensureOpened(conid);
|
||||||
if (!opened) {
|
if (!opened) {
|
||||||
return null;
|
return null;
|
||||||
@@ -270,8 +295,8 @@ module.exports = {
|
|||||||
|
|
||||||
serverSummary_meta: true,
|
serverSummary_meta: true,
|
||||||
async serverSummary({ conid }, req) {
|
async serverSummary({ conid }, req) {
|
||||||
|
await testConnectionPermission(conid, req);
|
||||||
logger.info({ conid }, 'DBGM-00260 Processing server summary');
|
logger.info({ conid }, 'DBGM-00260 Processing server summary');
|
||||||
testConnectionPermission(conid, req);
|
|
||||||
return this.loadDataCore('serverSummary', { conid });
|
return this.loadDataCore('serverSummary', { conid });
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -306,7 +331,7 @@ module.exports = {
|
|||||||
|
|
||||||
summaryCommand_meta: true,
|
summaryCommand_meta: true,
|
||||||
async summaryCommand({ conid, command, row }, req) {
|
async summaryCommand({ conid, command, row }, req) {
|
||||||
testConnectionPermission(conid, req);
|
await testConnectionPermission(conid, req);
|
||||||
const opened = await this.ensureOpened(conid);
|
const opened = await this.ensureOpened(conid);
|
||||||
if (!opened) {
|
if (!opened) {
|
||||||
return null;
|
return null;
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ const { getLogger, extractErrorLogData } = require('dbgate-tools');
|
|||||||
const pipeForkLogs = require('../utility/pipeForkLogs');
|
const pipeForkLogs = require('../utility/pipeForkLogs');
|
||||||
const config = require('./config');
|
const config = require('./config');
|
||||||
const { sendToAuditLog } = require('../utility/auditlog');
|
const { sendToAuditLog } = require('../utility/auditlog');
|
||||||
|
const { testStandardPermission, testDatabaseRolePermission } = require('../utility/hasPermission');
|
||||||
|
|
||||||
const logger = getLogger('sessions');
|
const logger = getLogger('sessions');
|
||||||
|
|
||||||
@@ -148,10 +149,12 @@ module.exports = {
|
|||||||
|
|
||||||
executeQuery_meta: true,
|
executeQuery_meta: true,
|
||||||
async executeQuery({ sesid, sql, autoCommit, autoDetectCharts, limitRows, frontMatter }, req) {
|
async executeQuery({ sesid, sql, autoCommit, autoDetectCharts, limitRows, frontMatter }, req) {
|
||||||
|
await testStandardPermission('dbops/query', req);
|
||||||
const session = this.opened.find(x => x.sesid == sesid);
|
const session = this.opened.find(x => x.sesid == sesid);
|
||||||
if (!session) {
|
if (!session) {
|
||||||
throw new Error('Invalid session');
|
throw new Error('Invalid session');
|
||||||
}
|
}
|
||||||
|
await testDatabaseRolePermission(session.conid, session.database, 'run_script', req);
|
||||||
|
|
||||||
sendToAuditLog(req, {
|
sendToAuditLog(req, {
|
||||||
category: 'dbop',
|
category: 'dbop',
|
||||||
|
|||||||
@@ -17,13 +17,14 @@ const requireEngineDriver = require('../utility/requireEngineDriver');
|
|||||||
const { connectUtility } = require('../utility/connectUtility');
|
const { connectUtility } = require('../utility/connectUtility');
|
||||||
const { handleProcessCommunication } = require('../utility/processComm');
|
const { handleProcessCommunication } = require('../utility/processComm');
|
||||||
const generateDeploySql = require('../shell/generateDeploySql');
|
const generateDeploySql = require('../shell/generateDeploySql');
|
||||||
const { dumpSqlSelect } = require('dbgate-sqltree');
|
const { dumpSqlSelect, scriptToSql } = require('dbgate-sqltree');
|
||||||
const { allowExecuteCustomScript, handleQueryStream } = require('../utility/handleQueryStream');
|
const { allowExecuteCustomScript, handleQueryStream } = require('../utility/handleQueryStream');
|
||||||
const dbgateApi = require('../shell');
|
const dbgateApi = require('../shell');
|
||||||
const requirePlugin = require('../shell/requirePlugin');
|
const requirePlugin = require('../shell/requirePlugin');
|
||||||
const path = require('path');
|
const path = require('path');
|
||||||
const { rundir } = require('../utility/directories');
|
const { rundir } = require('../utility/directories');
|
||||||
const fs = require('fs-extra');
|
const fs = require('fs-extra');
|
||||||
|
const { changeSetToSql } = require('dbgate-datalib');
|
||||||
|
|
||||||
const logger = getLogger('dbconnProcess');
|
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 }) {
|
async function handleSqlPreview({ msgid, objects, options }) {
|
||||||
await waitStructure();
|
await waitStructure();
|
||||||
const driver = requireEngineDriver(storedConnection);
|
const driver = requireEngineDriver(storedConnection);
|
||||||
@@ -464,6 +486,7 @@ const messageHandlers = {
|
|||||||
runScript: handleRunScript,
|
runScript: handleRunScript,
|
||||||
runOperation: handleRunOperation,
|
runOperation: handleRunOperation,
|
||||||
updateCollection: handleUpdateCollection,
|
updateCollection: handleUpdateCollection,
|
||||||
|
saveTableData: handleSaveTableData,
|
||||||
collectionData: handleCollectionData,
|
collectionData: handleCollectionData,
|
||||||
loadKeys: handleLoadKeys,
|
loadKeys: handleLoadKeys,
|
||||||
scanKeys: handleScanKeys,
|
scanKeys: handleScanKeys,
|
||||||
|
|||||||
@@ -695,27 +695,27 @@ module.exports = {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"pureName": "roles",
|
"pureName": "database_permission_roles",
|
||||||
"columns": [
|
"columns": [
|
||||||
{
|
{
|
||||||
"pureName": "roles",
|
"pureName": "database_permission_roles",
|
||||||
"columnName": "id",
|
"columnName": "id",
|
||||||
"dataType": "int",
|
"dataType": "int",
|
||||||
"autoIncrement": true,
|
"autoIncrement": true,
|
||||||
"notNull": true
|
"notNull": true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"pureName": "roles",
|
"pureName": "database_permission_roles",
|
||||||
"columnName": "name",
|
"columnName": "name",
|
||||||
"dataType": "varchar(250)",
|
"dataType": "varchar(100)",
|
||||||
"notNull": false
|
"notNull": true
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"foreignKeys": [],
|
"foreignKeys": [],
|
||||||
"primaryKey": {
|
"primaryKey": {
|
||||||
"pureName": "roles",
|
"pureName": "database_permission_roles",
|
||||||
"constraintType": "primaryKey",
|
"constraintType": "primaryKey",
|
||||||
"constraintName": "PK_roles",
|
"constraintName": "PK_database_permission_roles",
|
||||||
"columns": [
|
"columns": [
|
||||||
{
|
{
|
||||||
"columnName": "id"
|
"columnName": "id"
|
||||||
@@ -725,15 +725,23 @@ module.exports = {
|
|||||||
"preloadedRows": [
|
"preloadedRows": [
|
||||||
{
|
{
|
||||||
"id": -1,
|
"id": -1,
|
||||||
"name": "anonymous-user"
|
"name": "view"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": -2,
|
"id": -2,
|
||||||
"name": "logged-user"
|
"name": "read_content"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": -3,
|
"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",
|
"pureName": "role_permissions",
|
||||||
"columns": [
|
"columns": [
|
||||||
@@ -849,39 +949,132 @@ module.exports = {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"pureName": "users",
|
"pureName": "role_tables",
|
||||||
"columns": [
|
"columns": [
|
||||||
{
|
{
|
||||||
"pureName": "users",
|
"pureName": "role_tables",
|
||||||
"columnName": "id",
|
"columnName": "id",
|
||||||
"dataType": "int",
|
"dataType": "int",
|
||||||
"autoIncrement": true,
|
"autoIncrement": true,
|
||||||
"notNull": true
|
"notNull": true
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"pureName": "users",
|
"pureName": "role_tables",
|
||||||
"columnName": "login",
|
"columnName": "role_id",
|
||||||
"dataType": "varchar(250)",
|
"dataType": "int",
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"pureName": "role_tables",
|
||||||
|
"columnName": "connection_id",
|
||||||
|
"dataType": "int",
|
||||||
"notNull": false
|
"notNull": false
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"pureName": "users",
|
"pureName": "role_tables",
|
||||||
"columnName": "password",
|
"columnName": "database_names_list",
|
||||||
"dataType": "varchar(250)",
|
"dataType": "varchar(1000)",
|
||||||
"notNull": false
|
"notNull": false
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"pureName": "users",
|
"pureName": "role_tables",
|
||||||
"columnName": "email",
|
"columnName": "database_names_regex",
|
||||||
"dataType": "varchar(250)",
|
"dataType": "varchar(1000)",
|
||||||
"notNull": false
|
"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": {
|
"primaryKey": {
|
||||||
"pureName": "users",
|
"pureName": "role_tables",
|
||||||
"constraintType": "primaryKey",
|
"constraintType": "primaryKey",
|
||||||
"constraintName": "PK_users",
|
"constraintName": "PK_role_tables",
|
||||||
"columns": [
|
"columns": [
|
||||||
{
|
{
|
||||||
"columnName": "id"
|
"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",
|
"pureName": "user_connections",
|
||||||
"columns": [
|
"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",
|
"pureName": "user_permissions",
|
||||||
"columns": [
|
"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": [],
|
"collections": [],
|
||||||
|
|||||||
@@ -1,101 +1,302 @@
|
|||||||
const { compilePermissions, testPermission } = require('dbgate-tools');
|
const { compilePermissions, testPermission, getPermissionsCacheKey } = require('dbgate-tools');
|
||||||
const _ = require('lodash');
|
const _ = require('lodash');
|
||||||
const { getAuthProviderFromReq } = require('../auth/authProvider');
|
const { getAuthProviderFromReq } = require('../auth/authProvider');
|
||||||
|
|
||||||
const cachedPermissions = {};
|
const cachedPermissions = {};
|
||||||
|
|
||||||
function hasPermission(tested, req) {
|
async function loadPermissionsFromRequest(req) {
|
||||||
|
const authProvider = getAuthProviderFromReq(req);
|
||||||
if (!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;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
const permissions = getAuthProviderFromReq(req).getCurrentPermissions(req);
|
const permissionsKey = getPermissionsCacheKey(loadedPermissions);
|
||||||
|
if (!cachedPermissions[permissionsKey]) {
|
||||||
if (!cachedPermissions[permissions]) {
|
cachedPermissions[permissionsKey] = compilePermissions(loadedPermissions);
|
||||||
cachedPermissions[permissions] = compilePermissions(permissions);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return testPermission(tested, cachedPermissions[permissions]);
|
return testPermission(tested, cachedPermissions[permissionsKey]);
|
||||||
|
|
||||||
// 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]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// let loginsCache = null;
|
function connectionHasPermission(connection, loadedPermissions) {
|
||||||
// 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) {
|
|
||||||
if (!connection) {
|
if (!connection) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (_.isString(connection)) {
|
if (_.isString(connection)) {
|
||||||
return hasPermission(`connections/${connection}`, req);
|
return hasPermission(`connections/${connection}`, loadedPermissions);
|
||||||
} else {
|
} else {
|
||||||
return hasPermission(`connections/${connection._id}`, req);
|
return hasPermission(`connections/${connection._id}`, loadedPermissions);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function testConnectionPermission(connection, req) {
|
async function testConnectionPermission(connection, req, loadedPermissions) {
|
||||||
if (!connectionHasPermission(connection, req)) {
|
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');
|
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 = {
|
module.exports = {
|
||||||
hasPermission,
|
hasPermission,
|
||||||
connectionHasPermission,
|
connectionHasPermission,
|
||||||
testConnectionPermission,
|
testConnectionPermission,
|
||||||
|
loadPermissionsFromRequest,
|
||||||
|
loadDatabasePermissionsFromRequest,
|
||||||
|
loadTablePermissionsFromRequest,
|
||||||
|
getDatabasePermissionRole,
|
||||||
|
getTablePermissionRole,
|
||||||
|
testStandardPermission,
|
||||||
|
testDatabaseRolePermission,
|
||||||
|
getTablePermissionRoleLevelIndex
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -57,6 +57,12 @@ export function compilePermissions(permissions: string[] | string): CompiledPerm
|
|||||||
return res;
|
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) {
|
export function testPermission(tested: string, permissions: CompiledPermissions) {
|
||||||
let allow = true;
|
let allow = true;
|
||||||
|
|
||||||
@@ -103,9 +109,9 @@ export function getPredefinedPermissions(predefinedRoleName: string) {
|
|||||||
case 'superadmin':
|
case 'superadmin':
|
||||||
return ['*', '~widgets/*', 'widgets/admin', 'widgets/database', '~all-connections'];
|
return ['*', '~widgets/*', 'widgets/admin', 'widgets/database', '~all-connections'];
|
||||||
case 'logged-user':
|
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':
|
case 'anonymous-user':
|
||||||
return ['*', '~widgets/admin', '~admin/*', '~internal-storage', '~all-connections'];
|
return ['*', '~widgets/admin', '~admin/*', '~internal-storage', '~all-connections', '~run-shell-script'];
|
||||||
default:
|
default:
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|||||||
1
packages/types/dbinfo.d.ts
vendored
1
packages/types/dbinfo.d.ts
vendored
@@ -77,6 +77,7 @@ export interface DatabaseObjectInfo extends NamedObjectInfo {
|
|||||||
hashCode?: string;
|
hashCode?: string;
|
||||||
objectTypeField?: string;
|
objectTypeField?: string;
|
||||||
objectComment?: string;
|
objectComment?: string;
|
||||||
|
tablePermissionRole?: 'read' | 'update_only' | 'create_update_delete' | 'deny';
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface SqlObjectInfo extends DatabaseObjectInfo {
|
export interface SqlObjectInfo extends DatabaseObjectInfo {
|
||||||
|
|||||||
@@ -167,7 +167,7 @@ await dbgateApi.deployDb(${JSON.stringify(
|
|||||||
isProApp() && { text: 'Data deployer', onClick: handleOpenDataDeployTab },
|
isProApp() && { text: 'Data deployer', onClick: handleOpenDataDeployTab },
|
||||||
$currentDatabase && [
|
$currentDatabase && [
|
||||||
{ text: 'Generate deploy DB SQL', onClick: handleGenerateDeploySql },
|
{ 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' &&
|
data.name != 'default' &&
|
||||||
isProApp() &&
|
isProApp() &&
|
||||||
|
|||||||
@@ -382,7 +382,8 @@
|
|||||||
$extensions,
|
$extensions,
|
||||||
$currentDatabase,
|
$currentDatabase,
|
||||||
$apps,
|
$apps,
|
||||||
$openedSingleDatabaseConnections
|
$openedSingleDatabaseConnections,
|
||||||
|
data.databasePermissionRole,
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
|
||||||
|
|||||||
@@ -46,7 +46,8 @@
|
|||||||
$extensions,
|
$extensions,
|
||||||
$currentDatabase,
|
$currentDatabase,
|
||||||
$apps,
|
$apps,
|
||||||
$openedSingleDatabaseConnections
|
$openedSingleDatabaseConnections,
|
||||||
|
databasePermissionRole
|
||||||
) {
|
) {
|
||||||
const apps = filterAppsForDatabase(connection, name, $apps);
|
const apps = filterAppsForDatabase(connection, name, $apps);
|
||||||
const handleNewQuery = () => {
|
const handleNewQuery = () => {
|
||||||
@@ -412,7 +413,8 @@ await dbgateApi.executeQuery(${JSON.stringify(
|
|||||||
driver?.databaseEngineTypes?.includes('sql') || driver?.databaseEngineTypes?.includes('document');
|
driver?.databaseEngineTypes?.includes('sql') || driver?.databaseEngineTypes?.includes('document');
|
||||||
|
|
||||||
return [
|
return [
|
||||||
hasPermission(`dbops/query`) && {
|
hasPermission(`dbops/query`) &&
|
||||||
|
isAllowedDatabaseRunScript(databasePermissionRole) && {
|
||||||
onClick: handleNewQuery,
|
onClick: handleNewQuery,
|
||||||
text: _t('database.newQuery', { defaultMessage: 'New query' }),
|
text: _t('database.newQuery', { defaultMessage: 'New query' }),
|
||||||
isNewQuery: true,
|
isNewQuery: true,
|
||||||
@@ -545,12 +547,13 @@ await dbgateApi.executeQuery(${JSON.stringify(
|
|||||||
{ divider: true },
|
{ divider: true },
|
||||||
|
|
||||||
driver?.databaseEngineTypes?.includes('sql') &&
|
driver?.databaseEngineTypes?.includes('sql') &&
|
||||||
|
hasPermission(`run-shell-script`) &&
|
||||||
hasPermission(`dbops/dropdb`) && {
|
hasPermission(`dbops/dropdb`) && {
|
||||||
onClick: handleGenerateDropAllObjectsScript,
|
onClick: handleGenerateDropAllObjectsScript,
|
||||||
text: _t('database.shellDropAllObjects', { defaultMessage: 'Shell: Drop all objects' }),
|
text: _t('database.shellDropAllObjects', { defaultMessage: 'Shell: Drop all objects' }),
|
||||||
},
|
},
|
||||||
|
|
||||||
{
|
hasPermission(`run-shell-script`) && {
|
||||||
onClick: handleGenerateRunScript,
|
onClick: handleGenerateRunScript,
|
||||||
text: _t('database.shellRunScript', { defaultMessage: 'Shell: Run script' }),
|
text: _t('database.shellRunScript', { defaultMessage: 'Shell: Run script' }),
|
||||||
},
|
},
|
||||||
@@ -625,7 +628,7 @@ await dbgateApi.executeQuery(${JSON.stringify(
|
|||||||
import ConfirmModal from '../modals/ConfirmModal.svelte';
|
import ConfirmModal from '../modals/ConfirmModal.svelte';
|
||||||
import { closeMultipleTabs } from '../tabpanel/TabsPanel.svelte';
|
import { closeMultipleTabs } from '../tabpanel/TabsPanel.svelte';
|
||||||
import NewCollectionModal from '../modals/NewCollectionModal.svelte';
|
import NewCollectionModal from '../modals/NewCollectionModal.svelte';
|
||||||
import hasPermission from '../utility/hasPermission';
|
import hasPermission, { isAllowedDatabaseRunScript } from '../utility/hasPermission';
|
||||||
import { openImportExportTab } from '../utility/importExportTools';
|
import { openImportExportTab } from '../utility/importExportTools';
|
||||||
import newTable from '../tableeditor/newTable';
|
import newTable from '../tableeditor/newTable';
|
||||||
import { loadSchemaList, switchCurrentDatabase } from '../utility/common';
|
import { loadSchemaList, switchCurrentDatabase } from '../utility/common';
|
||||||
@@ -636,6 +639,7 @@ await dbgateApi.executeQuery(${JSON.stringify(
|
|||||||
import { getNumberIcon } from '../icons/FontIcon.svelte';
|
import { getNumberIcon } from '../icons/FontIcon.svelte';
|
||||||
import { getDatabaseClickActionSetting } from '../settings/settingsTools';
|
import { getDatabaseClickActionSetting } from '../settings/settingsTools';
|
||||||
import { _t } from '../translations';
|
import { _t } from '../translations';
|
||||||
|
import { dataGridRowHeight } from '../datagrid/DataGridRowHeightMeter.svelte';
|
||||||
|
|
||||||
export let data;
|
export let data;
|
||||||
export let passProps;
|
export let passProps;
|
||||||
@@ -647,7 +651,8 @@ await dbgateApi.executeQuery(${JSON.stringify(
|
|||||||
$extensions,
|
$extensions,
|
||||||
$currentDatabase,
|
$currentDatabase,
|
||||||
$apps,
|
$apps,
|
||||||
$openedSingleDatabaseConnections
|
$openedSingleDatabaseConnections,
|
||||||
|
data.databasePermissionRole
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -697,6 +702,9 @@ await dbgateApi.executeQuery(${JSON.stringify(
|
|||||||
).length
|
).length
|
||||||
)
|
)
|
||||||
: ''}
|
: ''}
|
||||||
|
statusIconBefore={data.databasePermissionRole == 'read_content' || data.databasePermissionRole == 'view'
|
||||||
|
? 'icon lock'
|
||||||
|
: null}
|
||||||
menu={createMenu}
|
menu={createMenu}
|
||||||
showPinnedInsteadOfUnpin={passProps?.showPinnedInsteadOfUnpin}
|
showPinnedInsteadOfUnpin={passProps?.showPinnedInsteadOfUnpin}
|
||||||
onPin={isPinned ? null : () => pinnedDatabases.update(list => [...list, data])}
|
onPin={isPinned ? null : () => pinnedDatabases.update(list => [...list, data])}
|
||||||
|
|||||||
@@ -703,7 +703,15 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
function createMenus(objectTypeField, driver, data): ReturnType<typeof createMenusCore> {
|
function createMenus(objectTypeField, driver, data): ReturnType<typeof createMenusCore> {
|
||||||
return createMenusCore(objectTypeField, driver, data).filter(x => {
|
const coreMenus = createMenusCore(objectTypeField, driver, data);
|
||||||
|
|
||||||
|
const filteredSumenus = coreMenus.map(item => {
|
||||||
|
if (!item.submenu) {
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
...item,
|
||||||
|
submenu: item.submenu.filter(x => {
|
||||||
if (x.scriptTemplate) {
|
if (x.scriptTemplate) {
|
||||||
return hasPermission(`dbops/sql-template/${x.scriptTemplate}`);
|
return hasPermission(`dbops/sql-template/${x.scriptTemplate}`);
|
||||||
}
|
}
|
||||||
@@ -711,7 +719,13 @@
|
|||||||
return hasPermission(`dbops/sql-generator`);
|
return hasPermission(`dbops/sql-generator`);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
}),
|
||||||
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const filteredNoEmptySubmenus = filteredSumenus.filter(x => !x.submenu || x.submenu.length > 0);
|
||||||
|
|
||||||
|
return filteredNoEmptySubmenus;
|
||||||
}
|
}
|
||||||
|
|
||||||
function getObjectTitle(connection, schemaName, pureName) {
|
function getObjectTitle(connection, schemaName, pureName) {
|
||||||
@@ -1062,6 +1076,7 @@
|
|||||||
: null}
|
: null}
|
||||||
extInfo={getExtInfo(data)}
|
extInfo={getExtInfo(data)}
|
||||||
isChoosed={matchDatabaseObjectAppObject($selectedDatabaseObjectAppObject, data)}
|
isChoosed={matchDatabaseObjectAppObject($selectedDatabaseObjectAppObject, data)}
|
||||||
|
statusIconBefore={data.tablePermissionRole == 'read' ? 'icon lock' : null}
|
||||||
on:click={() => handleObjectClick(data, 'leftClick')}
|
on:click={() => handleObjectClick(data, 'leftClick')}
|
||||||
on:middleclick={() => handleObjectClick(data, 'middleClick')}
|
on:middleclick={() => handleObjectClick(data, 'middleClick')}
|
||||||
on:dblclick={() => handleObjectClick(data, 'dblClick')}
|
on:dblclick={() => handleObjectClick(data, 'dblClick')}
|
||||||
|
|||||||
@@ -322,6 +322,7 @@ registerCommand({
|
|||||||
toolbar: true,
|
toolbar: true,
|
||||||
toolbarName: 'New table',
|
toolbarName: 'New table',
|
||||||
testEnabled: () => {
|
testEnabled: () => {
|
||||||
|
if (!hasPermission('dbops/model/edit')) return false;
|
||||||
const driver = findEngineDriver(get(currentDatabase)?.connection, getExtensions());
|
const driver = findEngineDriver(get(currentDatabase)?.connection, getExtensions());
|
||||||
return !!get(currentDatabase) && driver?.databaseEngineTypes?.includes('sql');
|
return !!get(currentDatabase) && driver?.databaseEngineTypes?.includes('sql');
|
||||||
},
|
},
|
||||||
@@ -671,7 +672,7 @@ registerCommand({
|
|||||||
name: 'Export database',
|
name: 'Export database',
|
||||||
toolbar: true,
|
toolbar: true,
|
||||||
icon: 'icon export',
|
icon: 'icon export',
|
||||||
testEnabled: () => getCurrentDatabase() != null,
|
testEnabled: () => getCurrentDatabase() != null && hasPermission(`dbops/export`),
|
||||||
onClick: () => {
|
onClick: () => {
|
||||||
openImportExportTab({
|
openImportExportTab({
|
||||||
targetStorageType: getDefaultFileFormat(getExtensions()).storageType,
|
targetStorageType: getDefaultFileFormat(getExtensions()).storageType,
|
||||||
@@ -691,7 +692,8 @@ if (isProApp()) {
|
|||||||
icon: 'icon compare',
|
icon: 'icon compare',
|
||||||
testEnabled: () =>
|
testEnabled: () =>
|
||||||
getCurrentDatabase() != null &&
|
getCurrentDatabase() != null &&
|
||||||
findEngineDriver(getCurrentDatabase()?.connection, getExtensions())?.databaseEngineTypes?.includes('sql'),
|
findEngineDriver(getCurrentDatabase()?.connection, getExtensions())?.databaseEngineTypes?.includes('sql')
|
||||||
|
&& hasPermission(`dbops/export`),
|
||||||
onClick: () => {
|
onClick: () => {
|
||||||
openNewTab(
|
openNewTab(
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -77,7 +77,10 @@
|
|||||||
{ showHintColumns: getBoolSettingsValue('dataGrid.showHintColumns', true) },
|
{ showHintColumns: getBoolSettingsValue('dataGrid.showHintColumns', true) },
|
||||||
$serverVersion,
|
$serverVersion,
|
||||||
table => getDictionaryDescription(table, conid, database, $apps, $connections),
|
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,
|
isRawMode,
|
||||||
$settingsValue
|
$settingsValue
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -74,6 +74,8 @@
|
|||||||
'icon arrow-link': 'mdi mdi-arrow-top-right-thick',
|
'icon arrow-link': 'mdi mdi-arrow-top-right-thick',
|
||||||
'icon reset': 'mdi mdi-cancel',
|
'icon reset': 'mdi mdi-cancel',
|
||||||
'icon send': 'mdi mdi-send',
|
'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-restore': 'mdi mdi-window-restore',
|
||||||
'icon window-maximize': 'mdi mdi-window-maximize',
|
'icon window-maximize': 'mdi mdi-window-maximize',
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
import runCommand from '../commands/runCommand';
|
import runCommand from '../commands/runCommand';
|
||||||
import newQuery from '../query/newQuery';
|
import newQuery from '../query/newQuery';
|
||||||
import { commandsCustomized, selectedWidget } from '../stores';
|
import { commandsCustomized, selectedWidget } from '../stores';
|
||||||
|
import hasPermission from '../utility/hasPermission';
|
||||||
import { isProApp } from '../utility/proTools';
|
import { isProApp } from '../utility/proTools';
|
||||||
import ModalBase from './ModalBase.svelte';
|
import ModalBase from './ModalBase.svelte';
|
||||||
import { closeCurrentModal } from './modalTools';
|
import { closeCurrentModal } from './modalTools';
|
||||||
@@ -19,6 +20,7 @@
|
|||||||
newQuery({ multiTabIndex });
|
newQuery({ multiTabIndex });
|
||||||
},
|
},
|
||||||
testid: 'NewObjectModal_query',
|
testid: 'NewObjectModal_query',
|
||||||
|
testEnabled: () => hasPermission('dbops/query'),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
icon: 'icon connection',
|
icon: 'icon connection',
|
||||||
@@ -114,7 +116,7 @@
|
|||||||
isProFeature: true,
|
isProFeature: true,
|
||||||
disabledMessage: 'Database chat is not available for current database',
|
disabledMessage: 'Database chat is not available for current database',
|
||||||
testid: 'NewObjectModal_databaseChat',
|
testid: 'NewObjectModal_databaseChat',
|
||||||
}
|
},
|
||||||
];
|
];
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
@@ -122,7 +124,11 @@
|
|||||||
<div class="create-header">Create new</div>
|
<div class="create-header">Create new</div>
|
||||||
<div class="wrapper">
|
<div class="wrapper">
|
||||||
{#each NEW_ITEMS as item}
|
{#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
|
<NewObjectButton
|
||||||
icon={item.icon}
|
icon={item.icon}
|
||||||
title={item.title}
|
title={item.title}
|
||||||
|
|||||||
@@ -40,7 +40,7 @@
|
|||||||
execute: true,
|
execute: true,
|
||||||
toggleComment: true,
|
toggleComment: true,
|
||||||
findReplace: true,
|
findReplace: true,
|
||||||
executeAdditionalCondition: () => getCurrentEditor()?.hasConnection(),
|
executeAdditionalCondition: () => getCurrentEditor()?.hasConnection() && hasPermission('dbops/query'),
|
||||||
copyPaste: true,
|
copyPaste: true,
|
||||||
});
|
});
|
||||||
registerCommand({
|
registerCommand({
|
||||||
|
|||||||
@@ -80,7 +80,7 @@
|
|||||||
import invalidateCommands from '../commands/invalidateCommands';
|
import invalidateCommands from '../commands/invalidateCommands';
|
||||||
import { showModal } from '../modals/modalTools';
|
import { showModal } from '../modals/modalTools';
|
||||||
import ErrorMessageModal from '../modals/ErrorMessageModal.svelte';
|
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 { scriptToSql } from 'dbgate-sqltree';
|
||||||
import { extensions, lastUsedDefaultActions } from '../stores';
|
import { extensions, lastUsedDefaultActions } from '../stores';
|
||||||
import ConfirmSqlModal from '../modals/ConfirmSqlModal.svelte';
|
import ConfirmSqlModal from '../modals/ConfirmSqlModal.svelte';
|
||||||
@@ -156,9 +156,25 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function save() {
|
export async function save() {
|
||||||
const driver = findEngineDriver($connection, $extensions);
|
const driver = findEngineDriver($connection, $extensions);
|
||||||
|
const tablePermissionRole = (await getTableInfo({ conid, database, schemaName, pureName }))?.tablePermissionRole;
|
||||||
|
|
||||||
|
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, () =>
|
const script = driver.createSaveChangeSetScript($changeSetStore?.value, $dbinfo, () =>
|
||||||
changeSetToSql($changeSetStore?.value, $dbinfo, driver.dialect)
|
changeSetToSql($changeSetStore?.value, $dbinfo, driver.dialect)
|
||||||
);
|
);
|
||||||
@@ -182,6 +198,7 @@
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export function canSave() {
|
export function canSave() {
|
||||||
return changeSetContainsChanges($changeSetStore?.value);
|
return changeSetContainsChanges($changeSetStore?.value);
|
||||||
|
|||||||
@@ -22,3 +22,8 @@ export function subscribePermissionCompiler() {
|
|||||||
export function setConfigForPermissions(config) {
|
export function setConfigForPermissions(config) {
|
||||||
compiled = compilePermissions(config?.permissions || []);
|
compiled = compilePermissions(config?.permissions || []);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function isAllowedDatabaseRunScript(databasePermissionRole) {
|
||||||
|
return !databasePermissionRole || databasePermissionRole == 'run_script';
|
||||||
|
}
|
||||||
|
|
||||||
Reference in New Issue
Block a user