ChengLei Shao bd285e0ba9
Plugin acl (#166)
* feat: getRepository

* getRepository return type

* export action

* add: acl

* feat: setResourceAction

* feat: action alias

* chore: code struct

* feat: removeResourceAction

* chore: file name

* ignorecase

* remove ACL

* feat: ACL

* feat: role toJSON

* using emit

* chore: test

* feat: plugin-acl

* feat: acl with predicate

* grant universal action test

* grant action test

* update resource action test

* revoke resource action

* usingActionsConfig switch

* plugin-ui-schema-storage

* remove global acl instance

* fix: collection manager with sqlite

* add own action listener

* add acl middleware

* add acl allowConfigure strategy option

* add plugin-acl allowConfigure

* change acl resourceName

* add acl middleware merge params

* bugfix

* append fields on acl action params

* acl middleware parse template

* fix: collection-manager migrate

Co-authored-by: chenos <chenlinxh@gmail.com>
2022-01-24 14:10:35 +08:00

403 lines
8.5 KiB
TypeScript

import { ACL } from '..';
describe('acl', () => {
let acl: ACL;
beforeEach(() => {
acl = new ACL();
});
it('should grant action with own params', () => {
acl.setAvailableAction('edit', {
type: 'old-data',
});
acl.setAvailableAction('create', {
type: 'new-data',
});
acl.define({
role: 'admin',
actions: {
'posts:edit': {
own: true,
},
},
});
const canResult = acl.can({ role: 'admin', resource: 'posts', action: 'edit' });
expect(canResult).toMatchObject({
role: 'admin',
resource: 'posts',
action: 'edit',
params: {
filter: {
createdById: '{{ ctx.state.currentUser.id }}',
},
},
});
});
it('should define role with predicate', () => {
acl.setAvailableAction('edit', {
type: 'old-data',
});
acl.setAvailableAction('create', {
type: 'new-data',
});
acl.define({
role: 'admin',
strategy: {
actions: ['edit:own', 'create'],
},
});
const canResult = acl.can({ role: 'admin', resource: 'posts', action: 'edit' });
expect(canResult).toMatchObject({
role: 'admin',
resource: 'posts',
action: 'edit',
params: {
filter: {
createdById: '{{ ctx.state.currentUser.id }}',
},
},
});
});
it('should allow all', () => {
acl.setAvailableAction('create', {
type: 'new-data',
});
acl.setAvailableAction('edit', {
type: 'old-data',
});
acl.setAvailableStrategy('s1', {
displayName: 's1',
actions: '*',
});
acl.define({
role: 'admin',
strategy: 's1',
});
expect(acl.can({ role: 'admin', resource: 'posts', action: 'create' })).toMatchObject({
role: 'admin',
resource: 'posts',
action: 'create',
});
});
it('should deny all', () => {
acl.setAvailableStrategy('s1', {
displayName: 'test',
actions: false,
});
acl.define({
role: 'admin',
strategy: 's1',
});
expect(acl.can({ role: 'admin', resource: 'posts', action: 'create' })).toBeNull();
});
it('should deny when action is not available action', () => {
acl.setAvailableStrategy('s1', {
displayName: 'test',
actions: false,
});
const role = acl.define({
role: 'admin',
strategy: 's1',
});
expect(acl.can({ role: 'admin', resource: 'posts', action: 'create' })).toBeNull();
role.grantAction('posts:create', {});
expect(acl.can({ role: 'admin', resource: 'posts', action: 'create' })).toBeNull();
});
it('should grant action when define role', () => {
acl.setAvailableAction('create', {
displayName: 'create',
type: 'new-data',
});
acl.setAvailableStrategy('s1', {
displayName: 'test',
actions: false,
});
const role = acl.define({
role: 'admin',
strategy: 's1',
actions: {
'posts:create': {},
},
});
expect(acl.can({ role: 'admin', resource: 'posts', action: 'create' })).toMatchObject({
role: 'admin',
resource: 'posts',
action: 'create',
});
});
it('should grant action', function () {
acl.setAvailableAction('create', {
displayName: 'create',
type: 'new-data',
});
acl.setAvailableStrategy('s1', {
displayName: 'test',
actions: false,
});
const role = acl.define({
role: 'admin',
strategy: 's1',
});
expect(acl.can({ role: 'admin', resource: 'posts', action: 'create' })).toBeNull();
role.grantAction('posts:create', {});
expect(acl.can({ role: 'admin', resource: 'posts', action: 'create' })).toMatchObject({
role: 'admin',
resource: 'posts',
action: 'create',
});
});
it('should works with alias action', () => {
acl.setAvailableAction('view', {
displayName: 'view',
type: 'new-data',
aliases: ['get', 'list'],
});
acl.setAvailableStrategy('s1', {
displayName: 'test',
actions: ['view'],
});
const role = acl.define({
role: 'admin',
strategy: 's1',
});
expect(acl.can({ role: 'admin', resource: 'posts', action: 'get' })).toMatchObject({
role: 'admin',
resource: 'posts',
action: 'get',
});
expect(acl.can({ role: 'admin', resource: 'posts', action: 'list' })).toMatchObject({
role: 'admin',
resource: 'posts',
action: 'list',
});
});
it('should return action params when check permission', () => {
acl.setAvailableStrategy('s2', {
displayName: 'view create update',
actions: ['view', 'create', 'update'],
});
acl.setAvailableAction('view', { type: 'new-data' });
acl.setAvailableAction('create', { type: 'new-data' });
acl.setAvailableAction('update', { type: 'new-data' });
acl.define({
role: 'admin',
strategy: 's2',
actions: {
'posts:view': {
filter: {
createdById: '{{ ctx.state.currentUser.id }}',
},
},
},
});
const canResult = acl.can({ role: 'admin', resource: 'posts', action: 'view' });
expect(canResult).toMatchObject({
role: 'admin',
resource: 'posts',
action: 'view',
params: {
filter: {
createdById: '{{ ctx.state.currentUser.id }}',
},
},
});
});
it('should getActionParams', () => {
acl.setAvailableStrategy('s2', {
displayName: 'view create update',
actions: ['view', 'create', 'update'],
});
acl.setAvailableAction('view', { type: 'new-data' });
acl.setAvailableAction('create', { type: 'new-data' });
acl.setAvailableAction('update', { type: 'new-data' });
const role = acl.define({
role: 'admin',
strategy: 's2',
actions: {
'posts:view': {
filter: {
createdById: '{{ ctx.state.currentUser.id }}',
},
},
},
});
const params = role.getActionParams('posts:view');
expect(params).toMatchObject({
filter: {
createdById: '{{ ctx.state.currentUser.id }}',
},
});
});
it('should revoke action', () => {
acl.setAvailableAction('create', {
displayName: 'create',
type: 'new-data',
});
acl.setAvailableStrategy('s1', {
displayName: 'test',
actions: false,
});
const role = acl.define({
role: 'admin',
strategy: 's1',
});
role.grantAction('posts:create', {});
expect(acl.can({ role: 'admin', resource: 'posts', action: 'create' })).toMatchObject({
role: 'admin',
resource: 'posts',
action: 'create',
});
role.revokeAction('posts:create');
expect(acl.can({ role: 'admin', resource: 'posts', action: 'create' })).toBeNull();
});
it('should call beforeGrantAction', () => {
acl.setAvailableAction('create', {
type: 'old-data',
});
acl.beforeGrantAction((ctx) => {
if (ctx.path === 'posts:create') {
ctx.params = {
filter: {
status: 'publish',
},
};
}
});
acl.define({
role: 'admin',
actions: {
'posts:create': {},
},
});
const results = acl.can({ role: 'admin', resource: 'posts', action: 'create' });
expect(results).toMatchObject({
role: 'admin',
resource: 'posts',
action: 'create',
params: {
filter: {
status: 'publish',
},
},
});
});
it('should to JSON', () => {
acl.setAvailableAction('create', {
displayName: 'create',
type: 'new-data',
});
acl.setAvailableStrategy('s1', {
displayName: 'test',
actions: false,
});
const role = acl.define({
role: 'admin',
strategy: 's1',
actions: {
'posts:create': {
filter: { a: 'b' },
},
},
});
const roleJSON = role.toJSON();
expect(roleJSON).toMatchObject({
role: 'admin',
strategy: 's1',
actions: {
'posts:create': {},
},
});
});
it('should allow system config', () => {
acl.setAvailableAction('create', {
displayName: 'create',
type: 'new-data',
});
acl.registerConfigResources(['roles']);
const role = acl.define({
role: 'admin',
strategy: {
allowConfigure: true,
},
});
expect(
acl.can({
role: 'admin',
resource: 'roles',
action: 'create',
}),
).toMatchObject({
role: 'admin',
resource: 'roles',
action: 'create',
});
});
});