@plumier/core
Advanced tools
Comparing version 1.0.0-dev11.14 to 1.0.0-dev11.15
@@ -1,6 +0,6 @@ | ||
import { ActionResult, Invocation, Middleware, RouteInfo, AuthorizeMetadataInfo } from "./types"; | ||
declare type AuthorizeCallback = (info: AuthorizeMetadataInfo, location: "Class" | "Parameter" | "Method") => boolean | Promise<boolean>; | ||
import { AuthorizationContext, ActionContext, RouteInfo, Configuration } from "./types"; | ||
declare type AuthorizerFunction = (info: AuthorizationContext, location: "Class" | "Parameter" | "Method") => boolean | Promise<boolean>; | ||
interface AuthorizeDecorator { | ||
type: "plumier-meta:authorize"; | ||
authorize: string | AuthorizeCallback | Authorizer; | ||
authorize: string | AuthorizerFunction | Authorizer; | ||
tag: string; | ||
@@ -10,15 +10,8 @@ location: "Class" | "Parameter" | "Method"; | ||
interface Authorizer { | ||
authorize(info: AuthorizeMetadataInfo, location: "Class" | "Parameter" | "Method"): boolean | Promise<boolean>; | ||
authorize(info: AuthorizationContext, location: "Class" | "Parameter" | "Method"): boolean | Promise<boolean>; | ||
} | ||
declare type RoleField = string | ((value: any) => Promise<string[]>); | ||
declare function updateRouteAccess(routes: RouteInfo[], globals?: (...args: any[]) => void): void; | ||
declare class AuthorizeMiddleware implements Middleware { | ||
private roleField; | ||
private global?; | ||
constructor(roleField: RoleField, global?: ((...args: any[]) => void) | undefined); | ||
private getRole; | ||
private checkUserAccessToRoute; | ||
private checkUserAccessToParameters; | ||
execute(invocation: Readonly<Invocation>): Promise<ActionResult>; | ||
} | ||
export { AuthorizeCallback, RoleField, Authorizer, updateRouteAccess, AuthorizeMiddleware, AuthorizeDecorator }; | ||
declare function getAuthorizeDecorators(info: RouteInfo, globalDecorator?: (...args: any[]) => void): AuthorizeDecorator[]; | ||
declare function updateRouteAuthorizationAccess(routes: RouteInfo[], config: Configuration): void; | ||
declare function checkAuthorize(ctx: ActionContext): Promise<void>; | ||
export { AuthorizerFunction, RoleField, Authorizer, checkAuthorize, AuthorizeDecorator, getAuthorizeDecorators, updateRouteAuthorizationAccess }; |
@@ -47,2 +47,3 @@ "use strict"; | ||
} | ||
exports.getAuthorizeDecorators = getAuthorizeDecorators; | ||
async function checkParameter(path, meta, value, info) { | ||
@@ -84,61 +85,55 @@ if (value === undefined) | ||
} | ||
async function checkUserAccessToRoute(decorators, info) { | ||
if (decorators.some(x => x.tag === "Public")) | ||
return; | ||
if (info.role.length === 0) | ||
throw new types_1.HttpStatusError(http_status_1.HttpStatus.Forbidden, "Forbidden"); | ||
const conditions = await Promise.all(decorators.map(x => executeDecorator(x, info))); | ||
//use OR condition | ||
//if ALL condition doesn't authorize user then throw | ||
if (conditions.length > 0 && conditions.every(x => x === false)) | ||
throw new types_1.HttpStatusError(http_status_1.HttpStatus.Unauthorized, "Unauthorized"); | ||
} | ||
async function checkUserAccessToParameters(meta, values, info) { | ||
const unauthorizedPaths = await checkParameters([], meta, values, info); | ||
if (unauthorizedPaths.length > 0) | ||
throw new types_1.HttpStatusError(401, `Unauthorized to populate parameter paths (${unauthorizedPaths.join(", ")})`); | ||
} | ||
async function getRole(user, roleField) { | ||
if (!user) | ||
return []; | ||
if (typeof roleField === "function") | ||
return await roleField(user); | ||
else { | ||
const role = user[roleField]; | ||
return Array.isArray(role) ? role : [role]; | ||
} | ||
} | ||
/* ------------------------------------------------------------------------------- */ | ||
/* --------------------------- MAIN IMPLEMENTATION ------------------------------- */ | ||
/* ------------------------------------------------------------------------------- */ | ||
function updateRouteAccess(routes, globals) { | ||
routes.forEach(x => { | ||
const decorators = getAuthorizeDecorators(x, globals); | ||
if (decorators.length > 0) | ||
x.access = decorators.map(x => x.tag).join("|"); | ||
else | ||
x.access = "Authenticated"; | ||
}); | ||
function updateRouteAuthorizationAccess(routes, config) { | ||
if (config.enableAuthorization) { | ||
routes.forEach(x => { | ||
const decorators = getAuthorizeDecorators(x, config.globalAuthorizationDecorators); | ||
if (decorators.length > 0) | ||
x.access = decorators.map(x => x.tag).join("|"); | ||
else | ||
x.access = "Authenticated"; | ||
}); | ||
} | ||
} | ||
exports.updateRouteAccess = updateRouteAccess; | ||
class AuthorizeMiddleware { | ||
constructor(roleField, global) { | ||
this.roleField = roleField; | ||
this.global = global; | ||
} | ||
async getRole(user) { | ||
if (!user) | ||
return []; | ||
if (typeof this.roleField === "function") | ||
return await this.roleField(user); | ||
else { | ||
const role = user[this.roleField]; | ||
return Array.isArray(role) ? role : [role]; | ||
} | ||
} | ||
async checkUserAccessToRoute(decorators, info) { | ||
if (decorators.some(x => x.tag === "Public")) | ||
return; | ||
if (info.role.length === 0) | ||
throw new types_1.HttpStatusError(http_status_1.HttpStatus.Forbidden, "Forbidden"); | ||
const conditions = await Promise.all(decorators.map(x => executeDecorator(x, info))); | ||
//use OR condition | ||
//if ALL condition doesn't authorize user then throw | ||
if (conditions.length > 0 && conditions.every(x => x === false)) | ||
throw new types_1.HttpStatusError(http_status_1.HttpStatus.Unauthorized, "Unauthorized"); | ||
} | ||
async checkUserAccessToParameters(meta, values, info) { | ||
const unauthorizedPaths = await checkParameters([], meta, values, info); | ||
if (unauthorizedPaths.length > 0) | ||
throw new types_1.HttpStatusError(401, `Unauthorized to populate parameter paths (${unauthorizedPaths.join(", ")})`); | ||
} | ||
async execute(invocation) { | ||
if (!invocation.context.route) | ||
return invocation.proceed(); | ||
const { route, parameters, state } = invocation.context; | ||
const decorator = getAuthorizeDecorators(invocation.context.route, this.global); | ||
const userRoles = await this.getRole(invocation.context.state.user); | ||
const info = { role: userRoles, parameters, user: state.user, route, ctx: invocation.context }; | ||
exports.updateRouteAuthorizationAccess = updateRouteAuthorizationAccess; | ||
async function checkAuthorize(ctx) { | ||
if (ctx.config.enableAuthorization) { | ||
const { route, parameters, state, config } = ctx; | ||
const decorator = getAuthorizeDecorators(route, config.globalAuthorizationDecorators); | ||
const userRoles = await getRole(state.user, config.roleField); | ||
const info = { role: userRoles, user: state.user, route, ctx }; | ||
//check user access | ||
await this.checkUserAccessToRoute(decorator, info); | ||
await checkUserAccessToRoute(decorator, info); | ||
//if ok check parameter access | ||
await this.checkUserAccessToParameters(invocation.context.route.action.parameters, invocation.context.parameters, info); | ||
//if all above passed then proceed | ||
return invocation.proceed(); | ||
await checkUserAccessToParameters(route.action.parameters, parameters, info); | ||
} | ||
} | ||
exports.AuthorizeMiddleware = AuthorizeMiddleware; | ||
exports.checkAuthorize = checkAuthorize; |
/// <reference types="node" /> | ||
import { IncomingHttpHeaders } from "http"; | ||
import { Context, Request } from "koa"; | ||
import { ParameterReflection } from "tinspector"; | ||
interface BindingDecorator { | ||
@@ -17,3 +16,3 @@ type: "ParameterBinding"; | ||
} | ||
declare const binder: (ctx: Context, par: ParameterReflection) => any; | ||
declare function binder(ctx: Context): any[]; | ||
export { RequestPart, HeaderPart, BindingDecorator, binder }; |
@@ -27,3 +27,6 @@ "use strict"; | ||
} | ||
const binder = chain(bindDecorator, bindByName, bindBody); | ||
const binderChain = chain(bindDecorator, bindByName, bindBody); | ||
function binder(ctx) { | ||
return ctx.route.action.parameters.map(x => binderChain(ctx, x)); | ||
} | ||
exports.binder = binder; |
@@ -18,2 +18,2 @@ declare type Class = new (...args: any[]) => any; | ||
declare function findFilesRecursive(path: string): string[]; | ||
export { getChildValue, Class, hasKeyOf, isCustomClass, consoleLog, findFilesRecursive, }; | ||
export { getChildValue, Class, hasKeyOf, isCustomClass, consoleLog, findFilesRecursive }; |
@@ -1,4 +0,4 @@ | ||
import { AuthorizeCallback, Authorizer } from "./authorization"; | ||
import { AuthorizerFunction, Authorizer } from "./authorization"; | ||
declare class AuthDecoratorImpl { | ||
custom(callback: AuthorizeCallback, tag?: string): (...args: any[]) => void; | ||
custom(callback: AuthorizerFunction, tag?: string): (...args: any[]) => void; | ||
custom(authorizer: Authorizer, tag?: string): (...args: any[]) => void; | ||
@@ -5,0 +5,0 @@ custom(id: string, tag?: string): (...args: any[]) => void; |
import { val } from "typedconverter"; | ||
export { val }; | ||
export { AuthorizeCallback, AuthorizeMiddleware, RoleField, updateRouteAccess, Authorizer } from "./authorization"; | ||
export { AuthorizerFunction, checkAuthorize, RoleField, Authorizer } from "./authorization"; | ||
export { HeaderPart, RequestPart, BindingDecorator, binder } from "./binder"; | ||
export { invoke } from "./middleware-pipeline"; | ||
export { invoke } from "./application-pipeline"; | ||
export { response } from "./response"; | ||
export { analyzeRoutes, generateRoutes, printAnalysis } from "./route-generator"; | ||
export { generateRoutes } from "./route-generator"; | ||
export { analyzeRoutes, printAnalysis } from "./route-analyzer"; | ||
export { router } from "./router"; | ||
export { ValidationMiddleware } from "./validator"; | ||
export { Class, consoleLog, findFilesRecursive, getChildValue, hasKeyOf, isCustomClass } from "./common"; | ||
@@ -16,2 +16,2 @@ export { AuthDecoratorImpl, authorize } from "./decorator.authorize"; | ||
export { HttpStatus } from "./http-status"; | ||
export { ActionResult, Application, AuthorizeMetadataInfo, Configuration, DefaultFacility, CustomValidator, DependencyResolver, Facility, FileParser, FileUploadInfo, HttpMethod, HttpStatusError, Invocation, KoaMiddleware, Middleware, MiddlewareFunction, MiddlewareDecorator, MiddlewareUtil, PlumierApplication, PlumierConfiguration, RedirectActionResult, RouteContext, RouteInfo, RouteAnalyzerFunction, RouteAnalyzerIssue, ValidatorDecorator, ValidatorFunction, ValidatorInfo, ValidationError, errorMessage, AsyncValidatorResult, DefaultDependencyResolver } from "./types"; | ||
export { ActionResult, Application, AuthorizationContext as AuthorizationContext, Configuration, DefaultFacility, CustomValidator, DependencyResolver, Facility, FileParser, FileUploadInfo, HttpMethod, HttpStatusError, Invocation, KoaMiddleware, Middleware, MiddlewareFunction, MiddlewareDecorator, MiddlewareUtil, PlumierApplication, PlumierConfiguration, RedirectActionResult, ActionContext, RouteInfo, RouteAnalyzerFunction, RouteAnalyzerIssue, ValidatorDecorator, CustomValidatorFunction as CustomValidatorFunction, ValidatorContext, ValidationError, errorMessage, AsyncValidatorResult, DefaultDependencyResolver } from "./types"; |
@@ -6,18 +6,16 @@ "use strict"; | ||
var authorization_1 = require("./authorization"); | ||
exports.AuthorizeMiddleware = authorization_1.AuthorizeMiddleware; | ||
exports.updateRouteAccess = authorization_1.updateRouteAccess; | ||
exports.checkAuthorize = authorization_1.checkAuthorize; | ||
var binder_1 = require("./binder"); | ||
exports.binder = binder_1.binder; | ||
var middleware_pipeline_1 = require("./middleware-pipeline"); | ||
exports.invoke = middleware_pipeline_1.invoke; | ||
var application_pipeline_1 = require("./application-pipeline"); | ||
exports.invoke = application_pipeline_1.invoke; | ||
var response_1 = require("./response"); | ||
exports.response = response_1.response; | ||
var route_generator_1 = require("./route-generator"); | ||
exports.analyzeRoutes = route_generator_1.analyzeRoutes; | ||
exports.generateRoutes = route_generator_1.generateRoutes; | ||
exports.printAnalysis = route_generator_1.printAnalysis; | ||
var route_analyzer_1 = require("./route-analyzer"); | ||
exports.analyzeRoutes = route_analyzer_1.analyzeRoutes; | ||
exports.printAnalysis = route_analyzer_1.printAnalysis; | ||
var router_1 = require("./router"); | ||
exports.router = router_1.router; | ||
var validator_1 = require("./validator"); | ||
exports.ValidationMiddleware = validator_1.ValidationMiddleware; | ||
var common_1 = require("./common"); | ||
@@ -24,0 +22,0 @@ exports.consoleLog = common_1.consoleLog; |
import { Class } from "./common"; | ||
import { HttpMethod, RouteInfo, RouteAnalyzerIssue, RouteAnalyzerFunction } from "./types"; | ||
import { HttpMethod, RouteInfo } from "./types"; | ||
interface RouteDecorator { | ||
@@ -15,9 +15,3 @@ name: "Route"; | ||
} | ||
interface TestResult { | ||
route: RouteInfo; | ||
issues: RouteAnalyzerIssue[]; | ||
} | ||
declare function generateRoutes(executionPath: string, controller: string | Class[] | Class): RouteInfo[]; | ||
declare function analyzeRoutes(routes: RouteInfo[], extensions?: RouteAnalyzerFunction[]): TestResult[]; | ||
declare function printAnalysis(results: TestResult[]): void; | ||
export { analyzeRoutes, generateRoutes, printAnalysis, RouteDecorator, IgnoreDecorator, RootDecorator }; | ||
export { generateRoutes, RouteDecorator, IgnoreDecorator, RootDecorator }; |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
const tslib_1 = require("tslib"); | ||
const chalk_1 = tslib_1.__importDefault(require("chalk")); | ||
const fs_1 = require("fs"); | ||
@@ -34,5 +32,2 @@ const path_1 = require("path"); | ||
} | ||
function getActionName(route) { | ||
return `${route.controller.name}.${route.action.name}(${route.action.parameters.map(x => x.name).join(", ")})`; | ||
} | ||
function getRoot(rootPath, path) { | ||
@@ -125,143 +120,1 @@ const part = path.slice(rootPath.length).split("/").filter(x => !!x) | ||
exports.generateRoutes = generateRoutes; | ||
/* ------------------------------------------------------------------------------- */ | ||
/* --------------------------- ANALYZER FUNCTION --------------------------------- */ | ||
/* ------------------------------------------------------------------------------- */ | ||
//------ Analyzer Helpers | ||
function getModelsInParameters(par) { | ||
return par | ||
.map((x, i) => ({ type: x.type, index: i })) | ||
.filter(x => x.type && common_1.isCustomClass(x.type)) | ||
.map(x => ({ meta: tinspector_1.reflect((Array.isArray(x.type) ? x.type[0] : x.type)), index: x.index })); | ||
} | ||
function traverseModel(par) { | ||
const models = getModelsInParameters(par).map(x => x.meta); | ||
const child = models.map(x => traverseModel(x.properties)) | ||
.filter((x) => Boolean(x)) | ||
.reduce((a, b) => a.concat(b), []); | ||
return models.concat(child); | ||
} | ||
function traverseArray(parent, par) { | ||
const models = getModelsInParameters(par); | ||
if (models.length > 0) { | ||
return models.map((x, i) => traverseArray(x.meta.name, x.meta.properties)) | ||
.flatten(); | ||
} | ||
return par.filter(x => x.type === Array) | ||
.map(x => `${parent}.${x.name}`); | ||
} | ||
function backingParameterTest(route, allRoutes) { | ||
const ids = route.url.split("/") | ||
.filter(x => x.startsWith(":")) | ||
.map(x => x.substring(1).toLowerCase()); | ||
const missing = ids.filter(id => route.action.parameters.map(x => x.name.toLowerCase()).indexOf(id) === -1); | ||
if (missing.length > 0) { | ||
return { | ||
type: "error", | ||
message: types_1.errorMessage.RouteDoesNotHaveBackingParam.format(missing.join(", ")) | ||
}; | ||
} | ||
else | ||
return { type: "success" }; | ||
} | ||
function metadataTypeTest(route, allRoutes) { | ||
const hasTypeInfo = route.action | ||
.parameters.some(x => Boolean(x.type)); | ||
if (!hasTypeInfo && route.action.parameters.length > 0) { | ||
return { | ||
type: "warning", | ||
message: types_1.errorMessage.ActionDoesNotHaveTypeInfo | ||
}; | ||
} | ||
else | ||
return { type: "success" }; | ||
} | ||
function duplicateRouteTest(route, allRoutes) { | ||
const dup = allRoutes.filter(x => x.url == route.url && x.method == route.method); | ||
if (dup.length > 1) { | ||
return { | ||
type: "error", | ||
message: types_1.errorMessage.DuplicateRouteFound.format(dup.map(x => getActionName(x)).join(" ")) | ||
}; | ||
} | ||
else | ||
return { type: "success" }; | ||
} | ||
function modelTypeInfoTest(route, allRoutes) { | ||
const classes = traverseModel(route.action.parameters) | ||
.filter(x => x.properties.every(par => typeof par.type == "undefined")) | ||
.map(x => x.type); | ||
//get only unique type | ||
const noTypeInfo = Array.from(new Set(classes)); | ||
if (noTypeInfo.length > 0) { | ||
return { | ||
type: "warning", | ||
message: types_1.errorMessage.ModelWithoutTypeInformation.format(noTypeInfo.map(x => x.name).join(", ")) | ||
}; | ||
} | ||
else | ||
return { type: "success" }; | ||
} | ||
function arrayTypeInfoTest(route, allRoutes) { | ||
const issues = traverseArray(`${route.controller.name}.${route.action.name}`, route.action.parameters); | ||
const array = Array.from(new Set(issues)); | ||
if (array.length > 0) { | ||
return { | ||
type: "warning", | ||
message: types_1.errorMessage.ArrayWithoutTypeInformation.format(array.join(", ")) | ||
}; | ||
} | ||
else | ||
return { type: 'success' }; | ||
} | ||
/* ------------------------------------------------------------------------------- */ | ||
/* -------------------------------- ANALYZER ------------------------------------- */ | ||
/* ------------------------------------------------------------------------------- */ | ||
function analyzeRoute(route, tests, allRoutes) { | ||
const issues = tests.map(test => { | ||
return test(route, allRoutes); | ||
}) | ||
.filter(x => x.type != "success"); | ||
return { route, issues }; | ||
} | ||
function analyzeRoutes(routes, extensions = []) { | ||
const tests = [ | ||
backingParameterTest, metadataTypeTest, | ||
duplicateRouteTest, modelTypeInfoTest, | ||
arrayTypeInfoTest | ||
]; | ||
return routes.map(x => analyzeRoute(x, tests.concat(extensions), routes)); | ||
} | ||
exports.analyzeRoutes = analyzeRoutes; | ||
function printAnalysis(results) { | ||
const data = results.map(x => { | ||
const method = x.route.method.toUpperCase(); | ||
const action = getActionName(x.route); | ||
const issues = x.issues.map(issue => ` - ${issue.type} ${issue.message}`); | ||
return { method, url: x.route.url, action, issues, access: x.route.access }; | ||
}); | ||
console.log(); | ||
console.log("Route Analysis Report"); | ||
if (data.length == 0) | ||
console.log("No controller found"); | ||
const paddings = { | ||
number: data.length.toString().length, | ||
action: Math.max(...data.map(x => x.action.length)), | ||
method: Math.max(...data.map(x => x.method.length)), | ||
access: Math.max(...data.map(x => x.access && x.access.length || 0)), | ||
}; | ||
data.forEach((x, i) => { | ||
const num = (i + 1).toString().padStart(paddings.number); | ||
const action = x.action.padEnd(paddings.action); | ||
const method = x.method.padEnd(paddings.method); | ||
const access = x.access && (" " + x.access.padEnd(paddings.access)) || ""; | ||
const color = x.issues.length === 0 ? (x) => x : x.issues.some(x => x.startsWith(" - error")) ? chalk_1.default.red : chalk_1.default.yellow; | ||
console.log(color(`${num}. ${action} ->${access} ${method} ${x.url}`)); | ||
x.issues.forEach(x => { | ||
const color = x.startsWith(" - warning") ? chalk_1.default.yellow : chalk_1.default.red; | ||
console.log(color(x)); | ||
}); | ||
}); | ||
if (data.length > 0) | ||
console.log(); | ||
} | ||
exports.printAnalysis = printAnalysis; |
@@ -5,3 +5,3 @@ "use strict"; | ||
const tinspector_1 = require("tinspector"); | ||
const middleware_pipeline_1 = require("./middleware-pipeline"); | ||
const application_pipeline_1 = require("./application-pipeline"); | ||
const types_1 = require("./types"); | ||
@@ -46,3 +46,3 @@ // --------------------------------------------------------------------- // | ||
} | ||
const result = await middleware_pipeline_1.pipe(ctx, ctx.route); | ||
const result = await application_pipeline_1.pipe(ctx); | ||
await result.execute(ctx); | ||
@@ -49,0 +49,0 @@ } |
@@ -7,2 +7,3 @@ import Koa, { Context } from "koa"; | ||
import { SetOption } from 'cookies'; | ||
import { RoleField } from './authorization'; | ||
export declare class ActionResult { | ||
@@ -47,3 +48,3 @@ body?: any; | ||
export interface Invocation { | ||
context: Readonly<Context>; | ||
ctx: Readonly<Context>; | ||
proceed(): Promise<ActionResult>; | ||
@@ -56,3 +57,2 @@ } | ||
config: Readonly<Configuration>; | ||
parameters?: any[]; | ||
} | ||
@@ -63,3 +63,3 @@ interface DefaultState { | ||
} | ||
export interface RouteContext extends Context { | ||
export interface ActionContext extends Context { | ||
route: Readonly<RouteInfo>; | ||
@@ -151,7 +151,7 @@ parameters: any[]; | ||
type: "ValidatorDecorator"; | ||
validator: ValidatorFunction | string | symbol; | ||
validator: CustomValidatorFunction | string | symbol; | ||
} | ||
export interface ValidatorInfo { | ||
export interface ValidatorContext { | ||
name: string; | ||
ctx: RouteContext; | ||
ctx: ActionContext; | ||
parent?: { | ||
@@ -167,11 +167,11 @@ value: any; | ||
} | ||
export declare type ValidatorFunction = (value: any, info: ValidatorInfo) => undefined | string | AsyncValidatorResult[] | Promise<AsyncValidatorResult[] | string | undefined>; | ||
export declare type CustomValidatorFunction = (value: any, info: ValidatorContext) => undefined | string | AsyncValidatorResult[] | Promise<AsyncValidatorResult[] | string | undefined>; | ||
export interface CustomValidator { | ||
validate(value: any, info: ValidatorInfo): undefined | string | AsyncValidatorResult[] | Promise<AsyncValidatorResult[] | string | undefined>; | ||
validate(value: any, info: ValidatorContext): undefined | string | AsyncValidatorResult[] | Promise<AsyncValidatorResult[] | string | undefined>; | ||
} | ||
export interface AuthorizeMetadataInfo { | ||
export interface AuthorizationContext { | ||
value?: any; | ||
role: string[]; | ||
user: any; | ||
ctx: RouteContext; | ||
ctx: ActionContext; | ||
} | ||
@@ -220,2 +220,14 @@ export interface FileUploadInfo { | ||
analyzers?: RouteAnalyzerFunction[]; | ||
/** | ||
* Role field / function used to specify current login user role inside JWT claim for authorization | ||
*/ | ||
roleField: RoleField; | ||
/** | ||
* Global authorization decorators, use mergeDecorator for multiple | ||
*/ | ||
globalAuthorizationDecorators?: (...args: any[]) => void; | ||
/** | ||
* Enable/disable authorization, when enabled all routes will be private by default. Default false | ||
*/ | ||
enableAuthorization: boolean; | ||
} | ||
@@ -222,0 +234,0 @@ export interface PlumierConfiguration extends Configuration { |
@@ -67,7 +67,7 @@ "use strict"; | ||
execute: async (x) => { | ||
await middleware(x.context, async () => { | ||
await middleware(x.ctx, async () => { | ||
const nextResult = await x.proceed(); | ||
await nextResult.execute(x.context); | ||
await nextResult.execute(x.ctx); | ||
}); | ||
return ActionResult.fromContext(x.context); | ||
return ActionResult.fromContext(x.ctx); | ||
} | ||
@@ -74,0 +74,0 @@ }; |
@@ -1,16 +0,12 @@ | ||
import { ActionResult, AsyncValidatorResult, Invocation, Middleware, ValidatorFunction, CustomValidator } from "./types"; | ||
import { AsyncValidatorResult, CustomValidator, ActionContext, CustomValidatorFunction } from "./types"; | ||
declare module "typedconverter" { | ||
namespace val { | ||
function custom(validator: ValidatorFunction): (...arg: any[]) => void; | ||
function custom(validator: CustomValidatorFunction): (...arg: any[]) => void; | ||
function custom(validator: CustomValidator): (...arg: any[]) => void; | ||
function custom(id: string): (...arg: any[]) => void; | ||
function custom(id: symbol): (...arg: any[]) => void; | ||
function custom(val: ValidatorFunction | string | symbol | CustomValidator): (...arg: any[]) => void; | ||
function result(path: string, messages: string | string[]): AsyncValidatorResult[]; | ||
} | ||
} | ||
declare class ValidationMiddleware implements Middleware { | ||
constructor(); | ||
execute(invocation: Readonly<Invocation>): Promise<ActionResult>; | ||
} | ||
export { ValidationMiddleware }; | ||
declare function validate(ctx: ActionContext): Promise<any[]>; | ||
export { validate }; |
@@ -6,3 +6,2 @@ "use strict"; | ||
const tc = tslib_1.__importStar(require("typedconverter")); | ||
const binder_1 = require("./binder"); | ||
const common_1 = require("./common"); | ||
@@ -65,4 +64,4 @@ const types_1 = require("./types"); | ||
//sync validations | ||
for (const parMeta of ctx.route.action.parameters) { | ||
const rawParameter = binder_1.binder(ctx, parMeta); | ||
for (const [index, parMeta] of ctx.route.action.parameters.entries()) { | ||
const rawParameter = ctx.parameters[index]; | ||
const parValue = tc.validate(rawParameter, { | ||
@@ -87,21 +86,6 @@ decorators: parMeta.decorators, path: parMeta.name, type: parMeta.type || Object, | ||
} | ||
return (issues.length > 0) ? { issues, value: undefined } : { value: result }; | ||
if (issues.length > 0) | ||
throw new types_1.ValidationError(issues.map(x => ({ path: x.path.split("."), messages: x.messages }))); | ||
return result; | ||
} | ||
// --------------------------------------------------------------------- // | ||
// ----------------------------- MIDDLEWARE ---------------------------- // | ||
// --------------------------------------------------------------------- // | ||
class ValidationMiddleware { | ||
constructor() { } | ||
async execute(invocation) { | ||
const ctx = invocation.context; | ||
if (!ctx.route) | ||
return invocation.proceed(); | ||
const result = await validate(invocation.context); | ||
if (result.issues) | ||
throw new types_1.ValidationError(result.issues | ||
.map(x => ({ path: x.path.split("."), messages: x.messages }))); | ||
ctx.parameters = result.value; | ||
return invocation.proceed(); | ||
} | ||
} | ||
exports.ValidationMiddleware = ValidationMiddleware; | ||
exports.validate = validate; |
{ | ||
"name": "@plumier/core", | ||
"version": "1.0.0-dev11.14+feae170", | ||
"version": "1.0.0-dev11.15+7313eb2", | ||
"description": "Delightful Node.js Rest Framework", | ||
@@ -41,3 +41,3 @@ "main": "lib/index.js", | ||
}, | ||
"gitHead": "feae170e8302c3db06c54ad4f34df84a904aacd8", | ||
"gitHead": "7313eb26d1992e5ffa25402fce8230f05e79743b", | ||
"devDependencies": { | ||
@@ -44,0 +44,0 @@ "upath": "^1.2.0" |
Manifest confusion
Supply chain riskThis package has inconsistent metadata. This could be malicious or caused by an error when publishing the package.
Found 1 instance in 1 package
Manifest confusion
Supply chain riskThis package has inconsistent metadata. This could be malicious or caused by an error when publishing the package.
Found 1 instance in 1 package
35
123879
2837