Skip to content

Commit

Permalink
Merge 0ad4bd8 into b3af0ad
Browse files Browse the repository at this point in the history
  • Loading branch information
jonathan-casarrubias committed May 2, 2018
2 parents b3af0ad + 0ad4bd8 commit 822b8b2
Show file tree
Hide file tree
Showing 6 changed files with 110 additions and 32 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@onixjs/core",
"version": "1.0.0-alpha.22.2",
"version": "1.0.0-alpha.23",
"description": "An Enterprise Grade NodeJS Platform that implements Industry Standards and Patterns in order to provide Connectivity, Stability, High-Availability and High-Performance.",
"main": "dist/src/index.js",
"scripts": {
Expand Down
35 changes: 29 additions & 6 deletions src/core/acl.group.match.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import {
promiseSeries,
IACLRule,
IGroup,
Injector,
IModuleConfig,
} from '..';
/**
* @class GroupMatch
Expand All @@ -22,32 +24,53 @@ export class GroupMatch {
* component ACL Configuration and the operation request.
*/
static async verify(
// Name of method to be executed
name: string,
// Application operation reference
operation: IAppOperation,
config: IComponentConfig,
// Module level configurations
moduleConfig: IModuleConfig,
// Component level configurations
componentConfig: IComponentConfig,
// Scoped injector, it will inject module level dependencies
injector: Injector,
) {
// Verify the parent component provides an ACL Configuration
if (Array.isArray(config.acl)) {
if (Array.isArray(componentConfig.acl)) {
// Need to await the result to allow finding a truthy result
return (await promiseSeries(
// Iterate over given ACL Rules
config.acl.map((Rule: new () => IACLRule) => async () => {
componentConfig.acl.map((Rule: new () => IACLRule) => async () => {
// Need an instance from this rule class.
const rule: IACLRule = new Rule();
let rule: IACLRule | null = new Rule();
// Make sure this method has any group associated
// Or there is a whildcard for any component method
if (rule.methods.find(value => value === name || value === '*')) {
// Await for group async operations, so we can find thruthy results
const results = await promiseSeries(
rule.groups.map(Group => async () => {
const group: IGroup = new Group();
// Create group instance
let group: IGroup | null = new Group();
// Inject whatever has been requested into this group
await injector.inject(Group, group, moduleConfig);
// Execute group access method to verify operation request access
return group.access(operation.message.request, rule.access);
const groupResult: boolean = await group.access(
operation.message.request,
rule!.access,
);
// Wipe group instance
group = null;
// return group results
return groupResult;
}),
);
// Wipe ACL Rule instance
rule = null;
// Find if any of the group results gave access for this method.
return results.find(value => value === true) ? true : false;
} else {
// Wipe ACL Rule instance
rule = null;
// Don't give access if there is no group associated for this method
return false;
}
Expand Down
46 changes: 35 additions & 11 deletions src/core/call.responser.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
import {ReflectionKeys, IAppOperation, IComponentConfig} from '../interfaces';
import {
ReflectionKeys,
IAppOperation,
IComponentConfig,
IModuleConfig,
} from '../interfaces';
import {AppFactory, LifeCycle} from '../core';
import {GroupMatch} from './acl.group.match';
//import { RoleMatch } from './roles';
Expand Down Expand Up @@ -43,12 +48,25 @@ export class CallResponser {
return;
}
// Declare executable endpoint method and hooks references
let scope,
let // Declare Operation Scope
scope,
// Declare Current Module Default Config
moduleConfig: IModuleConfig = {
components: [],
models: [],
services: [],
renderers: [],
},
// Define a flag for systemcalls, to override ACL access
systemcall: boolean = false,
// Define reference for the method to be executed
method: Function | null = null,
// Define a main hook, it refers to a module level hook
mainHook: Function = () => null,
// Define a slave hook, it refers to a component level hook
slaveHook: Function | null = null,
config: IComponentConfig = {};
// Declare a reference for the executing component config
componentConfig: IComponentConfig = {};
// If segments are exactly 2, then it is an application level call
// Only god can remotly execute this type of calls.
if (segments.length === 2) {
Expand All @@ -61,10 +79,7 @@ export class CallResponser {
if (segments.length > 2) {
scope = this.factory.app.modules[segments[1]];
method = this.factory.app.modules[segments[1]][segments[2]];
const moduleConfig = Reflect.getMetadata(
ReflectionKeys.MODULE_CONFIG,
scope,
);
moduleConfig = Reflect.getMetadata(ReflectionKeys.MODULE_CONFIG, scope);
mainHook = moduleConfig.lifecycle
? moduleConfig.lifecycle
: this.lifecycle.onModuleMethodCall;
Expand All @@ -76,9 +91,12 @@ export class CallResponser {
segments[3]
];
if (scope && method) {
config = Reflect.getMetadata(ReflectionKeys.COMPONENT_CONFIG, scope);
slaveHook = config.lifecycle
? config.lifecycle
componentConfig = Reflect.getMetadata(
ReflectionKeys.COMPONENT_CONFIG,
scope,
);
slaveHook = componentConfig.lifecycle
? componentConfig.lifecycle
: this.lifecycle.onComponentMethodCall;
}
}
Expand All @@ -93,7 +111,13 @@ export class CallResponser {
}
// Verify the call request matches the ACL Rules
if (
(await GroupMatch.verify(method.name, operation, config)) ||
(await GroupMatch.verify(
method.name,
operation,
moduleConfig,
componentConfig,
this.factory.scopes[segments[1]],
)) ||
systemcall
) {
// Execute main hook, might be app/system or module level.
Expand Down
44 changes: 32 additions & 12 deletions src/core/call.streamer.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import {AppFactory} from './app.factory';
import {IAppOperation, IComponentConfig} from '../interfaces';
import {IAppOperation, IComponentConfig, IModuleConfig} from '../interfaces';
import {LifeCycle} from '.';
import {ReflectionKeys} from '..';
import {GroupMatch} from './acl.group.match';
Expand All @@ -24,12 +24,24 @@ export class CallStreamer {
* to send back an answer.
*/
async register(operation: IAppOperation, handler) {
// Get segments from rpc endpoint
let scope,
// Declare executable endpoint method and hooks references
let // Declare Operation Scope
scope,
// Declare Current Module Default Config
moduleConfig: IModuleConfig = {
components: [],
models: [],
services: [],
renderers: [],
},
// Define reference for the method to be executed
method: Function | null = null,
// Define a main hook, it refers to a module level hook
mainHook: Function = () => null,
// Define a slave hook, it refers to a component level hook
slaveHook: Function | null = null,
config: IComponentConfig = {};
// Declare a reference for the executing component config
componentConfig: IComponentConfig = {};

const segments: string[] = operation.message.rpc.split('.');
// Component level method, RPC Exposed
Expand All @@ -44,10 +56,7 @@ export class CallStreamer {
if (segments.length > 2) {
scope = this.factory.app.modules[segments[1]];
method = this.factory.app.modules[segments[1]][segments[2]];
const moduleConfig = Reflect.getMetadata(
ReflectionKeys.MODULE_CONFIG,
scope,
);
moduleConfig = Reflect.getMetadata(ReflectionKeys.MODULE_CONFIG, scope);
mainHook = moduleConfig.lifecycle
? moduleConfig.lifecycle
: this.lifecycle.onModuleMethodStream;
Expand All @@ -57,9 +66,12 @@ export class CallStreamer {
scope = this.factory.app.modules[segments[1]][segments[2]];
method = this.factory.app.modules[segments[1]][segments[2]][segments[3]];
if (scope && method) {
config = Reflect.getMetadata(ReflectionKeys.COMPONENT_CONFIG, scope);
slaveHook = config.lifecycle
? config.lifecycle
componentConfig = Reflect.getMetadata(
ReflectionKeys.COMPONENT_CONFIG,
scope,
);
slaveHook = componentConfig.lifecycle
? componentConfig.lifecycle
: this.lifecycle.onComponentMethodStream;
}
}
Expand All @@ -73,7 +85,15 @@ export class CallStreamer {
}

// Verify the call request matches the ACL Rules
if (await GroupMatch.verify(method.name, operation, config)) {
if (
await GroupMatch.verify(
method.name,
operation,
moduleConfig,
componentConfig,
this.factory.scopes[segments[1]],
)
) {
// Default handler
const def = data => data;
// Execute main hook, might be app/system or module level.
Expand Down
2 changes: 1 addition & 1 deletion src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ export class OnixJS {
* @description Current Onix Version.
*/
get version(): string {
return '1.0.0-alpha.22.2';
return '1.0.0-alpha.23';
}
/**
* @property router
Expand Down
13 changes: 12 additions & 1 deletion test/onixjs.core.unit.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1388,7 +1388,18 @@ test('CORE: ACL Group Match', async t => {
acl: [AllowEveryone],
};
// VERIFY ACCESS
const hasAccess: boolean = await GroupMatch.verify(name, operation, config);
const hasAccess: boolean = await GroupMatch.verify(
name,
operation,
{
components: [],
services: [],
models: [],
renderers: [],
},
config,
new Injector(),
);
// TEST IF HAS ACCESS
t.true(hasAccess);
});

0 comments on commit 822b8b2

Please sign in to comment.