mirror of
https://github.com/DeNNiiInc/dbgate.git
synced 2026-04-29 18:03:58 +00:00
permissions refactor
This commit is contained in:
@@ -1,3 +1,4 @@
|
|||||||
DEVMODE=1
|
DEVMODE=1
|
||||||
|
# PERMISSIONS=~widgets/app,~widgets/plugins
|
||||||
# DISABLE_SHELL=1
|
# DISABLE_SHELL=1
|
||||||
# HIDE_APP_EDITOR=1
|
# HIDE_APP_EDITOR=1
|
||||||
@@ -32,7 +32,7 @@ module.exports = {
|
|||||||
return {
|
return {
|
||||||
runAsPortal: !!connections.portalConnections,
|
runAsPortal: !!connections.portalConnections,
|
||||||
singleDatabase: connections.singleDatabase,
|
singleDatabase: connections.singleDatabase,
|
||||||
hideAppEditor: !!process.env.HIDE_APP_EDITOR,
|
// hideAppEditor: !!process.env.HIDE_APP_EDITOR,
|
||||||
allowShellConnection: platformInfo.allowShellConnection,
|
allowShellConnection: platformInfo.allowShellConnection,
|
||||||
allowShellScripting: platformInfo.allowShellConnection,
|
allowShellScripting: platformInfo.allowShellConnection,
|
||||||
permissions,
|
permissions,
|
||||||
|
|||||||
@@ -46,26 +46,29 @@ module.exports = {
|
|||||||
|
|
||||||
delete_meta: true,
|
delete_meta: true,
|
||||||
async delete({ folder, file }) {
|
async delete({ folder, file }) {
|
||||||
if (!hasPermission(`files/${folder}/write`)) return;
|
if (!hasPermission(`files/${folder}/write`)) return false;
|
||||||
await fs.unlink(path.join(filesdir(), folder, file));
|
await fs.unlink(path.join(filesdir(), folder, file));
|
||||||
socket.emitChanged(`files-changed-${folder}`);
|
socket.emitChanged(`files-changed-${folder}`);
|
||||||
socket.emitChanged(`all-files-changed`);
|
socket.emitChanged(`all-files-changed`);
|
||||||
|
return true;
|
||||||
},
|
},
|
||||||
|
|
||||||
rename_meta: true,
|
rename_meta: true,
|
||||||
async rename({ folder, file, newFile }) {
|
async rename({ folder, file, newFile }) {
|
||||||
if (!hasPermission(`files/${folder}/write`)) return;
|
if (!hasPermission(`files/${folder}/write`)) return false;
|
||||||
await fs.rename(path.join(filesdir(), folder, file), path.join(filesdir(), folder, newFile));
|
await fs.rename(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`);
|
||||||
|
return true;
|
||||||
},
|
},
|
||||||
|
|
||||||
copy_meta: true,
|
copy_meta: true,
|
||||||
async copy({ folder, file, newFile }) {
|
async copy({ folder, file, newFile }) {
|
||||||
if (!hasPermission(`files/${folder}/write`)) return;
|
if (!hasPermission(`files/${folder}/write`)) 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`);
|
||||||
|
return true;
|
||||||
},
|
},
|
||||||
|
|
||||||
load_meta: true,
|
load_meta: true,
|
||||||
@@ -90,11 +93,13 @@ module.exports = {
|
|||||||
save_meta: true,
|
save_meta: true,
|
||||||
async save({ folder, file, data, format }) {
|
async save({ folder, file, data, format }) {
|
||||||
if (folder.startsWith('archive:')) {
|
if (folder.startsWith('archive:')) {
|
||||||
|
if (!hasPermission(`archive/write`)) 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.substring('archive:'.length)}`);
|
socket.emitChanged(`archive-files-changed-${folder.substring('archive:'.length)}`);
|
||||||
return true;
|
return true;
|
||||||
} else if (folder.startsWith('app:')) {
|
} else if (folder.startsWith('app:')) {
|
||||||
|
if (!hasPermission(`apps/write`)) 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}`);
|
||||||
|
|||||||
@@ -1,16 +1,38 @@
|
|||||||
import _escapeRegExp from 'lodash/escapeRegExp';
|
import _escapeRegExp from 'lodash/escapeRegExp';
|
||||||
import _isString from 'lodash/isString';
|
import _isString from 'lodash/isString';
|
||||||
|
import _compact from 'lodash/compact';
|
||||||
|
|
||||||
export function compilePermissions(permissions: string[] | string) {
|
interface CompiledPermissions {
|
||||||
|
revoke: RegExp;
|
||||||
|
allow: RegExp;
|
||||||
|
}
|
||||||
|
|
||||||
|
function compileRegexp(permissions) {
|
||||||
|
if (permissions.length == 0) return null;
|
||||||
|
return new RegExp(permissions.map(x => '^' + _escapeRegExp(x).replace(/\\\*/g, '.*') + '$').join('|'));
|
||||||
|
}
|
||||||
|
|
||||||
|
export function compilePermissions(permissions: string[] | string): CompiledPermissions {
|
||||||
if (!permissions) return null;
|
if (!permissions) return null;
|
||||||
if (_isString(permissions)) permissions = permissions.split(',');
|
if (_isString(permissions)) permissions = permissions.split(',');
|
||||||
return permissions.map(x => new RegExp('^' + _escapeRegExp(x).replace(/\\\*/g, '.*') + '$'));
|
permissions = _compact(permissions.map(x => x.trim()));
|
||||||
|
const revoke = permissions.filter(x => x.startsWith('~')).map(x => x.substring(1));
|
||||||
|
const allow = permissions.filter(x => !x.startsWith('~'));
|
||||||
|
return {
|
||||||
|
revoke: compileRegexp(revoke),
|
||||||
|
allow: compileRegexp(allow),
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export function testPermission(tested: string, permissions: RegExp[]) {
|
export function testPermission(tested: string, permissions: CompiledPermissions) {
|
||||||
if (!permissions) return true;
|
if (!permissions) return true;
|
||||||
for (const permission of permissions) {
|
if (!permissions.revoke) return true;
|
||||||
if (tested.match(permission)) return true;
|
|
||||||
}
|
if (tested.match(permissions.revoke)) {
|
||||||
|
if (!tested.match(permissions.allow)) {
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
import { currentDropDownMenu, selectedWidget, visibleCommandPalette, visibleHamburgerMenuWidget } from '../stores';
|
import { currentDropDownMenu, selectedWidget, visibleCommandPalette, visibleHamburgerMenuWidget } from '../stores';
|
||||||
import mainMenuDefinition from '../../../../app/src/mainMenuDefinition';
|
import mainMenuDefinition from '../../../../app/src/mainMenuDefinition';
|
||||||
import { useConfig } from '../utility/metadataLoaders';
|
import { useConfig } from '../utility/metadataLoaders';
|
||||||
|
import hasPermission from '../utility/hasPermission';
|
||||||
|
|
||||||
let domSettings;
|
let domSettings;
|
||||||
let domMainMenu;
|
let domMainMenu;
|
||||||
@@ -88,7 +89,7 @@
|
|||||||
<FontIcon icon="icon menu" />
|
<FontIcon icon="icon menu" />
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
{#each widgets.filter(x => !$config?.hideAppEditor || x.name != 'app') as item}
|
{#each widgets.filter(x => hasPermission(`widgets/${x.name}`)) as item}
|
||||||
<div class="wrapper" class:selected={item.name == $selectedWidget} on:click={() => handleChangeWidget(item.name)}>
|
<div class="wrapper" class:selected={item.name == $selectedWidget} on:click={() => handleChangeWidget(item.name)}>
|
||||||
<FontIcon icon={item.icon} title={item.title} />
|
<FontIcon icon={item.icon} title={item.title} />
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user