mirror of https://github.com/Squidex/squidex.git
40 changed files with 369 additions and 610 deletions
@ -0,0 +1,39 @@ |
|||||
|
// ==========================================================================
|
||||
|
// Squidex Headless CMS
|
||||
|
// ==========================================================================
|
||||
|
// Copyright (c) Squidex UG (haftungsbeschraenkt)
|
||||
|
// All rights reserved. Licensed under the MIT license.
|
||||
|
// ==========================================================================
|
||||
|
|
||||
|
using Squidex.Areas.Api.Controllers.Backups; |
||||
|
using Squidex.Areas.Api.Controllers.EventConsumers; |
||||
|
using Squidex.Shared; |
||||
|
using Squidex.Web; |
||||
|
|
||||
|
namespace Squidex.Areas.Api.Controllers.Users.Models |
||||
|
{ |
||||
|
public sealed class ResourcesDto : Resource |
||||
|
{ |
||||
|
public static ResourcesDto FromController(ApiController controller) |
||||
|
{ |
||||
|
var result = new ResourcesDto(); |
||||
|
|
||||
|
if (controller.HasPermission(Permissions.AdminEventsRead)) |
||||
|
{ |
||||
|
result.AddGetLink("admin/eventConsumers", controller.Url<EventConsumersController>(x => nameof(x.GetEventConsumers))); |
||||
|
} |
||||
|
|
||||
|
if (controller.HasPermission(Permissions.AdminRestoreRead)) |
||||
|
{ |
||||
|
result.AddGetLink("admin/restore", controller.Url<RestoreController>(x => nameof(x.GetJob))); |
||||
|
} |
||||
|
|
||||
|
if (controller.HasPermission(Permissions.AdminUsersRead)) |
||||
|
{ |
||||
|
result.AddGetLink("admin/users", controller.Url<UserManagementController>(x => nameof(x.GetUsers))); |
||||
|
} |
||||
|
|
||||
|
return result; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -1,145 +0,0 @@ |
|||||
/* |
|
||||
* Squidex Headless CMS |
|
||||
* |
|
||||
* @license |
|
||||
* Copyright (c) Squidex UG (haftungsbeschränkt). All rights reserved. |
|
||||
*/ |
|
||||
|
|
||||
import { Permission } from './permission'; |
|
||||
|
|
||||
describe('Permission', () => { |
|
||||
it('should check when permissions are not equal', () => { |
|
||||
const g = new Permission('app.contents'); |
|
||||
const r = new Permission('app.assets'); |
|
||||
|
|
||||
expect(g.allows(r)).toBeFalsy(); |
|
||||
|
|
||||
expect(g.includes(r)).toBeFalsy(); |
|
||||
}); |
|
||||
|
|
||||
it('should check when permissions are equal with wildcards', () => { |
|
||||
const g = new Permission('app.*'); |
|
||||
const r = new Permission('app.*'); |
|
||||
|
|
||||
expect(g.allows(r)).toBeTruthy(); |
|
||||
|
|
||||
expect(g.includes(r)).toBeTruthy(); |
|
||||
}); |
|
||||
|
|
||||
it('should check when equal permissions', () => { |
|
||||
const g = new Permission('app.contents'); |
|
||||
const r = new Permission('app.contents'); |
|
||||
|
|
||||
expect(g.allows(r)).toBeTruthy(); |
|
||||
|
|
||||
expect(g.includes(r)).toBeTruthy(); |
|
||||
}); |
|
||||
|
|
||||
it('should check when given is parent of requested', () => { |
|
||||
const g = new Permission('app'); |
|
||||
const r = new Permission('app.contents'); |
|
||||
|
|
||||
expect(g.allows(r)).toBeTruthy(); |
|
||||
|
|
||||
expect(g.includes(r)).toBeTruthy(); |
|
||||
}); |
|
||||
|
|
||||
it('should check when requested is parent of given', () => { |
|
||||
const g = new Permission('app.contents'); |
|
||||
const r = new Permission('app'); |
|
||||
|
|
||||
expect(g.allows(r)).toBeFalsy(); |
|
||||
|
|
||||
expect(g.includes(r)).toBeTruthy(); |
|
||||
}); |
|
||||
|
|
||||
it('should check when given is wildcard of requested', () => { |
|
||||
const g = new Permission('app.*'); |
|
||||
const r = new Permission('app.contents'); |
|
||||
|
|
||||
expect(g.allows(r)).toBeTruthy(); |
|
||||
|
|
||||
expect(g.includes(r)).toBeTruthy(); |
|
||||
}); |
|
||||
|
|
||||
it('should check when requested is wildcard of given', () => { |
|
||||
const g = new Permission('app.contents'); |
|
||||
const r = new Permission('app.*'); |
|
||||
|
|
||||
expect(g.allows(r)).toBeFalsy(); |
|
||||
|
|
||||
expect(g.includes(r)).toBeTruthy(); |
|
||||
}); |
|
||||
|
|
||||
it('should check when given is has alternatives of requested', () => { |
|
||||
const g = new Permission('app.contents|schemas'); |
|
||||
const r = new Permission('app.contents'); |
|
||||
|
|
||||
expect(g.allows(r)).toBeTruthy(); |
|
||||
|
|
||||
expect(g.includes(r)).toBeTruthy(); |
|
||||
}); |
|
||||
|
|
||||
it('should check when requested is has alternatives of given', () => { |
|
||||
const g = new Permission('app.contents'); |
|
||||
const r = new Permission('app.contents|schemas'); |
|
||||
|
|
||||
expect(g.allows(r)).toBeTruthy(); |
|
||||
|
|
||||
expect(g.includes(r)).toBeTruthy(); |
|
||||
}); |
|
||||
|
|
||||
|
|
||||
it('should check for requested is null', () => { |
|
||||
const g = new Permission('app.contents'); |
|
||||
|
|
||||
expect(g.allows(null!)).toBeFalsy(); |
|
||||
|
|
||||
expect(g.includes(null!)).toBeFalsy(); |
|
||||
}); |
|
||||
|
|
||||
it('should return true if any permission gives permission to requested', () => { |
|
||||
const set = [ |
|
||||
new Permission('app.contents'), |
|
||||
new Permission('app.assets') |
|
||||
]; |
|
||||
|
|
||||
expect(new Permission('app.contents').allowedBy(set)).toBeTruthy(); |
|
||||
}); |
|
||||
|
|
||||
it('should return true if any permission includes parent given', () => { |
|
||||
const set = [ |
|
||||
new Permission('app.contents'), |
|
||||
new Permission('app.assets') |
|
||||
]; |
|
||||
|
|
||||
expect(new Permission('app').includedIn(set)).toBeTruthy(); |
|
||||
}); |
|
||||
|
|
||||
it('should return true if any permission includes child given', () => { |
|
||||
const set = [ |
|
||||
new Permission('app.contents'), |
|
||||
new Permission('app.assets') |
|
||||
]; |
|
||||
|
|
||||
expect(new Permission('app.contents.read').includedIn(set)).toBeTruthy(); |
|
||||
}); |
|
||||
|
|
||||
it('should return false if none permission gives permission to requested', () => { |
|
||||
const set = [ |
|
||||
new Permission('app.contents'), |
|
||||
new Permission('app.assets') |
|
||||
]; |
|
||||
|
|
||||
expect(new Permission('app.schemas').allowedBy(set)).toBeFalsy(); |
|
||||
}); |
|
||||
|
|
||||
it('should return false if none permission includes given', () => { |
|
||||
const set = [ |
|
||||
new Permission('app.contents'), |
|
||||
new Permission('app.assets') |
|
||||
]; |
|
||||
|
|
||||
expect(new Permission('other').allowedBy(set)).toBeFalsy(); |
|
||||
}); |
|
||||
}); |
|
||||
@ -1,116 +0,0 @@ |
|||||
/* |
|
||||
* Squidex Headless CMS |
|
||||
* |
|
||||
* @license |
|
||||
* Copyright (c) Squidex UG (haftungsbeschränkt). All rights reserved. |
|
||||
*/ |
|
||||
|
|
||||
import { Types } from './types'; |
|
||||
|
|
||||
export class Permission { |
|
||||
private readonly parts: ({ [key: string]: true } | null)[]; |
|
||||
|
|
||||
constructor( |
|
||||
public readonly id: string |
|
||||
) { |
|
||||
this.parts = id.split('.').map(x => { |
|
||||
if (x === '*') { |
|
||||
return null; |
|
||||
} else { |
|
||||
const result: { [key: string]: true } = {}; |
|
||||
|
|
||||
for (let p of x.split('|')) { |
|
||||
result[p] = true; |
|
||||
} |
|
||||
|
|
||||
return result; |
|
||||
} |
|
||||
}); |
|
||||
} |
|
||||
|
|
||||
public includedIn(permissions: Permission[]) { |
|
||||
for (let permission of permissions) { |
|
||||
if (permission.includes(this)) { |
|
||||
return true; |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
return false; |
|
||||
} |
|
||||
|
|
||||
public allowedBy(permissions: Permission[]) { |
|
||||
for (let permission of permissions) { |
|
||||
if (permission.allows(this)) { |
|
||||
return true; |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
return false; |
|
||||
} |
|
||||
|
|
||||
public includes(permission?: Permission | string) { |
|
||||
if (!permission) { |
|
||||
return false; |
|
||||
} |
|
||||
|
|
||||
if (Types.isString(permission)) { |
|
||||
permission = new Permission(permission); |
|
||||
} |
|
||||
|
|
||||
for (let i = 0; i < Math.min(permission.parts.length, this.parts.length); i++) { |
|
||||
const lhs = this.parts[i]; |
|
||||
const rhs = permission.parts[i]; |
|
||||
|
|
||||
if (lhs != null && rhs != null && !Permission.intersects(lhs, rhs)) { |
|
||||
return false; |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
return true; |
|
||||
} |
|
||||
|
|
||||
public allows(permission?: Permission | string) { |
|
||||
if (!permission) { |
|
||||
return false; |
|
||||
} |
|
||||
|
|
||||
if (Types.isString(permission)) { |
|
||||
permission = new Permission(permission); |
|
||||
} |
|
||||
|
|
||||
if (this.parts.length > permission.parts.length) { |
|
||||
return false; |
|
||||
} |
|
||||
|
|
||||
for (let i = 0; i < this.parts.length; i++) { |
|
||||
const lhs = this.parts[i]; |
|
||||
const rhs = permission.parts[i]; |
|
||||
|
|
||||
if (lhs !== null && (rhs === null || !Permission.intersects(lhs, rhs))) { |
|
||||
return false; |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
return true; |
|
||||
} |
|
||||
|
|
||||
private static intersects(lhs: { [key: string]: true }, rhs: { [key: string]: true }) { |
|
||||
for (let key in lhs) { |
|
||||
if (lhs.hasOwnProperty(key)) { |
|
||||
if (rhs[key]) { |
|
||||
return true; |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
for (let key in rhs) { |
|
||||
if (rhs.hasOwnProperty(key)) { |
|
||||
if (lhs[key]) { |
|
||||
return true; |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
return false; |
|
||||
} |
|
||||
} |
|
||||
@ -1,133 +0,0 @@ |
|||||
/* |
|
||||
* Squidex Headless CMS |
|
||||
* |
|
||||
* @license |
|
||||
* Copyright (c) Squidex UG (haftungsbeschränkt). All rights reserved. |
|
||||
*/ |
|
||||
|
|
||||
import { ChangeDetectorRef, Directive, Input, OnChanges, OnInit, TemplateRef, ViewContainerRef } from '@angular/core'; |
|
||||
|
|
||||
import { |
|
||||
AppDto, |
|
||||
AppsState, |
|
||||
AuthService, |
|
||||
Permission, |
|
||||
ResourceOwner, |
|
||||
SchemaDto, |
|
||||
SchemasState |
|
||||
} from '@app/shared/internal'; |
|
||||
|
|
||||
@Directive({ |
|
||||
selector: '[sqxPermission]' |
|
||||
}) |
|
||||
export class PermissionDirective extends ResourceOwner implements OnChanges, OnInit { |
|
||||
private viewCreated = false; |
|
||||
|
|
||||
@Input('sqxPermissionApp') |
|
||||
public app?: AppDto; |
|
||||
|
|
||||
@Input('sqxPermissionSchema') |
|
||||
public schema?: SchemaDto; |
|
||||
|
|
||||
@Input('sqxPermission') |
|
||||
public permissions: string; |
|
||||
|
|
||||
constructor( |
|
||||
private readonly authService: AuthService, |
|
||||
private readonly appsState: AppsState, |
|
||||
private readonly changeDetector: ChangeDetectorRef, |
|
||||
private readonly schemasState: SchemasState, |
|
||||
private readonly templateRef: TemplateRef<any>, |
|
||||
private readonly viewContainer: ViewContainerRef |
|
||||
) { |
|
||||
super(); |
|
||||
} |
|
||||
|
|
||||
public ngOnInit() { |
|
||||
this.own( |
|
||||
this.appsState.selectedApp.subscribe(app => { |
|
||||
if (app && !this.app) { |
|
||||
this.update(app, this.schemasState.snapshot.selectedSchema); |
|
||||
} |
|
||||
})); |
|
||||
|
|
||||
this.own( |
|
||||
this.schemasState.selectedSchema.subscribe(schema => { |
|
||||
if (schema && !this.schema) { |
|
||||
this.update(this.appsState.snapshot.selectedApp, schema); |
|
||||
} |
|
||||
})); |
|
||||
} |
|
||||
|
|
||||
public ngOnChanges() { |
|
||||
this.update(this.appsState.snapshot.selectedApp, this.schemasState.snapshot.selectedSchema); |
|
||||
} |
|
||||
|
|
||||
private update(app?: AppDto | null, schema?: SchemaDto | null) { |
|
||||
if (this.app) { |
|
||||
app = this.app; |
|
||||
} |
|
||||
|
|
||||
if (this.schema) { |
|
||||
schema = this.schema; |
|
||||
} |
|
||||
|
|
||||
let permissions = this.permissions; |
|
||||
|
|
||||
let show = false; |
|
||||
|
|
||||
if (permissions) { |
|
||||
let include = permissions[0] === '?'; |
|
||||
|
|
||||
if (include) { |
|
||||
permissions = permissions.substr(1); |
|
||||
} |
|
||||
|
|
||||
const array = permissions.split(';'); |
|
||||
|
|
||||
for (let id of array) { |
|
||||
if (app) { |
|
||||
id = id.replace('{app}', app.name); |
|
||||
} |
|
||||
|
|
||||
if (schema) { |
|
||||
id = id.replace('{name}', schema.name); |
|
||||
} |
|
||||
|
|
||||
const permission = new Permission(id); |
|
||||
|
|
||||
if (include) { |
|
||||
if (app && permission.includedIn(app.permissions)) { |
|
||||
show = true; |
|
||||
} |
|
||||
|
|
||||
if (!show) { |
|
||||
show = permission.includedIn(this.authService.user!.permissions); |
|
||||
} |
|
||||
} else { |
|
||||
if (app && permission.allowedBy(app.permissions)) { |
|
||||
show = true; |
|
||||
} |
|
||||
|
|
||||
if (!show) { |
|
||||
show = permission.allowedBy(this.authService.user!.permissions); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
if (show) { |
|
||||
break; |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
if (show && !this.viewCreated) { |
|
||||
this.viewContainer.createEmbeddedView(this.templateRef); |
|
||||
this.viewCreated = true; |
|
||||
} else if (!show && this.viewCreated) { |
|
||||
this.viewContainer.clear(); |
|
||||
this.viewCreated = false; |
|
||||
} |
|
||||
|
|
||||
this.changeDetector.markForCheck(); |
|
||||
} |
|
||||
} |
|
||||
Loading…
Reference in new issue