From d91f362d96c0a2a8020b1c05d6475851d4bfd85f Mon Sep 17 00:00:00 2001 From: Raymond Feng Date: Wed, 28 Mar 2018 11:22:06 -0700 Subject: [PATCH 01/10] feat: add authorization component --- packages/authorization/.npmrc | 1 + packages/authorization/LICENSE | 25 +++ packages/authorization/README.md | 56 ++++++ packages/authorization/docs.json | 12 ++ packages/authorization/index.d.ts | 6 + packages/authorization/index.js | 6 + packages/authorization/index.ts | 8 + packages/authorization/package-lock.json | 27 +++ packages/authorization/package.json | 49 +++++ .../acceptance/authorization.acceptance.ts | 124 ++++++++++++ .../unit/authorize-decorator.test.ts | 135 +++++++++++++ .../src/authorization-component.ts | 11 ++ .../src/authorize-interceptor.ts | 68 +++++++ .../authorization/src/decorators/authorize.ts | 165 ++++++++++++++++ packages/authorization/src/index.ts | 10 + packages/authorization/src/keys.ts | 11 ++ packages/authorization/src/types.ts | 179 ++++++++++++++++++ packages/authorization/tsconfig.build.json | 9 + 18 files changed, 902 insertions(+) create mode 100644 packages/authorization/.npmrc create mode 100644 packages/authorization/LICENSE create mode 100644 packages/authorization/README.md create mode 100644 packages/authorization/docs.json create mode 100644 packages/authorization/index.d.ts create mode 100644 packages/authorization/index.js create mode 100644 packages/authorization/index.ts create mode 100644 packages/authorization/package-lock.json create mode 100644 packages/authorization/package.json create mode 100644 packages/authorization/src/__tests__/acceptance/authorization.acceptance.ts create mode 100644 packages/authorization/src/__tests__/unit/authorize-decorator.test.ts create mode 100644 packages/authorization/src/authorization-component.ts create mode 100644 packages/authorization/src/authorize-interceptor.ts create mode 100644 packages/authorization/src/decorators/authorize.ts create mode 100644 packages/authorization/src/index.ts create mode 100644 packages/authorization/src/keys.ts create mode 100644 packages/authorization/src/types.ts create mode 100644 packages/authorization/tsconfig.build.json diff --git a/packages/authorization/.npmrc b/packages/authorization/.npmrc new file mode 100644 index 000000000000..cafe685a112d --- /dev/null +++ b/packages/authorization/.npmrc @@ -0,0 +1 @@ +package-lock=true diff --git a/packages/authorization/LICENSE b/packages/authorization/LICENSE new file mode 100644 index 000000000000..af99ad048201 --- /dev/null +++ b/packages/authorization/LICENSE @@ -0,0 +1,25 @@ +Copyright (c) IBM Corp. 2018. All Rights Reserved. +Node module: @loopback/authorization +This project is licensed under the MIT License, full text below. + +-------- + +MIT license + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/packages/authorization/README.md b/packages/authorization/README.md new file mode 100644 index 000000000000..826d31b386d7 --- /dev/null +++ b/packages/authorization/README.md @@ -0,0 +1,56 @@ +# @loopback/authorization + +A LoopBack 4 component for authorization support. + +**This is a reference implementation showing how to implement an authorization +component, it is not production ready.** + +## Overview + +## Installation + +```shell +npm install --save @loopback/authorization +``` + +## Basic use + +Start by decorating your controller methods with `@authorize` to require the +request to be authorized. + +In this example, we make the user profile available via dependency injection +using a key available from `@loopback/authorization` package. + +```ts +import {inject} from '@loopback/context'; +import {authorize} from '@loopback/authorization'; +import {get} from '@loopback/rest'; + +export class MyController { + @authorize({allow: ['ADMIN']}) + @get('/number-of-views') + numOfViews(): number { + return 100; + } +} +``` + +## Related resources + +## Contributions + +- [Guidelines](https://github.com/strongloop/loopback-next/blob/master/docs/CONTRIBUTING.md) +- [Join the team](https://github.com/strongloop/loopback-next/issues/110) + +## Tests + +run `npm test` from the root folder. + +## Contributors + +See +[all contributors](https://github.com/strongloop/loopback-next/graphs/contributors). + +## License + +MIT diff --git a/packages/authorization/docs.json b/packages/authorization/docs.json new file mode 100644 index 000000000000..0ce80ef8469d --- /dev/null +++ b/packages/authorization/docs.json @@ -0,0 +1,12 @@ +{ + "content": [ + "index.ts", + "src/index.ts", + "src/decorators/authorize.ts", + "src/providers/authorization-metadata.ts", + "src/providers/authorize.ts", + "src/authorization-component.ts", + "src/keys.ts" + ], + "codeSectionDepth": 4 +} diff --git a/packages/authorization/index.d.ts b/packages/authorization/index.d.ts new file mode 100644 index 000000000000..026b9d7c9ffc --- /dev/null +++ b/packages/authorization/index.d.ts @@ -0,0 +1,6 @@ +// Copyright IBM Corp. 2017,2018. All Rights Reserved. +// Node module: @loopback/authorization +// This file is licensed under the MIT License. +// License text available at https://opensource.org/licenses/MIT + +export * from './dist'; diff --git a/packages/authorization/index.js b/packages/authorization/index.js new file mode 100644 index 000000000000..28622def8c06 --- /dev/null +++ b/packages/authorization/index.js @@ -0,0 +1,6 @@ +// Copyright IBM Corp. 2017,2018. All Rights Reserved. +// Node module: @loopback/authorization +// This file is licensed under the MIT License. +// License text available at https://opensource.org/licenses/MIT + +module.exports = require('./dist'); diff --git a/packages/authorization/index.ts b/packages/authorization/index.ts new file mode 100644 index 000000000000..f81c156a7f3f --- /dev/null +++ b/packages/authorization/index.ts @@ -0,0 +1,8 @@ +// Copyright IBM Corp. 2017,2018. All Rights Reserved. +// Node module: @loopback/authorization +// This file is licensed under the MIT License. +// License text available at https://opensource.org/licenses/MIT + +// DO NOT EDIT THIS FILE +// Add any additional (re)exports to src/index.ts instead. +export * from './src'; diff --git a/packages/authorization/package-lock.json b/packages/authorization/package-lock.json new file mode 100644 index 000000000000..316be2d826b0 --- /dev/null +++ b/packages/authorization/package-lock.json @@ -0,0 +1,27 @@ +{ + "name": "@loopback/authorization", + "version": "0.1.0", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "@types/debug": { + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.4.tgz", + "integrity": "sha512-D9MyoQFI7iP5VdpEyPZyjjqIJ8Y8EDNQFIFVLOmeg1rI1xiHOChyUPMPRUVfqFCerxfE+yS3vMyj37F6IdtOoQ==", + "dev": true + }, + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "requires": { + "ms": "^2.1.1" + } + }, + "ms": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", + "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==" + } + } +} diff --git a/packages/authorization/package.json b/packages/authorization/package.json new file mode 100644 index 000000000000..87de20934c99 --- /dev/null +++ b/packages/authorization/package.json @@ -0,0 +1,49 @@ +{ + "name": "@loopback/authorization", + "version": "0.1.0", + "description": "A LoopBack component for authorization support.", + "engines": { + "node": ">=8" + }, + "scripts": { + "acceptance": "lb-mocha \"dist/__tests__/acceptance/**/*.js\"", + "build": "lb-tsc es2017 --outDir dist", + "build:apidocs": "lb-apidocs", + "clean": "lb-clean loopback-authorization*.tgz dist package api-docs", + "integration": "lb-mocha \"dist/__tests__/integration/**/*.js\"", + "prepublishOnly": "npm run build && npm run build:apidocs", + "pretest": "npm run build", + "test": "lb-mocha \"dist/__tests__/**/*.js\"", + "unit": "lb-mocha \"dist/__tests__/unit/**/*.js\"", + "verify": "npm pack && tar xf loopback-authorization*.tgz && tree package && npm run clean" + }, + "author": "IBM", + "copyright.owner": "IBM Corp.", + "license": "MIT", + "dependencies": { + "@loopback/context": "^1.13.0", + "@loopback/core": "^1.6.2", + "debug": "^4.1.1" + }, + "devDependencies": { + "@loopback/build": "^1.5.2", + "@loopback/testlab": "^1.2.7", + "@types/debug": "^4.1.4" + }, + "keywords": [ + "LoopBack", + "Authorization" + ], + "files": [ + "README.md", + "index.js", + "index.d.ts", + "dist", + "src", + "!*/__tests__" + ], + "repository": { + "type": "git", + "url": "https://github.com/strongloop/loopback-next.git" + } +} diff --git a/packages/authorization/src/__tests__/acceptance/authorization.acceptance.ts b/packages/authorization/src/__tests__/acceptance/authorization.acceptance.ts new file mode 100644 index 000000000000..a363631b3c06 --- /dev/null +++ b/packages/authorization/src/__tests__/acceptance/authorization.acceptance.ts @@ -0,0 +1,124 @@ +// Copyright IBM Corp. 2019. All Rights Reserved. +// Node module: @loopback/authorization +// This file is licensed under the MIT License. +// License text available at https://opensource.org/licenses/MIT + +import {Context, invokeMethod, Provider} from '@loopback/context'; +import {Application} from '@loopback/core'; +import {expect} from '@loopback/testlab'; +import {AuthorizationComponent} from '../../authorization-component'; +import {authorize} from '../../decorators/authorize'; +import { + AuthorizationDecision, + AuthorizationMetadata, + AuthorizeFn, + EVERYONE, + AuthorizationContext, +} from '../../types'; + +describe('Authorization', () => { + let app: Application; + let controller: OrderController; + let reqCtx: Context; + let events: string[]; + + before(givenApplication); + beforeEach(givenRequestContext); + + it('allows placeOrder for everyone', async () => { + const orderId = await invokeMethod(controller, 'placeOrder', reqCtx, [ + { + customerId: 'customer-01', + productId: 'product-a', + quantity: 10, + price: 320, + }, + ]); + expect(orderId).to.eql('order-1'); + expect(events).to.containEql('OrderController.prototype.placeOrder'); + }); + + it('denies cancelOrder for regular user', async () => { + const result = invokeMethod(controller, 'cancelOrder', reqCtx, [ + 'order-01', + ]); + await expect(result).to.be.rejectedWith('Access denied'); + expect(events).to.containEql('OrderController.prototype.cancelOrder'); + }); + + class Order { + id?: string; + customerId: string; + productId: string; + quantity: number; + price: number; + } + + class OrderController { + orders: Order[] = []; + + @authorize({allowedRoles: [EVERYONE], scopes: ['order.create']}) + async placeOrder(order: Order) { + order.id = `order-${this.orders.length + 1}`; + this.orders.push(order); + return order.id; + } + + @authorize({allowedRoles: ['customer-service'], scopes: ['order.delete']}) + async cancelOrder(orderId: string) { + const index = this.orders.findIndex(order => order.id === orderId); + if (index === -1) return false; + this.orders.splice(index, 1); + return true; + } + } + + function givenApplication() { + app = new Application(); + app.component(AuthorizationComponent); + app + .bind('authorizationProviders.my-provider') + .toProvider(MyAuthorizationProvider) + .tag('authorizationProvider'); + } + + function givenRequestContext() { + events = []; + reqCtx = new Context(app); + reqCtx.bind('current.user').to('user-01'); + controller = new OrderController(); + } + + /** + * Provider of a function which authenticates + */ + class MyAuthorizationProvider implements Provider { + constructor() {} + + /** + * @returns authenticateFn + */ + value(): AuthorizeFn { + return async ( + securityContext: AuthorizationContext, + metadata: AuthorizationMetadata, + ) => { + return this.authorize(securityContext, metadata); + }; + } + + authorize( + securityContext: AuthorizationContext, + metadata: AuthorizationMetadata, + ) { + events.push(securityContext.resource); + if ( + securityContext.resource === 'OrderController.prototype.cancelOrder' && + securityContext.principals[0].name === 'user-01' + ) { + return AuthorizationDecision.DENY; + } + return AuthorizationDecision.ALLOW; + } + } +}); diff --git a/packages/authorization/src/__tests__/unit/authorize-decorator.test.ts b/packages/authorization/src/__tests__/unit/authorize-decorator.test.ts new file mode 100644 index 000000000000..f133c0f71439 --- /dev/null +++ b/packages/authorization/src/__tests__/unit/authorize-decorator.test.ts @@ -0,0 +1,135 @@ +// Copyright IBM Corp. 2019. All Rights Reserved. +// Node module: @loopback/authorization +// This file is licensed under the MIT License. +// License text available at https://opensource.org/licenses/MIT + +import {expect} from '@loopback/testlab'; +import { + AUTHENTICATED, + authorize, + EVERYONE, + getAuthorizeMetadata, + UNAUTHENTICATED, +} from '../..'; + +describe('Authentication', () => { + describe('@authorize decorator', () => { + it('can add authorize metadata to target method', () => { + class TestClass { + @authorize({allowedRoles: ['ADMIN'], scopes: ['secret.read']}) + getSecret() {} + + @authorize({allowedRoles: ['OWNER'], scopes: ['data.update']}) + update() {} + } + + let metaData = getAuthorizeMetadata(TestClass, 'getSecret'); + expect(metaData).to.eql({ + allowedRoles: ['ADMIN'], + scopes: ['secret.read'], + }); + + metaData = getAuthorizeMetadata(TestClass, 'update'); + expect(metaData).to.eql({ + allowedRoles: ['OWNER'], + scopes: ['data.update'], + }); + }); + + it('can add allowAll to target method', () => { + class TestClass { + @authorize.allowAll() + getSecret() {} + } + + const metaData = getAuthorizeMetadata(TestClass, 'getSecret'); + expect(metaData).to.eql({ + allowedRoles: [EVERYONE], + }); + }); + + it('can add allowAllExcept to target method', () => { + class TestClass { + @authorize.allowAllExcept('xyz') + getSecret() {} + } + + const metaData = getAuthorizeMetadata(TestClass, 'getSecret'); + expect(metaData).to.eql({ + allowedRoles: [EVERYONE], + deniedRoles: ['xyz'], + }); + }); + + it('can add denyAll to target method', () => { + class TestClass { + @authorize.denyAll() + getSecret() {} + } + + const metaData = getAuthorizeMetadata(TestClass, 'getSecret'); + expect(metaData).to.eql({ + deniedRoles: [EVERYONE], + }); + }); + + it('can add denyAllExcept to target method', () => { + class TestClass { + @authorize.denyAllExcept('xyz') + getSecret() {} + } + + const metaData = getAuthorizeMetadata(TestClass, 'getSecret'); + expect(metaData).to.eql({ + allowedRoles: ['xyz'], + deniedRoles: [EVERYONE], + }); + }); + + it('can add allowAuthenticated to target method', () => { + class TestClass { + @authorize.allowAuthenticated() + getSecret() {} + } + + const metaData = getAuthorizeMetadata(TestClass, 'getSecret'); + expect(metaData).to.eql({ + allowedRoles: [AUTHENTICATED], + }); + }); + + it('can add allowAuthenticated to target method', () => { + class TestClass { + @authorize.denyUnauthenticated() + getSecret() {} + } + + const metaData = getAuthorizeMetadata(TestClass, 'getSecret'); + expect(metaData).to.eql({ + deniedRoles: [UNAUTHENTICATED], + }); + }); + + it('can stack decorators to target method', () => { + class TestClass { + @authorize.allow('a1', 'a2') + @authorize.deny('d1', 'd2') + @authorize({ + allowedRoles: ['a1', 'a3'], + deniedRoles: ['d3'], + }) + @authorize.scope('s1', 's2') + @authorize.vote('v1', 'v2') + getSecret() {} + } + + const metaData = getAuthorizeMetadata(TestClass, 'getSecret'); + expect(metaData).to.deepEqual({ + voters: ['v1', 'v2'], + allowedRoles: ['a1', 'a3', 'a2'], + deniedRoles: ['d3', 'd1', 'd2'], + scopes: ['s1', 's2'], + }); + }); + }); +}); diff --git a/packages/authorization/src/authorization-component.ts b/packages/authorization/src/authorization-component.ts new file mode 100644 index 000000000000..7ff43c3af9f2 --- /dev/null +++ b/packages/authorization/src/authorization-component.ts @@ -0,0 +1,11 @@ +// Copyright IBM Corp. 2018. All Rights Reserved. +// Node module: @loopback/authorization +// This file is licensed under the MIT License. +// License text available at https://opensource.org/licenses/MIT + +import {Component, createBindingFromClass} from '@loopback/core'; +import {AuthorizationInterceptor} from './authorize-interceptor'; + +export class AuthorizationComponent implements Component { + bindings = [createBindingFromClass(AuthorizationInterceptor)]; +} diff --git a/packages/authorization/src/authorize-interceptor.ts b/packages/authorization/src/authorize-interceptor.ts new file mode 100644 index 000000000000..7fd40fe247c6 --- /dev/null +++ b/packages/authorization/src/authorize-interceptor.ts @@ -0,0 +1,68 @@ +// Copyright IBM Corp. 2019. All Rights Reserved. +// Node module: @loopback/authorization +// This file is licensed under the MIT License. +// License text available at https://opensource.org/licenses/MIT + +import { + asGlobalInterceptor, + bind, + BindingTemplate, + filterByTag, + inject, + Interceptor, + Provider, +} from '@loopback/context'; +import * as debugFactory from 'debug'; +import {getAuthorizeMetadata} from './decorators/authorize'; +import { + AuthorizationContext, + AuthorizationDecision, + AuthorizeFn, +} from './types'; + +const debug = debugFactory('loopback:authorization:interceptor'); + +const globalInterceptorTemplate = asGlobalInterceptor( + 'authorization', +) as BindingTemplate; + +@bind(globalInterceptorTemplate) +export class AuthorizationInterceptor implements Provider { + constructor( + @inject(filterByTag('authorizationProvider')) + private authorizationFunctions: AuthorizeFn[], + ) {} + + value(): Interceptor { + return async (invocationCtx, next) => { + const description = debug.enabled ? invocationCtx.toString() : ''; + const metadata = getAuthorizeMetadata( + invocationCtx.target, + invocationCtx.methodName, + ); + if (!metadata) { + debug('No authorization metadata is found %s', description); + return await next(); + } + debug('Authorization metadata for %s', description, metadata); + const user = await invocationCtx.get('current.user', { + optional: true, + }); + const authCtx: AuthorizationContext = { + principals: user ? [{name: user, type: 'USER'}] : [], + roles: [], + scopes: [], + resource: invocationCtx.targetName, + invocationContext: invocationCtx, + }; + debug('Security context for %s', description, authCtx); + for (const fn of this.authorizationFunctions) { + const decision = await fn(authCtx, metadata); + if (decision === AuthorizationDecision.DENY) { + throw new Error('Access denied'); + } + } + return await next(); + }; + } +} diff --git a/packages/authorization/src/decorators/authorize.ts b/packages/authorization/src/decorators/authorize.ts new file mode 100644 index 000000000000..f09f736082ba --- /dev/null +++ b/packages/authorization/src/decorators/authorize.ts @@ -0,0 +1,165 @@ +// Copyright IBM Corp. 2019. All Rights Reserved. +// Node module: @loopback/authorization +// This file is licensed under the MIT License. +// License text available at https://opensource.org/licenses/MIT + +import { + BindingAddress, + MetadataInspector, + MetadataMap, + MethodDecoratorFactory, +} from '@loopback/context'; +import {AuthorizationBindings} from '../keys'; +import { + AUTHENTICATED, + AuthorizationMetadata, + EVERYONE, + UNAUTHENTICATED, + Voter, +} from '../types'; + +export class AuthorizeMethodDecoratorFactory extends MethodDecoratorFactory< + AuthorizationMetadata +> { + protected mergeWithOwn( + ownMetadata: MetadataMap, + target: Object, + methodName?: string, + // tslint:disable-next-line:no-any + methodDescriptor?: TypedPropertyDescriptor | number, + ) { + ownMetadata = ownMetadata || {}; + let methodMeta = ownMetadata[methodName!]; + if (!methodMeta) { + methodMeta = {}; + ownMetadata[methodName!] = methodMeta; + } + if (this.spec.allowedRoles) { + methodMeta.allowedRoles = this.merge( + methodMeta.allowedRoles, + this.spec.allowedRoles, + ); + } + if (this.spec.deniedRoles) { + methodMeta.deniedRoles = this.merge( + methodMeta.deniedRoles, + this.spec.deniedRoles, + ); + } + if (this.spec.scopes) { + methodMeta.scopes = this.merge(methodMeta.scopes, this.spec.scopes); + } + if (this.spec.voters) { + methodMeta.voters = this.merge(methodMeta.voters, this.spec.voters); + } + + return ownMetadata; + } + + private merge(src?: T[], target?: T[]): T[] { + const list: T[] = []; + const set = new Set(src || []); + if (target) { + for (const i of target) { + set.add(i); + } + } + for (const i of set.values()) list.push(i); + return list; + } +} +/** + * Decorator `@authorize` to mark methods that require authorization + * + * @param spec Authorization metadata + */ +export function authorize(spec: AuthorizationMetadata) { + return AuthorizeMethodDecoratorFactory.createDecorator( + AuthorizationBindings.METADATA, + spec, + ); +} + +export namespace authorize { + /** + * Shortcut to configure allowed roles + * @param roles + */ + export const allow = (...roles: string[]) => authorize({allowedRoles: roles}); + /** + * Shortcut to configure denied roles + * @param roles + */ + export const deny = (...roles: string[]) => authorize({deniedRoles: roles}); + /** + * Shortcut to specify access scopes + * @param scopes + */ + export const scope = (...scopes: string[]) => authorize({scopes}); + + /** + * Shortcut to configure voters + * @param voters + */ + export const vote = (...voters: (Voter | BindingAddress)[]) => + authorize({voters}); + + /** + * Allows all + */ + export const allowAll = () => allow(EVERYONE); + + /** + * Allow all but the given roles + * @param roles + */ + export const allowAllExcept = (...roles: string[]) => + authorize({ + deniedRoles: roles, + allowedRoles: [EVERYONE], + }); + + /** + * Deny all + */ + export const denyAll = () => deny(EVERYONE); + + /** + * Deny all but the given roles + * @param roles + */ + export const denyAllExcept = (...roles: string[]) => + authorize({ + allowedRoles: roles, + deniedRoles: [EVERYONE], + }); + + /** + * Allow authenticated users + */ + export const allowAuthenticated = () => allow(AUTHENTICATED); + /** + * Deny unauthenticated users + */ + export const denyUnauthenticated = () => deny(UNAUTHENTICATED); +} + +/** + * Fetch authorization metadata stored by `@authorize` decorator. + * + * @param target Target object/class + * @param methodName Target method + */ +export function getAuthorizeMetadata( + target: object, + methodName: string, +): AuthorizationMetadata | undefined { + if (typeof target === 'function') { + target = target.prototype; + } + return MetadataInspector.getMethodMetadata( + AuthorizationBindings.METADATA, + target, + methodName, + ); +} diff --git a/packages/authorization/src/index.ts b/packages/authorization/src/index.ts new file mode 100644 index 000000000000..7c1bead268cd --- /dev/null +++ b/packages/authorization/src/index.ts @@ -0,0 +1,10 @@ +// Copyright IBM Corp. 2018. All Rights Reserved. +// Node module: @loopback/authorization +// This file is licensed under the MIT License. +// License text available at https://opensource.org/licenses/MIT + +export * from './authorization-component'; +export * from './authorize-interceptor'; +export * from './decorators/authorize'; +export * from './keys'; +export * from './types'; diff --git a/packages/authorization/src/keys.ts b/packages/authorization/src/keys.ts new file mode 100644 index 000000000000..01b950d87001 --- /dev/null +++ b/packages/authorization/src/keys.ts @@ -0,0 +1,11 @@ +// Copyright IBM Corp. 2018. All Rights Reserved. +// Node module: @loopback/authorization +// This file is licensed under the MIT License. +// License text available at https://opensource.org/licenses/MIT + +/** + * Binding keys used by this component. + */ +export namespace AuthorizationBindings { + export const METADATA = 'authorization.operationMetadata'; +} diff --git a/packages/authorization/src/types.ts b/packages/authorization/src/types.ts new file mode 100644 index 000000000000..404ae6152204 --- /dev/null +++ b/packages/authorization/src/types.ts @@ -0,0 +1,179 @@ +// Copyright IBM Corp. 2018. All Rights Reserved. +// Node module: @loopback/authorization +// This file is licensed under the MIT License. +// License text available at https://opensource.org/licenses/MIT + +import {BindingAddress, Context, InvocationContext} from '@loopback/context'; + +/** + * Built-in roles + */ +export const EVERYONE = '$everyone'; +export const AUTHENTICATED = '$authenticated'; +export const UNAUTHENTICATED = '$unauthenticated'; +export const ANONYMOUS = '$anonymous'; + +/** + * Voting decision for the authorization decision + */ +export enum VotingDecision { + ALLOW = 'Allow', + DENY = 'Deny', + ABSTAIN = 'Abstain', +} + +/** + * A voter function + */ +export interface Voter { + (ctx: Context): Promise; +} + +/** + * Authorization metadata stored via Reflection API + */ +export interface AuthorizationMetadata { + /** + * Roles that are allowed access + */ + allowedRoles?: string[]; + /** + * Roles that are denied access + */ + deniedRoles?: string[]; + /** + * Voters that help make the authorization decision + */ + voters?: (Voter | BindingAddress)[]; + + /** + * Define the access scopes + */ + scopes?: string[]; +} + +/** + * Decisions for authorization + */ +export enum AuthorizationDecision { + /** + * Access allowed + */ + ALLOW = 'Allow', + /** + * Access denied + */ + DENY = 'Deny', + /** + * No decision + */ + ABSTAIN = 'Abstain', +} + +/** + * Represent a user, an application, or a device + */ +export interface Principal { + /** + * Name/id + */ + name: string; + /** + * Type - user/application/device etc + */ + type: string; + // tslint:disable-next-line:no-any + [attribute: string]: any; +} + +/** + * Represent a group of principals that have the same responsibility + */ +export interface Role { + /** + * Name/id + */ + name: string; + // tslint:disable-next-line:no-any + [attribute: string]: any; +} + +/** + * Request context for authorization + */ +export interface AuthorizationContext { + /** + * An array of principals identified for the request - it should come from + * authentication + */ + principals: Principal[]; + /** + * An array of roles for principals + */ + roles: Role[]; + /** + * An array of scopes representing granted permissions - usually come from + * access tokens + */ + scopes: string[]; + /** + * An name for the target resource to be accessed, such as + * `OrderController.prototype.cancelOrder` + */ + resource: string; + + /** + * Context for the invocation + */ + invocationContext: InvocationContext; +} + +/** + * A function to decide if access to the target should be allowed or denied + */ +export interface AuthorizeFn { + /** + * @param request: Context information for authorization + * @param metadata: Metadata representing requirements for authorization + */ + (request: AuthorizationContext, metadata: AuthorizationMetadata): Promise< + AuthorizationDecision + >; +} + +/** + * Inspired by https://github.com/casbin/node-casbin + */ +export interface AuthorizationRequest { + /** + * The requestor that wants to access a resource. + */ + subject: string; + /** + * The resource that is going to be accessed. + */ + object: string; + /** + * The operation that the requestor performs on the resource. + */ + action: string; +} + +/** + * An enforcer of authorization policies + */ +export interface Enforcer { + /** + * Extract the request from authorization context + * @param authorizationContext + */ + buildRequest( + authorizationContext: AuthorizationContext, + ): Promise; + + /** + * Decide if the request can be granted access + * @param request + */ + enforce(request: AuthorizationRequest): Promise; +} diff --git a/packages/authorization/tsconfig.build.json b/packages/authorization/tsconfig.build.json new file mode 100644 index 000000000000..85351e10ace0 --- /dev/null +++ b/packages/authorization/tsconfig.build.json @@ -0,0 +1,9 @@ +{ + "$schema": "http://json.schemastore.org/tsconfig", + "extends": "@loopback/build/config/tsconfig.common.json", + "compilerOptions": { + "rootDir": "src" + }, + "include": ["src"] +} + From f9b94695bdb7715e1f9d3eb6bae0828110f336c3 Mon Sep 17 00:00:00 2001 From: Raymond Feng Date: Fri, 10 May 2019 12:36:56 -0700 Subject: [PATCH 02/10] feat(authorization): add an acceptance to demonstrate casbin integration --- .../fixtures/casbin/rbac_model.conf | 14 ++ .../fixtures/casbin/rbac_policy.csv | 7 + packages/authorization/package-lock.json | 38 ++++ packages/authorization/package.json | 6 +- .../authorization-casbin.acceptance.ts | 170 ++++++++++++++++++ .../acceptance/authorization.acceptance.ts | 10 +- .../src/authorize-interceptor.ts | 14 +- .../authorization/src/decorators/authorize.ts | 4 + packages/authorization/src/types.ts | 4 + 9 files changed, 251 insertions(+), 16 deletions(-) create mode 100644 packages/authorization/fixtures/casbin/rbac_model.conf create mode 100644 packages/authorization/fixtures/casbin/rbac_policy.csv create mode 100644 packages/authorization/src/__tests__/acceptance/authorization-casbin.acceptance.ts diff --git a/packages/authorization/fixtures/casbin/rbac_model.conf b/packages/authorization/fixtures/casbin/rbac_model.conf new file mode 100644 index 000000000000..71159e387d34 --- /dev/null +++ b/packages/authorization/fixtures/casbin/rbac_model.conf @@ -0,0 +1,14 @@ +[request_definition] +r = sub, obj, act + +[policy_definition] +p = sub, obj, act + +[role_definition] +g = _, _ + +[policy_effect] +e = some(where (p.eft == allow)) + +[matchers] +m = g(r.sub, p.sub) && r.obj == p.obj && r.act == p.act \ No newline at end of file diff --git a/packages/authorization/fixtures/casbin/rbac_policy.csv b/packages/authorization/fixtures/casbin/rbac_policy.csv new file mode 100644 index 000000000000..b6742e6bec1d --- /dev/null +++ b/packages/authorization/fixtures/casbin/rbac_policy.csv @@ -0,0 +1,7 @@ +p, bob, order, create +p, alice, order, create +p, customer_service, order, read +p, customer_service, order, create +p, customer_service, order, delete +p, customer_service, order, update +g, alice, customer_service diff --git a/packages/authorization/package-lock.json b/packages/authorization/package-lock.json index 316be2d826b0..a68693b35b20 100644 --- a/packages/authorization/package-lock.json +++ b/packages/authorization/package-lock.json @@ -10,6 +10,17 @@ "integrity": "sha512-D9MyoQFI7iP5VdpEyPZyjjqIJ8Y8EDNQFIFVLOmeg1rI1xiHOChyUPMPRUVfqFCerxfE+yS3vMyj37F6IdtOoQ==", "dev": true }, + "casbin": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/casbin/-/casbin-2.0.4.tgz", + "integrity": "sha512-ddc1KsoMXurw1RAjXI5nbvKNfRrlCGfjvcwp29MH6RfXVLF1q7HVjFMr1Wdttck2y+DAKESQ2hdz1joNTuACDA==", + "dev": true, + "requires": { + "expression-eval": "^1.3.0", + "ip": "^1.1.5", + "lodash": "^4.17.10" + } + }, "debug": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", @@ -18,6 +29,33 @@ "ms": "^2.1.1" } }, + "expression-eval": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/expression-eval/-/expression-eval-1.4.0.tgz", + "integrity": "sha512-CvpqG2feKjGcr+6NB/ZOA2csOeVL+2DSiWrF/4h0mrdYv4SxR2vCZhLHSst4Sp+xHtN/LQtPfi6i7K9EJwzRGw==", + "dev": true, + "requires": { + "jsep": "^0.3.0" + } + }, + "ip": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/ip/-/ip-1.1.5.tgz", + "integrity": "sha1-vd7XARQpCCjAoDnnLvJfWq7ENUo=", + "dev": true + }, + "jsep": { + "version": "0.3.4", + "resolved": "https://registry.npmjs.org/jsep/-/jsep-0.3.4.tgz", + "integrity": "sha512-ovGD9wE+wvudIIYxZGrRcZCxNyZ3Cl1N7Bzyp7/j4d/tA0BaUwcVM9bu0oZaSrefMiNwv6TwZ9X15gvZosteCQ==", + "dev": true + }, + "lodash": { + "version": "4.17.11", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz", + "integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==", + "dev": true + }, "ms": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", diff --git a/packages/authorization/package.json b/packages/authorization/package.json index 87de20934c99..e8a0be101a44 100644 --- a/packages/authorization/package.json +++ b/packages/authorization/package.json @@ -28,7 +28,8 @@ "devDependencies": { "@loopback/build": "^1.5.2", "@loopback/testlab": "^1.2.7", - "@types/debug": "^4.1.4" + "@types/debug": "^4.1.4", + "casbin": "^2.0.4" }, "keywords": [ "LoopBack", @@ -40,7 +41,8 @@ "index.d.ts", "dist", "src", - "!*/__tests__" + "!*/__tests__", + "!/fixtures" ], "repository": { "type": "git", diff --git a/packages/authorization/src/__tests__/acceptance/authorization-casbin.acceptance.ts b/packages/authorization/src/__tests__/acceptance/authorization-casbin.acceptance.ts new file mode 100644 index 000000000000..09777896b846 --- /dev/null +++ b/packages/authorization/src/__tests__/acceptance/authorization-casbin.acceptance.ts @@ -0,0 +1,170 @@ +// Copyright IBM Corp. 2019. All Rights Reserved. +// Node module: @loopback/authorization +// This file is licensed under the MIT License. +// License text available at https://opensource.org/licenses/MIT + +import {Context, inject, invokeMethod, Provider} from '@loopback/context'; +import {Application} from '@loopback/core'; +import {expect} from '@loopback/testlab'; +import * as casbin from 'casbin'; +import * as path from 'path'; +import { + AuthorizationComponent, + AuthorizationContext, + AuthorizationDecision, + AuthorizationMetadata, + AuthorizationRequest, + authorize, + AuthorizeFn, +} from '../..'; + +describe('Authorization', () => { + let app: Application; + let controller: OrderController; + let reqCtx: Context; + let events: string[]; + + before(givenApplication); + beforeEach(givenRequestContext); + + it('allows placeOrder for everyone', async () => { + const orderId = await invokeMethod(controller, 'placeOrder', reqCtx, [ + { + customerId: 'bob', + productId: 'product-a', + quantity: 10, + price: 320, + }, + ]); + expect(orderId).to.eql('order-1'); + expect(events).to.containEql('OrderController.prototype.placeOrder'); + }); + + it('allows cancelOrder for customer_service', async () => { + const orderId = await controller.placeOrder({ + customerId: 'bob', + productId: 'product-a', + quantity: 10, + price: 320, + }); + const result = await invokeMethod(controller, 'cancelOrder', reqCtx, [ + orderId, + ]); + expect(result).to.be.true(); + expect(events).to.containEql('OrderController.prototype.cancelOrder'); + }); + + it('denies cancelOrder for bob', async () => { + givenRequestContext({name: 'bob'}); + const orderId = await controller.placeOrder({ + customerId: 'bob', + productId: 'product-a', + quantity: 10, + price: 320, + }); + const result = invokeMethod(controller, 'cancelOrder', reqCtx, [orderId]); + await expect(result).to.be.rejectedWith('Access denied'); + expect(events).to.containEql('OrderController.prototype.cancelOrder'); + }); + + class Order { + id?: string; + customerId: string; + productId: string; + quantity: number; + price: number; + } + + class OrderController { + orders: Order[] = []; + + @authorize({ + resource: 'order', + scopes: ['create'], + }) + async placeOrder(order: Order) { + order.id = `order-${this.orders.length + 1}`; + this.orders.push(order); + return order.id; + } + + @authorize({ + resource: 'order', + scopes: ['delete'], + }) + async cancelOrder(orderId: string) { + const index = this.orders.findIndex(order => order.id === orderId); + if (index === -1) return false; + this.orders.splice(index, 1); + return true; + } + } + + function givenApplication() { + app = new Application(); + app.component(AuthorizationComponent); + app.bind('casbin.enforcer').toDynamicValue(createEnforcer); + app + .bind('authorizationProviders.casbin-provider') + .toProvider(CasbinAuthorizationProvider) + .tag('authorizationProvider'); + } + + function givenRequestContext(user = {name: 'alice'}) { + events = []; + reqCtx = new Context(app); + reqCtx.bind('current.user').to(user); + controller = new OrderController(); + } + + /** + * Provider of a function which authenticates + */ + class CasbinAuthorizationProvider implements Provider { + constructor(@inject('casbin.enforcer') private enforcer: casbin.Enforcer) {} + + /** + * @returns authenticateFn + */ + value(): AuthorizeFn { + return async ( + authzCtx: AuthorizationContext, + metadata: AuthorizationMetadata, + ) => { + return this.authorize(authzCtx, metadata); + }; + } + + async authorize( + authzCtx: AuthorizationContext, + metadata: AuthorizationMetadata, + ) { + events.push(authzCtx.resource); + const request: AuthorizationRequest = { + subject: authzCtx.principals[0].name, + object: metadata.resource || authzCtx.resource, + action: (metadata.scopes && metadata.scopes[0]) || 'execute', + }; + const allow = await this.enforcer.enforce( + request.subject, + request.object, + request.action, + ); + if (allow) return AuthorizationDecision.ALLOW; + else if (allow === false) return AuthorizationDecision.DENY; + return AuthorizationDecision.ABSTAIN; + } + } + + async function createEnforcer() { + const conf = path.resolve( + __dirname, + '../../../fixtures/casbin/rbac_model.conf', + ); + const policy = path.resolve( + __dirname, + '../../../fixtures/casbin/rbac_policy.csv', + ); + return await casbin.newEnforcer(conf, policy); + } +}); diff --git a/packages/authorization/src/__tests__/acceptance/authorization.acceptance.ts b/packages/authorization/src/__tests__/acceptance/authorization.acceptance.ts index a363631b3c06..9d96bb5264b0 100644 --- a/packages/authorization/src/__tests__/acceptance/authorization.acceptance.ts +++ b/packages/authorization/src/__tests__/acceptance/authorization.acceptance.ts @@ -6,15 +6,15 @@ import {Context, invokeMethod, Provider} from '@loopback/context'; import {Application} from '@loopback/core'; import {expect} from '@loopback/testlab'; -import {AuthorizationComponent} from '../../authorization-component'; -import {authorize} from '../../decorators/authorize'; import { + AuthorizationComponent, + AuthorizationContext, AuthorizationDecision, AuthorizationMetadata, + authorize, AuthorizeFn, EVERYONE, - AuthorizationContext, -} from '../../types'; +} from '../..'; describe('Authorization', () => { let app: Application; @@ -85,7 +85,7 @@ describe('Authorization', () => { function givenRequestContext() { events = []; reqCtx = new Context(app); - reqCtx.bind('current.user').to('user-01'); + reqCtx.bind('current.user').to({name: 'user-01'}); controller = new OrderController(); } diff --git a/packages/authorization/src/authorize-interceptor.ts b/packages/authorization/src/authorize-interceptor.ts index 7fd40fe247c6..d1fabccbc02c 100644 --- a/packages/authorization/src/authorize-interceptor.ts +++ b/packages/authorization/src/authorize-interceptor.ts @@ -6,7 +6,6 @@ import { asGlobalInterceptor, bind, - BindingTemplate, filterByTag, inject, Interceptor, @@ -22,11 +21,7 @@ import { const debug = debugFactory('loopback:authorization:interceptor'); -const globalInterceptorTemplate = asGlobalInterceptor( - 'authorization', -) as BindingTemplate; - -@bind(globalInterceptorTemplate) +@bind(asGlobalInterceptor('authorization')) export class AuthorizationInterceptor implements Provider { constructor( @inject(filterByTag('authorizationProvider')) @@ -35,7 +30,7 @@ export class AuthorizationInterceptor implements Provider { value(): Interceptor { return async (invocationCtx, next) => { - const description = debug.enabled ? invocationCtx.toString() : ''; + const description = debug.enabled ? invocationCtx.description : ''; const metadata = getAuthorizeMetadata( invocationCtx.target, invocationCtx.methodName, @@ -45,11 +40,12 @@ export class AuthorizationInterceptor implements Provider { return await next(); } debug('Authorization metadata for %s', description, metadata); - const user = await invocationCtx.get('current.user', { + const user = await invocationCtx.get<{name: string}>('current.user', { optional: true, }); + debug('Current user', user); const authCtx: AuthorizationContext = { - principals: user ? [{name: user, type: 'USER'}] : [], + principals: user ? [{name: user.name, type: 'USER'}] : [], roles: [], scopes: [], resource: invocationCtx.targetName, diff --git a/packages/authorization/src/decorators/authorize.ts b/packages/authorization/src/decorators/authorize.ts index f09f736082ba..29483ba7c9a8 100644 --- a/packages/authorization/src/decorators/authorize.ts +++ b/packages/authorization/src/decorators/authorize.ts @@ -53,6 +53,10 @@ export class AuthorizeMethodDecoratorFactory extends MethodDecoratorFactory< methodMeta.voters = this.merge(methodMeta.voters, this.spec.voters); } + if (this.spec.resource) { + methodMeta.resource = this.spec.resource; + } + return ownMetadata; } diff --git a/packages/authorization/src/types.ts b/packages/authorization/src/types.ts index 404ae6152204..c08c76c88400 100644 --- a/packages/authorization/src/types.ts +++ b/packages/authorization/src/types.ts @@ -46,6 +46,10 @@ export interface AuthorizationMetadata { */ voters?: (Voter | BindingAddress)[]; + /** + * Name of the resource, default to the method name + */ + resource?: string; /** * Define the access scopes */ From 4ed12d3a601a400822f2d523e50f9fdae805c135 Mon Sep 17 00:00:00 2001 From: Raymond Feng Date: Sat, 11 May 2019 17:14:36 -0700 Subject: [PATCH 03/10] chore(authorization): add more interfaces and documents --- packages/authorization/README.md | 39 +++++++++- .../acceptance/authorization.acceptance.ts | 15 ++-- .../authorization/src/decorators/authorize.ts | 2 +- packages/authorization/src/types.ts | 77 +++++++++++++++++-- 4 files changed, 113 insertions(+), 20 deletions(-) diff --git a/packages/authorization/README.md b/packages/authorization/README.md index 826d31b386d7..4a9c4dd65676 100644 --- a/packages/authorization/README.md +++ b/packages/authorization/README.md @@ -2,11 +2,44 @@ A LoopBack 4 component for authorization support. -**This is a reference implementation showing how to implement an authorization -component, it is not production ready.** - ## Overview +Authorization decides if a **subject** can perform specific **action** on an +**object**. + +### Role based + +### Permission based + +### Vote based + +### Key building blocks + +1. Decorate a method to describe: + +- Permission (maps the method to an action on the protected resource) + + - Type of the protected resource (such as `customer` or `order`) + - What action does the method represent (such as `changeEmail`, `createOrder`, + or `cancelOrder`) + +- ACL (provides role based rules) + + - allowedRoles + - deniedRoles + +- Voters (supplies a list of function to vote on the decision) + +2. Intercept a method invocation + +- Build authorization context + + - Subject (who) - from authentication + - Map principals to roles + - Inspect the target method for metadata - Permission, ACL, voters + +- Run through voters/enforcers to make decisions + ## Installation ```shell diff --git a/packages/authorization/src/__tests__/acceptance/authorization.acceptance.ts b/packages/authorization/src/__tests__/acceptance/authorization.acceptance.ts index 9d96bb5264b0..fe2a754e3151 100644 --- a/packages/authorization/src/__tests__/acceptance/authorization.acceptance.ts +++ b/packages/authorization/src/__tests__/acceptance/authorization.acceptance.ts @@ -100,21 +100,18 @@ describe('Authorization', () => { */ value(): AuthorizeFn { return async ( - securityContext: AuthorizationContext, + context: AuthorizationContext, metadata: AuthorizationMetadata, ) => { - return this.authorize(securityContext, metadata); + return this.authorize(context, metadata); }; } - authorize( - securityContext: AuthorizationContext, - metadata: AuthorizationMetadata, - ) { - events.push(securityContext.resource); + authorize(context: AuthorizationContext, metadata: AuthorizationMetadata) { + events.push(context.resource); if ( - securityContext.resource === 'OrderController.prototype.cancelOrder' && - securityContext.principals[0].name === 'user-01' + context.resource === 'OrderController.prototype.cancelOrder' && + context.principals[0].name === 'user-01' ) { return AuthorizationDecision.DENY; } diff --git a/packages/authorization/src/decorators/authorize.ts b/packages/authorization/src/decorators/authorize.ts index 29483ba7c9a8..80aa941e0219 100644 --- a/packages/authorization/src/decorators/authorize.ts +++ b/packages/authorization/src/decorators/authorize.ts @@ -25,7 +25,7 @@ export class AuthorizeMethodDecoratorFactory extends MethodDecoratorFactory< ownMetadata: MetadataMap, target: Object, methodName?: string, - // tslint:disable-next-line:no-any + // eslint-disable-next-line @typescript-eslint/no-explicit-any methodDescriptor?: TypedPropertyDescriptor | number, ) { ownMetadata = ownMetadata || {}; diff --git a/packages/authorization/src/types.ts b/packages/authorization/src/types.ts index c08c76c88400..5997321f1f27 100644 --- a/packages/authorization/src/types.ts +++ b/packages/authorization/src/types.ts @@ -3,7 +3,7 @@ // This file is licensed under the MIT License. // License text available at https://opensource.org/licenses/MIT -import {BindingAddress, Context, InvocationContext} from '@loopback/context'; +import {BindingAddress, InvocationContext} from '@loopback/context'; /** * Built-in roles @@ -26,7 +26,7 @@ export enum VotingDecision { * A voter function */ export interface Voter { - (ctx: Context): Promise; + (authzCtx: AuthorizationContext): Promise; } /** @@ -86,22 +86,85 @@ export interface Principal { * Type - user/application/device etc */ type: string; - // tslint:disable-next-line:no-any + + // organization + // team/group + + // eslint-disable-next-line @typescript-eslint/no-explicit-any [attribute: string]: any; } /** - * Represent a group of principals that have the same responsibility + * Represent a group of principals that have the same authority. There are two + * types of roles: + * + * - explicit + * - implicit + * */ export interface Role { /** * Name/id */ name: string; - // tslint:disable-next-line:no-any + // eslint-disable-next-line @typescript-eslint/no-explicit-any [attribute: string]: any; } +/** + * `Subject` represents both security state and operations for a single + * application user. + * + * Such operations include: + * - authentication (login) + * - authorization (access control) + * - session access + * - logout + */ +export interface Subject { + principals: Principal[]; + roles: Role[]; + scopes: string[]; +} + +/** + * `Permission` defines an action/access against a protected resource. It's + * the `what` for authorization. + * + * There are three levels of permissions + * + * - Resource level (Order, User) + * - Instance level (Order-0001, User-1001) + * - Property level (User-0001.email) + * + * @example + * - create a user + * - read email of a user + * - change email of a user + * - cancel an order + */ +export interface Permission { + /** + * Action or access of a protected resources, such as `read`, `create`, + * `update`, or `delete` + */ + action: string; + + /** + * Type of protected resource, such as `Order` or `Customer` + */ + resourceType: string; + /** + * Identity of a protected resource instance, such as `order-0001` or + * `customer-101` + */ + resourceInstance?: string; + /** + * Property of a protected resource type/instance, such as `email` + */ + resourceProperty?: string; +} + /** * Request context for authorization */ @@ -137,10 +200,10 @@ export interface AuthorizationContext { */ export interface AuthorizeFn { /** - * @param request: Context information for authorization + * @param context: Context information for authorization * @param metadata: Metadata representing requirements for authorization */ - (request: AuthorizationContext, metadata: AuthorizationMetadata): Promise< + (context: AuthorizationContext, metadata: AuthorizationMetadata): Promise< AuthorizationDecision >; } From b9baef49024e2e28d2fc73d35cdda7a950af763a Mon Sep 17 00:00:00 2001 From: Raymond Feng Date: Thu, 6 Jun 2019 14:07:51 -0700 Subject: [PATCH 04/10] chore(authorization): upgrade dependencies --- packages/authorization/docs.json | 12 - packages/authorization/package-lock.json | 2682 ++++++++++++++++- packages/authorization/package.json | 13 +- .../unit/authorize-decorator.test.ts | 2 +- packages/authorization/tsconfig.build.json | 1 + 5 files changed, 2659 insertions(+), 51 deletions(-) delete mode 100644 packages/authorization/docs.json diff --git a/packages/authorization/docs.json b/packages/authorization/docs.json deleted file mode 100644 index 0ce80ef8469d..000000000000 --- a/packages/authorization/docs.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "content": [ - "index.ts", - "src/index.ts", - "src/decorators/authorize.ts", - "src/providers/authorization-metadata.ts", - "src/providers/authorize.ts", - "src/authorization-component.ts", - "src/keys.ts" - ], - "codeSectionDepth": 4 -} diff --git a/packages/authorization/package-lock.json b/packages/authorization/package-lock.json index a68693b35b20..9d8fca2d1f1c 100644 --- a/packages/authorization/package-lock.json +++ b/packages/authorization/package-lock.json @@ -1,65 +1,2685 @@ { "name": "@loopback/authorization", - "version": "0.1.0", + "version": "1.0.0", "lockfileVersion": 1, "requires": true, "dependencies": { + "@babel/code-frame": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.0.0.tgz", + "integrity": "sha512-OfC2uemaknXr87bdLUkWog7nYuliM9Ij5HUcajsVcMCpQrcLmtxRbVFTIqmcSkSeYRBFBRxs2FiUqFJDLdiebA==", + "dev": true, + "requires": { + "@babel/highlight": "^7.0.0" + } + }, + "@babel/core": { + "version": "7.4.5", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.4.5.tgz", + "integrity": "sha512-OvjIh6aqXtlsA8ujtGKfC7LYWksYSX8yQcM8Ay3LuvVeQ63lcOKgoZWVqcpFwkd29aYU9rVx7jxhfhiEDV9MZA==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.0.0", + "@babel/generator": "^7.4.4", + "@babel/helpers": "^7.4.4", + "@babel/parser": "^7.4.5", + "@babel/template": "^7.4.4", + "@babel/traverse": "^7.4.5", + "@babel/types": "^7.4.4", + "convert-source-map": "^1.1.0", + "debug": "^4.1.0", + "json5": "^2.1.0", + "lodash": "^4.17.11", + "resolve": "^1.3.2", + "semver": "^5.4.1", + "source-map": "^0.5.0" + } + }, + "@babel/generator": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.4.4.tgz", + "integrity": "sha512-53UOLK6TVNqKxf7RUh8NE851EHRxOOeVXKbK2bivdb+iziMyk03Sr4eaE9OELCbyZAAafAKPDwF2TPUES5QbxQ==", + "dev": true, + "requires": { + "@babel/types": "^7.4.4", + "jsesc": "^2.5.1", + "lodash": "^4.17.11", + "source-map": "^0.5.0", + "trim-right": "^1.0.1" + } + }, + "@babel/helper-annotate-as-pure": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.0.0.tgz", + "integrity": "sha512-3UYcJUj9kvSLbLbUIfQTqzcy5VX7GRZ/CCDrnOaZorFFM01aXp1+GJwuFGV4NDDoAS+mOUyHcO6UD/RfqOks3Q==", + "dev": true, + "requires": { + "@babel/types": "^7.0.0" + } + }, + "@babel/helper-builder-binary-assignment-operator-visitor": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.1.0.tgz", + "integrity": "sha512-qNSR4jrmJ8M1VMM9tibvyRAHXQs2PmaksQF7c1CGJNipfe3D8p+wgNwgso/P2A2r2mdgBWAXljNWR0QRZAMW8w==", + "dev": true, + "requires": { + "@babel/helper-explode-assignable-expression": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "@babel/helper-call-delegate": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@babel/helper-call-delegate/-/helper-call-delegate-7.4.4.tgz", + "integrity": "sha512-l79boDFJ8S1c5hvQvG+rc+wHw6IuH7YldmRKsYtpbawsxURu/paVy57FZMomGK22/JckepaikOkY0MoAmdyOlQ==", + "dev": true, + "requires": { + "@babel/helper-hoist-variables": "^7.4.4", + "@babel/traverse": "^7.4.4", + "@babel/types": "^7.4.4" + } + }, + "@babel/helper-create-class-features-plugin": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.4.4.tgz", + "integrity": "sha512-UbBHIa2qeAGgyiNR9RszVF7bUHEdgS4JAUNT8SiqrAN6YJVxlOxeLr5pBzb5kan302dejJ9nla4RyKcR1XT6XA==", + "dev": true, + "requires": { + "@babel/helper-function-name": "^7.1.0", + "@babel/helper-member-expression-to-functions": "^7.0.0", + "@babel/helper-optimise-call-expression": "^7.0.0", + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/helper-replace-supers": "^7.4.4", + "@babel/helper-split-export-declaration": "^7.4.4" + } + }, + "@babel/helper-define-map": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@babel/helper-define-map/-/helper-define-map-7.4.4.tgz", + "integrity": "sha512-IX3Ln8gLhZpSuqHJSnTNBWGDE9kdkTEWl21A/K7PQ00tseBwbqCHTvNLHSBd9M0R5rER4h5Rsvj9vw0R5SieBg==", + "dev": true, + "requires": { + "@babel/helper-function-name": "^7.1.0", + "@babel/types": "^7.4.4", + "lodash": "^4.17.11" + } + }, + "@babel/helper-explode-assignable-expression": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.1.0.tgz", + "integrity": "sha512-NRQpfHrJ1msCHtKjbzs9YcMmJZOg6mQMmGRB+hbamEdG5PNpaSm95275VD92DvJKuyl0s2sFiDmMZ+EnnvufqA==", + "dev": true, + "requires": { + "@babel/traverse": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "@babel/helper-function-name": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.1.0.tgz", + "integrity": "sha512-A95XEoCpb3TO+KZzJ4S/5uW5fNe26DjBGqf1o9ucyLyCmi1dXq/B3c8iaWTfBk3VvetUxl16e8tIrd5teOCfGw==", + "dev": true, + "requires": { + "@babel/helper-get-function-arity": "^7.0.0", + "@babel/template": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "@babel/helper-get-function-arity": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.0.0.tgz", + "integrity": "sha512-r2DbJeg4svYvt3HOS74U4eWKsUAMRH01Z1ds1zx8KNTPtpTL5JAsdFv8BNyOpVqdFhHkkRDIg5B4AsxmkjAlmQ==", + "dev": true, + "requires": { + "@babel/types": "^7.0.0" + } + }, + "@babel/helper-hoist-variables": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.4.4.tgz", + "integrity": "sha512-VYk2/H/BnYbZDDg39hr3t2kKyifAm1W6zHRfhx8jGjIHpQEBv9dry7oQ2f3+J703TLu69nYdxsovl0XYfcnK4w==", + "dev": true, + "requires": { + "@babel/types": "^7.4.4" + } + }, + "@babel/helper-member-expression-to-functions": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.0.0.tgz", + "integrity": "sha512-avo+lm/QmZlv27Zsi0xEor2fKcqWG56D5ae9dzklpIaY7cQMK5N8VSpaNVPPagiqmy7LrEjK1IWdGMOqPu5csg==", + "dev": true, + "requires": { + "@babel/types": "^7.0.0" + } + }, + "@babel/helper-module-imports": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.0.0.tgz", + "integrity": "sha512-aP/hlLq01DWNEiDg4Jn23i+CXxW/owM4WpDLFUbpjxe4NS3BhLVZQ5i7E0ZrxuQ/vwekIeciyamgB1UIYxxM6A==", + "dev": true, + "requires": { + "@babel/types": "^7.0.0" + } + }, + "@babel/helper-module-transforms": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.4.4.tgz", + "integrity": "sha512-3Z1yp8TVQf+B4ynN7WoHPKS8EkdTbgAEy0nU0rs/1Kw4pDgmvYH3rz3aI11KgxKCba2cn7N+tqzV1mY2HMN96w==", + "dev": true, + "requires": { + "@babel/helper-module-imports": "^7.0.0", + "@babel/helper-simple-access": "^7.1.0", + "@babel/helper-split-export-declaration": "^7.4.4", + "@babel/template": "^7.4.4", + "@babel/types": "^7.4.4", + "lodash": "^4.17.11" + } + }, + "@babel/helper-optimise-call-expression": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.0.0.tgz", + "integrity": "sha512-u8nd9NQePYNQV8iPWu/pLLYBqZBa4ZaY1YWRFMuxrid94wKI1QNt67NEZ7GAe5Kc/0LLScbim05xZFWkAdrj9g==", + "dev": true, + "requires": { + "@babel/types": "^7.0.0" + } + }, + "@babel/helper-plugin-utils": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.0.0.tgz", + "integrity": "sha512-CYAOUCARwExnEixLdB6sDm2dIJ/YgEAKDM1MOeMeZu9Ld/bDgVo8aiWrXwcY7OBh+1Ea2uUcVRcxKk0GJvW7QA==", + "dev": true + }, + "@babel/helper-regex": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@babel/helper-regex/-/helper-regex-7.4.4.tgz", + "integrity": "sha512-Y5nuB/kESmR3tKjU8Nkn1wMGEx1tjJX076HBMeL3XLQCu6vA/YRzuTW0bbb+qRnXvQGn+d6Rx953yffl8vEy7Q==", + "dev": true, + "requires": { + "lodash": "^4.17.11" + } + }, + "@babel/helper-remap-async-to-generator": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.1.0.tgz", + "integrity": "sha512-3fOK0L+Fdlg8S5al8u/hWE6vhufGSn0bN09xm2LXMy//REAF8kDCrYoOBKYmA8m5Nom+sV9LyLCwrFynA8/slg==", + "dev": true, + "requires": { + "@babel/helper-annotate-as-pure": "^7.0.0", + "@babel/helper-wrap-function": "^7.1.0", + "@babel/template": "^7.1.0", + "@babel/traverse": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "@babel/helper-replace-supers": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.4.4.tgz", + "integrity": "sha512-04xGEnd+s01nY1l15EuMS1rfKktNF+1CkKmHoErDppjAAZL+IUBZpzT748x262HF7fibaQPhbvWUl5HeSt1EXg==", + "dev": true, + "requires": { + "@babel/helper-member-expression-to-functions": "^7.0.0", + "@babel/helper-optimise-call-expression": "^7.0.0", + "@babel/traverse": "^7.4.4", + "@babel/types": "^7.4.4" + } + }, + "@babel/helper-simple-access": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.1.0.tgz", + "integrity": "sha512-Vk+78hNjRbsiu49zAPALxTb+JUQCz1aolpd8osOF16BGnLtseD21nbHgLPGUwrXEurZgiCOUmvs3ExTu4F5x6w==", + "dev": true, + "requires": { + "@babel/template": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "@babel/helper-split-export-declaration": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.4.4.tgz", + "integrity": "sha512-Ro/XkzLf3JFITkW6b+hNxzZ1n5OQ80NvIUdmHspih1XAhtN3vPTuUFT4eQnela+2MaZ5ulH+iyP513KJrxbN7Q==", + "dev": true, + "requires": { + "@babel/types": "^7.4.4" + } + }, + "@babel/helper-wrap-function": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.2.0.tgz", + "integrity": "sha512-o9fP1BZLLSrYlxYEYyl2aS+Flun5gtjTIG8iln+XuEzQTs0PLagAGSXUcqruJwD5fM48jzIEggCKpIfWTcR7pQ==", + "dev": true, + "requires": { + "@babel/helper-function-name": "^7.1.0", + "@babel/template": "^7.1.0", + "@babel/traverse": "^7.1.0", + "@babel/types": "^7.2.0" + } + }, + "@babel/helpers": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.4.4.tgz", + "integrity": "sha512-igczbR/0SeuPR8RFfC7tGrbdTbFL3QTvH6D+Z6zNxnTe//GyqmtHmDkzrqDmyZ3eSwPqB/LhyKoU5DXsp+Vp2A==", + "dev": true, + "requires": { + "@babel/template": "^7.4.4", + "@babel/traverse": "^7.4.4", + "@babel/types": "^7.4.4" + } + }, + "@babel/highlight": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.0.0.tgz", + "integrity": "sha512-UFMC4ZeFC48Tpvj7C8UgLvtkaUuovQX+5xNWrsIoMG8o2z+XFKjKaN9iVmS84dPwVN00W4wPmqvYoZF3EGAsfw==", + "dev": true, + "requires": { + "chalk": "^2.0.0", + "esutils": "^2.0.2", + "js-tokens": "^4.0.0" + } + }, + "@babel/parser": { + "version": "7.4.5", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.4.5.tgz", + "integrity": "sha512-9mUqkL1FF5T7f0WDFfAoDdiMVPWsdD1gZYzSnaXsxUCUqzuch/8of9G3VUSNiZmMBoRxT3neyVsqeiL/ZPcjew==", + "dev": true + }, + "@babel/plugin-proposal-async-generator-functions": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.2.0.tgz", + "integrity": "sha512-+Dfo/SCQqrwx48ptLVGLdE39YtWRuKc/Y9I5Fy0P1DDBB9lsAHpjcEJQt+4IifuSOSTLBKJObJqMvaO1pIE8LQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/helper-remap-async-to-generator": "^7.1.0", + "@babel/plugin-syntax-async-generators": "^7.2.0" + } + }, + "@babel/plugin-proposal-class-properties": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.4.4.tgz", + "integrity": "sha512-WjKTI8g8d5w1Bc9zgwSz2nfrsNQsXcCf9J9cdCvrJV6RF56yztwm4TmJC0MgJ9tvwO9gUA/mcYe89bLdGfiXFg==", + "dev": true, + "requires": { + "@babel/helper-create-class-features-plugin": "^7.4.4", + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-proposal-json-strings": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.2.0.tgz", + "integrity": "sha512-MAFV1CA/YVmYwZG0fBQyXhmj0BHCB5egZHCKWIFVv/XCxAeVGIHfos3SwDck4LvCllENIAg7xMKOG5kH0dzyUg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/plugin-syntax-json-strings": "^7.2.0" + } + }, + "@babel/plugin-proposal-object-rest-spread": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.4.4.tgz", + "integrity": "sha512-dMBG6cSPBbHeEBdFXeQ2QLc5gUpg4Vkaz8octD4aoW/ISO+jBOcsuxYL7bsb5WSu8RLP6boxrBIALEHgoHtO9g==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/plugin-syntax-object-rest-spread": "^7.2.0" + } + }, + "@babel/plugin-proposal-optional-catch-binding": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.2.0.tgz", + "integrity": "sha512-mgYj3jCcxug6KUcX4OBoOJz3CMrwRfQELPQ5560F70YQUBZB7uac9fqaWamKR1iWUzGiK2t0ygzjTScZnVz75g==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/plugin-syntax-optional-catch-binding": "^7.2.0" + } + }, + "@babel/plugin-proposal-unicode-property-regex": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.4.4.tgz", + "integrity": "sha512-j1NwnOqMG9mFUOH58JTFsA/+ZYzQLUZ/drqWUqxCYLGeu2JFZL8YrNC9hBxKmWtAuOCHPcRpgv7fhap09Fb4kA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/helper-regex": "^7.4.4", + "regexpu-core": "^4.5.4" + } + }, + "@babel/plugin-syntax-async-generators": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.2.0.tgz", + "integrity": "sha512-1ZrIRBv2t0GSlcwVoQ6VgSLpLgiN/FVQUzt9znxo7v2Ov4jJrs8RY8tv0wvDmFN3qIdMKWrmMMW6yZ0G19MfGg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-syntax-flow": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-flow/-/plugin-syntax-flow-7.2.0.tgz", + "integrity": "sha512-r6YMuZDWLtLlu0kqIim5o/3TNRAlWb073HwT3e2nKf9I8IIvOggPrnILYPsrrKilmn/mYEMCf/Z07w3yQJF6dg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-syntax-json-strings": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.2.0.tgz", + "integrity": "sha512-5UGYnMSLRE1dqqZwug+1LISpA403HzlSfsg6P9VXU6TBjcSHeNlw4DxDx7LgpF+iKZoOG/+uzqoRHTdcUpiZNg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-syntax-object-rest-spread": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.2.0.tgz", + "integrity": "sha512-t0JKGgqk2We+9may3t0xDdmneaXmyxq0xieYcKHxIsrJO64n1OiMWNUtc5gQK1PA0NpdCRrtZp4z+IUaKugrSA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-syntax-optional-catch-binding": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.2.0.tgz", + "integrity": "sha512-bDe4xKNhb0LI7IvZHiA13kff0KEfaGX/Hv4lMA9+7TEc63hMNvfKo6ZFpXhKuEp+II/q35Gc4NoMeDZyaUbj9w==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-syntax-typescript": { + "version": "7.3.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.3.3.tgz", + "integrity": "sha512-dGwbSMA1YhVS8+31CnPR7LB4pcbrzcV99wQzby4uAfrkZPYZlQ7ImwdpzLqi6Z6IL02b8IAL379CaMwo0x5Lag==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-transform-arrow-functions": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.2.0.tgz", + "integrity": "sha512-ER77Cax1+8/8jCB9fo4Ud161OZzWN5qawi4GusDuRLcDbDG+bIGYY20zb2dfAFdTRGzrfq2xZPvF0R64EHnimg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-transform-async-to-generator": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.4.4.tgz", + "integrity": "sha512-YiqW2Li8TXmzgbXw+STsSqPBPFnGviiaSp6CYOq55X8GQ2SGVLrXB6pNid8HkqkZAzOH6knbai3snhP7v0fNwA==", + "dev": true, + "requires": { + "@babel/helper-module-imports": "^7.0.0", + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/helper-remap-async-to-generator": "^7.1.0" + } + }, + "@babel/plugin-transform-block-scoped-functions": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.2.0.tgz", + "integrity": "sha512-ntQPR6q1/NKuphly49+QiQiTN0O63uOwjdD6dhIjSWBI5xlrbUFh720TIpzBhpnrLfv2tNH/BXvLIab1+BAI0w==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-transform-block-scoping": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.4.4.tgz", + "integrity": "sha512-jkTUyWZcTrwxu5DD4rWz6rDB5Cjdmgz6z7M7RLXOJyCUkFBawssDGcGh8M/0FTSB87avyJI1HsTwUXp9nKA1PA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0", + "lodash": "^4.17.11" + } + }, + "@babel/plugin-transform-classes": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.4.4.tgz", + "integrity": "sha512-/e44eFLImEGIpL9qPxSRat13I5QNRgBLu2hOQJCF7VLy/otSM/sypV1+XaIw5+502RX/+6YaSAPmldk+nhHDPw==", + "dev": true, + "requires": { + "@babel/helper-annotate-as-pure": "^7.0.0", + "@babel/helper-define-map": "^7.4.4", + "@babel/helper-function-name": "^7.1.0", + "@babel/helper-optimise-call-expression": "^7.0.0", + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/helper-replace-supers": "^7.4.4", + "@babel/helper-split-export-declaration": "^7.4.4", + "globals": "^11.1.0" + } + }, + "@babel/plugin-transform-computed-properties": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.2.0.tgz", + "integrity": "sha512-kP/drqTxY6Xt3NNpKiMomfgkNn4o7+vKxK2DDKcBG9sHj51vHqMBGy8wbDS/J4lMxnqs153/T3+DmCEAkC5cpA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-transform-destructuring": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.4.4.tgz", + "integrity": "sha512-/aOx+nW0w8eHiEHm+BTERB2oJn5D127iye/SUQl7NjHy0lf+j7h4MKMMSOwdazGq9OxgiNADncE+SRJkCxjZpQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-transform-dotall-regex": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.4.4.tgz", + "integrity": "sha512-P05YEhRc2h53lZDjRPk/OektxCVevFzZs2Gfjd545Wde3k+yFDbXORgl2e0xpbq8mLcKJ7Idss4fAg0zORN/zg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/helper-regex": "^7.4.4", + "regexpu-core": "^4.5.4" + } + }, + "@babel/plugin-transform-duplicate-keys": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.2.0.tgz", + "integrity": "sha512-q+yuxW4DsTjNceUiTzK0L+AfQ0zD9rWaTLiUqHA8p0gxx7lu1EylenfzjeIWNkPy6e/0VG/Wjw9uf9LueQwLOw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-transform-exponentiation-operator": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.2.0.tgz", + "integrity": "sha512-umh4hR6N7mu4Elq9GG8TOu9M0bakvlsREEC+ialrQN6ABS4oDQ69qJv1VtR3uxlKMCQMCvzk7vr17RHKcjx68A==", + "dev": true, + "requires": { + "@babel/helper-builder-binary-assignment-operator-visitor": "^7.1.0", + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-transform-flow-strip-types": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-flow-strip-types/-/plugin-transform-flow-strip-types-7.4.4.tgz", + "integrity": "sha512-WyVedfeEIILYEaWGAUWzVNyqG4sfsNooMhXWsu/YzOvVGcsnPb5PguysjJqI3t3qiaYj0BR8T2f5njdjTGe44Q==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/plugin-syntax-flow": "^7.2.0" + } + }, + "@babel/plugin-transform-for-of": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.4.4.tgz", + "integrity": "sha512-9T/5Dlr14Z9TIEXLXkt8T1DU7F24cbhwhMNUziN3hB1AXoZcdzPcTiKGRn/6iOymDqtTKWnr/BtRKN9JwbKtdQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-transform-function-name": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.4.4.tgz", + "integrity": "sha512-iU9pv7U+2jC9ANQkKeNF6DrPy4GBa4NWQtl6dHB4Pb3izX2JOEvDTFarlNsBj/63ZEzNNIAMs3Qw4fNCcSOXJA==", + "dev": true, + "requires": { + "@babel/helper-function-name": "^7.1.0", + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-transform-literals": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.2.0.tgz", + "integrity": "sha512-2ThDhm4lI4oV7fVQ6pNNK+sx+c/GM5/SaML0w/r4ZB7sAneD/piDJtwdKlNckXeyGK7wlwg2E2w33C/Hh+VFCg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-transform-member-expression-literals": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.2.0.tgz", + "integrity": "sha512-HiU3zKkSU6scTidmnFJ0bMX8hz5ixC93b4MHMiYebmk2lUVNGOboPsqQvx5LzooihijUoLR/v7Nc1rbBtnc7FA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-transform-modules-amd": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.2.0.tgz", + "integrity": "sha512-mK2A8ucqz1qhrdqjS9VMIDfIvvT2thrEsIQzbaTdc5QFzhDjQv2CkJJ5f6BXIkgbmaoax3zBr2RyvV/8zeoUZw==", + "dev": true, + "requires": { + "@babel/helper-module-transforms": "^7.1.0", + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-transform-modules-commonjs": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.4.4.tgz", + "integrity": "sha512-4sfBOJt58sEo9a2BQXnZq+Q3ZTSAUXyK3E30o36BOGnJ+tvJ6YSxF0PG6kERvbeISgProodWuI9UVG3/FMY6iw==", + "dev": true, + "requires": { + "@babel/helper-module-transforms": "^7.4.4", + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/helper-simple-access": "^7.1.0" + } + }, + "@babel/plugin-transform-modules-systemjs": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.4.4.tgz", + "integrity": "sha512-MSiModfILQc3/oqnG7NrP1jHaSPryO6tA2kOMmAQApz5dayPxWiHqmq4sWH2xF5LcQK56LlbKByCd8Aah/OIkQ==", + "dev": true, + "requires": { + "@babel/helper-hoist-variables": "^7.4.4", + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-transform-modules-umd": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.2.0.tgz", + "integrity": "sha512-BV3bw6MyUH1iIsGhXlOK6sXhmSarZjtJ/vMiD9dNmpY8QXFFQTj+6v92pcfy1iqa8DeAfJFwoxcrS/TUZda6sw==", + "dev": true, + "requires": { + "@babel/helper-module-transforms": "^7.1.0", + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-transform-named-capturing-groups-regex": { + "version": "7.4.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.4.5.tgz", + "integrity": "sha512-z7+2IsWafTBbjNsOxU/Iv5CvTJlr5w4+HGu1HovKYTtgJ362f7kBcQglkfmlspKKZ3bgrbSGvLfNx++ZJgCWsg==", + "dev": true, + "requires": { + "regexp-tree": "^0.1.6" + } + }, + "@babel/plugin-transform-new-target": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.4.4.tgz", + "integrity": "sha512-r1z3T2DNGQwwe2vPGZMBNjioT2scgWzK9BCnDEh+46z8EEwXBq24uRzd65I7pjtugzPSj921aM15RpESgzsSuA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-transform-object-super": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.2.0.tgz", + "integrity": "sha512-VMyhPYZISFZAqAPVkiYb7dUe2AsVi2/wCT5+wZdsNO31FojQJa9ns40hzZ6U9f50Jlq4w6qwzdBB2uwqZ00ebg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/helper-replace-supers": "^7.1.0" + } + }, + "@babel/plugin-transform-parameters": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.4.4.tgz", + "integrity": "sha512-oMh5DUO1V63nZcu/ZVLQFqiihBGo4OpxJxR1otF50GMeCLiRx5nUdtokd+u9SuVJrvvuIh9OosRFPP4pIPnwmw==", + "dev": true, + "requires": { + "@babel/helper-call-delegate": "^7.4.4", + "@babel/helper-get-function-arity": "^7.0.0", + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-transform-property-literals": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.2.0.tgz", + "integrity": "sha512-9q7Dbk4RhgcLp8ebduOpCbtjh7C0itoLYHXd9ueASKAG/is5PQtMR5VJGka9NKqGhYEGn5ITahd4h9QeBMylWQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-transform-regenerator": { + "version": "7.4.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.4.5.tgz", + "integrity": "sha512-gBKRh5qAaCWntnd09S8QC7r3auLCqq5DI6O0DlfoyDjslSBVqBibrMdsqO+Uhmx3+BlOmE/Kw1HFxmGbv0N9dA==", + "dev": true, + "requires": { + "regenerator-transform": "^0.14.0" + } + }, + "@babel/plugin-transform-reserved-words": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.2.0.tgz", + "integrity": "sha512-fz43fqW8E1tAB3DKF19/vxbpib1fuyCwSPE418ge5ZxILnBhWyhtPgz8eh1RCGGJlwvksHkyxMxh0eenFi+kFw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-transform-shorthand-properties": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.2.0.tgz", + "integrity": "sha512-QP4eUM83ha9zmYtpbnyjTLAGKQritA5XW/iG9cjtuOI8s1RuL/3V6a3DeSHfKutJQ+ayUfeZJPcnCYEQzaPQqg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-transform-spread": { + "version": "7.2.2", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.2.2.tgz", + "integrity": "sha512-KWfky/58vubwtS0hLqEnrWJjsMGaOeSBn90Ezn5Jeg9Z8KKHmELbP1yGylMlm5N6TPKeY9A2+UaSYLdxahg01w==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-transform-sticky-regex": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.2.0.tgz", + "integrity": "sha512-KKYCoGaRAf+ckH8gEL3JHUaFVyNHKe3ASNsZ+AlktgHevvxGigoIttrEJb8iKN03Q7Eazlv1s6cx2B2cQ3Jabw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/helper-regex": "^7.0.0" + } + }, + "@babel/plugin-transform-template-literals": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.4.4.tgz", + "integrity": "sha512-mQrEC4TWkhLN0z8ygIvEL9ZEToPhG5K7KDW3pzGqOfIGZ28Jb0POUkeWcoz8HnHvhFy6dwAT1j8OzqN8s804+g==", + "dev": true, + "requires": { + "@babel/helper-annotate-as-pure": "^7.0.0", + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-transform-typeof-symbol": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.2.0.tgz", + "integrity": "sha512-2LNhETWYxiYysBtrBTqL8+La0jIoQQnIScUJc74OYvUGRmkskNY4EzLCnjHBzdmb38wqtTaixpo1NctEcvMDZw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/plugin-transform-typescript": { + "version": "7.4.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.4.5.tgz", + "integrity": "sha512-RPB/YeGr4ZrFKNwfuQRlMf2lxoCUaU01MTw39/OFE/RiL8HDjtn68BwEPft1P7JN4akyEmjGWAMNldOV7o9V2g==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/plugin-syntax-typescript": "^7.2.0" + } + }, + "@babel/plugin-transform-unicode-regex": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.4.4.tgz", + "integrity": "sha512-il+/XdNw01i93+M9J9u4T7/e/Ue/vWfNZE4IRUQjplu2Mqb/AFTDimkw2tdEdSH50wuQXZAbXSql0UphQke+vA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/helper-regex": "^7.4.4", + "regexpu-core": "^4.5.4" + } + }, + "@babel/preset-env": { + "version": "7.4.5", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.4.5.tgz", + "integrity": "sha512-f2yNVXM+FsR5V8UwcFeIHzHWgnhXg3NpRmy0ADvALpnhB0SLbCvrCRr4BLOUYbQNLS+Z0Yer46x9dJXpXewI7w==", + "dev": true, + "requires": { + "@babel/helper-module-imports": "^7.0.0", + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/plugin-proposal-async-generator-functions": "^7.2.0", + "@babel/plugin-proposal-json-strings": "^7.2.0", + "@babel/plugin-proposal-object-rest-spread": "^7.4.4", + "@babel/plugin-proposal-optional-catch-binding": "^7.2.0", + "@babel/plugin-proposal-unicode-property-regex": "^7.4.4", + "@babel/plugin-syntax-async-generators": "^7.2.0", + "@babel/plugin-syntax-json-strings": "^7.2.0", + "@babel/plugin-syntax-object-rest-spread": "^7.2.0", + "@babel/plugin-syntax-optional-catch-binding": "^7.2.0", + "@babel/plugin-transform-arrow-functions": "^7.2.0", + "@babel/plugin-transform-async-to-generator": "^7.4.4", + "@babel/plugin-transform-block-scoped-functions": "^7.2.0", + "@babel/plugin-transform-block-scoping": "^7.4.4", + "@babel/plugin-transform-classes": "^7.4.4", + "@babel/plugin-transform-computed-properties": "^7.2.0", + "@babel/plugin-transform-destructuring": "^7.4.4", + "@babel/plugin-transform-dotall-regex": "^7.4.4", + "@babel/plugin-transform-duplicate-keys": "^7.2.0", + "@babel/plugin-transform-exponentiation-operator": "^7.2.0", + "@babel/plugin-transform-for-of": "^7.4.4", + "@babel/plugin-transform-function-name": "^7.4.4", + "@babel/plugin-transform-literals": "^7.2.0", + "@babel/plugin-transform-member-expression-literals": "^7.2.0", + "@babel/plugin-transform-modules-amd": "^7.2.0", + "@babel/plugin-transform-modules-commonjs": "^7.4.4", + "@babel/plugin-transform-modules-systemjs": "^7.4.4", + "@babel/plugin-transform-modules-umd": "^7.2.0", + "@babel/plugin-transform-named-capturing-groups-regex": "^7.4.5", + "@babel/plugin-transform-new-target": "^7.4.4", + "@babel/plugin-transform-object-super": "^7.2.0", + "@babel/plugin-transform-parameters": "^7.4.4", + "@babel/plugin-transform-property-literals": "^7.2.0", + "@babel/plugin-transform-regenerator": "^7.4.5", + "@babel/plugin-transform-reserved-words": "^7.2.0", + "@babel/plugin-transform-shorthand-properties": "^7.2.0", + "@babel/plugin-transform-spread": "^7.2.0", + "@babel/plugin-transform-sticky-regex": "^7.2.0", + "@babel/plugin-transform-template-literals": "^7.4.4", + "@babel/plugin-transform-typeof-symbol": "^7.2.0", + "@babel/plugin-transform-unicode-regex": "^7.4.4", + "@babel/types": "^7.4.4", + "browserslist": "^4.6.0", + "core-js-compat": "^3.1.1", + "invariant": "^2.2.2", + "js-levenshtein": "^1.1.3", + "semver": "^5.5.0" + } + }, + "@babel/preset-flow": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@babel/preset-flow/-/preset-flow-7.0.0.tgz", + "integrity": "sha512-bJOHrYOPqJZCkPVbG1Lot2r5OSsB+iUOaxiHdlOeB1yPWS6evswVHwvkDLZ54WTaTRIk89ds0iHmGZSnxlPejQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/plugin-transform-flow-strip-types": "^7.0.0" + } + }, + "@babel/preset-typescript": { + "version": "7.3.3", + "resolved": "https://registry.npmjs.org/@babel/preset-typescript/-/preset-typescript-7.3.3.tgz", + "integrity": "sha512-mzMVuIP4lqtn4du2ynEfdO0+RYcslwrZiJHXu4MGaC1ctJiW2fyaeDrtjJGs7R/KebZ1sgowcIoWf4uRpEfKEg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/plugin-transform-typescript": "^7.3.2" + } + }, + "@babel/register": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@babel/register/-/register-7.4.4.tgz", + "integrity": "sha512-sn51H88GRa00+ZoMqCVgOphmswG4b7mhf9VOB0LUBAieykq2GnRFerlN+JQkO/ntT7wz4jaHNSRPg9IdMPEUkA==", + "dev": true, + "requires": { + "core-js": "^3.0.0", + "find-cache-dir": "^2.0.0", + "lodash": "^4.17.11", + "mkdirp": "^0.5.1", + "pirates": "^4.0.0", + "source-map-support": "^0.5.9" + } + }, + "@babel/template": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.4.4.tgz", + "integrity": "sha512-CiGzLN9KgAvgZsnivND7rkA+AeJ9JB0ciPOD4U59GKbQP2iQl+olF1l76kJOupqidozfZ32ghwBEJDhnk9MEcw==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.0.0", + "@babel/parser": "^7.4.4", + "@babel/types": "^7.4.4" + } + }, + "@babel/traverse": { + "version": "7.4.5", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.4.5.tgz", + "integrity": "sha512-Vc+qjynwkjRmIFGxy0KYoPj4FdVDxLej89kMHFsWScq999uX+pwcX4v9mWRjW0KcAYTPAuVQl2LKP1wEVLsp+A==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.0.0", + "@babel/generator": "^7.4.4", + "@babel/helper-function-name": "^7.1.0", + "@babel/helper-split-export-declaration": "^7.4.4", + "@babel/parser": "^7.4.5", + "@babel/types": "^7.4.4", + "debug": "^4.1.0", + "globals": "^11.1.0", + "lodash": "^4.17.11" + } + }, + "@babel/types": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.4.4.tgz", + "integrity": "sha512-dOllgYdnEFOebhkKCjzSVFqw/PmmB8pH6RGOWkY4GsboQNd47b1fBThBSwlHAq9alF9vc1M3+6oqR47R50L0tQ==", + "dev": true, + "requires": { + "esutils": "^2.0.2", + "lodash": "^4.17.11", + "to-fast-properties": "^2.0.0" + } + }, "@types/debug": { "version": "4.1.4", "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.4.tgz", "integrity": "sha512-D9MyoQFI7iP5VdpEyPZyjjqIJ8Y8EDNQFIFVLOmeg1rI1xiHOChyUPMPRUVfqFCerxfE+yS3vMyj37F6IdtOoQ==", "dev": true }, - "casbin": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/casbin/-/casbin-2.0.4.tgz", - "integrity": "sha512-ddc1KsoMXurw1RAjXI5nbvKNfRrlCGfjvcwp29MH6RfXVLF1q7HVjFMr1Wdttck2y+DAKESQ2hdz1joNTuACDA==", + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "arr-diff": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", + "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=", + "dev": true + }, + "arr-flatten": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz", + "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==", + "dev": true + }, + "arr-union": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz", + "integrity": "sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ=", + "dev": true + }, + "array-unique": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", + "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=", + "dev": true + }, + "assign-symbols": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz", + "integrity": "sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=", + "dev": true + }, + "ast-types": { + "version": "0.11.7", + "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.11.7.tgz", + "integrity": "sha512-2mP3TwtkY/aTv5X3ZsMpNAbOnyoC/aMJwJSoaELPkHId0nSQgFcnU4dRW3isxiz7+zBexk0ym3WNVjMiQBnJSw==", + "dev": true + }, + "atob": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz", + "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==", + "dev": true + }, + "babel-core": { + "version": "7.0.0-bridge.0", + "resolved": "https://registry.npmjs.org/babel-core/-/babel-core-7.0.0-bridge.0.tgz", + "integrity": "sha512-poPX9mZH/5CSanm50Q+1toVci6pv5KSRv/5TWCwtzQS5XEwn40BcCrgIeMFWP9CKKIniKXNxoIOnOq4VVlGXhg==", + "dev": true + }, + "balanced-match": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", + "dev": true + }, + "base": { + "version": "0.11.2", + "resolved": "https://registry.npmjs.org/base/-/base-0.11.2.tgz", + "integrity": "sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==", + "dev": true, + "requires": { + "cache-base": "^1.0.1", + "class-utils": "^0.3.5", + "component-emitter": "^1.2.1", + "define-property": "^1.0.0", + "isobject": "^3.0.1", + "mixin-deep": "^1.2.0", + "pascalcase": "^0.1.1" + }, + "dependencies": { + "define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "dev": true, + "requires": { + "is-descriptor": "^1.0.0" + } + }, + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "dev": true, + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + } + } + }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "braces": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", + "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", + "dev": true, + "requires": { + "arr-flatten": "^1.1.0", + "array-unique": "^0.3.2", + "extend-shallow": "^2.0.1", + "fill-range": "^4.0.0", + "isobject": "^3.0.1", + "repeat-element": "^1.1.2", + "snapdragon": "^0.8.1", + "snapdragon-node": "^2.0.1", + "split-string": "^3.0.2", + "to-regex": "^3.0.1" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "browserslist": { + "version": "4.6.3", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.6.3.tgz", + "integrity": "sha512-CNBqTCq22RKM8wKJNowcqihHJ4SkI8CGeK7KOR9tPboXUuS5Zk5lQgzzTbs4oxD8x+6HUshZUa2OyNI9lR93bQ==", + "dev": true, + "requires": { + "caniuse-lite": "^1.0.30000975", + "electron-to-chromium": "^1.3.164", + "node-releases": "^1.1.23" + } + }, + "buffer-from": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", + "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==", + "dev": true + }, + "cache-base": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz", + "integrity": "sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==", + "dev": true, + "requires": { + "collection-visit": "^1.0.0", + "component-emitter": "^1.2.1", + "get-value": "^2.0.6", + "has-value": "^1.0.0", + "isobject": "^3.0.1", + "set-value": "^2.0.0", + "to-object-path": "^0.3.0", + "union-value": "^1.0.0", + "unset-value": "^1.0.0" + } + }, + "caniuse-lite": { + "version": "1.0.30000976", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000976.tgz", + "integrity": "sha512-tleNB1IwPRqZiod6nUNum63xQCMN96BUO2JTeiwuRM7p9d616EHsMBjBWJMudX39qCaPuWY8KEWzMZq7A9XQMQ==", + "dev": true + }, + "casbin": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/casbin/-/casbin-3.0.1.tgz", + "integrity": "sha512-yV0WklXVghifR6bYHHdC6+zyPuJXFpZJPYd2K3GJayyCkkmzmCyX088ZXGU3hQOa0+vmELxmjfjDgQSDGe2jyg==", + "dev": true, + "requires": { + "expression-eval": "^2.0.0", + "ip": "^1.1.5", + "jscodeshift": "^0.6.4", + "lodash": "^4.17.10" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "class-utils": { + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz", + "integrity": "sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==", + "dev": true, + "requires": { + "arr-union": "^3.1.0", + "define-property": "^0.2.5", + "isobject": "^3.0.0", + "static-extend": "^0.1.1" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "requires": { + "is-descriptor": "^0.1.0" + } + } + } + }, + "collection-visit": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz", + "integrity": "sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA=", + "dev": true, + "requires": { + "map-visit": "^1.0.0", + "object-visit": "^1.0.0" + } + }, + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", + "dev": true + }, + "colors": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/colors/-/colors-1.3.3.tgz", + "integrity": "sha512-mmGt/1pZqYRjMxB1axhTo16/snVZ5krrKkcmMeVKxzECMMXoCgnvTPp10QgHfcbQZw8Dq2jMNG6je4JlWU0gWg==", + "dev": true + }, + "commondir": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", + "integrity": "sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=", + "dev": true + }, + "component-emitter": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz", + "integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==", + "dev": true + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", + "dev": true + }, + "convert-source-map": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.6.0.tgz", + "integrity": "sha512-eFu7XigvxdZ1ETfbgPBohgyQ/Z++C0eEhTor0qRwBw9unw+L0/6V8wkSuGgzdThkiS5lSpdptOQPD8Ak40a+7A==", + "dev": true, + "requires": { + "safe-buffer": "~5.1.1" + } + }, + "copy-descriptor": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz", + "integrity": "sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=", + "dev": true + }, + "core-js": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.1.4.tgz", + "integrity": "sha512-YNZN8lt82XIMLnLirj9MhKDFZHalwzzrL9YLt6eb0T5D0EDl4IQ90IGkua8mHbnxNrkj1d8hbdizMc0Qmg1WnQ==", + "dev": true + }, + "core-js-compat": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.1.4.tgz", + "integrity": "sha512-Z5zbO9f1d0YrJdoaQhphVAnKPimX92D6z8lCGphH89MNRxlL1prI9ExJPqVwP0/kgkQCv8c4GJGT8X16yUncOg==", + "dev": true, + "requires": { + "browserslist": "^4.6.2", + "core-js-pure": "3.1.4", + "semver": "^6.1.1" + }, + "dependencies": { + "semver": { + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.1.2.tgz", + "integrity": "sha512-z4PqiCpomGtWj8633oeAdXm1Kn1W++3T8epkZYnwiVgIYIJ0QHszhInYSJTYxebByQH7KVCEAn8R9duzZW2PhQ==", + "dev": true + } + } + }, + "core-js-pure": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/core-js-pure/-/core-js-pure-3.1.4.tgz", + "integrity": "sha512-uJ4Z7iPNwiu1foygbcZYJsJs1jiXrTTCvxfLDXNhI/I+NHbSIEyr548y4fcsCEyWY0XgfAG/qqaunJ1SThHenA==", + "dev": true + }, + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "requires": { + "ms": "^2.1.1" + } + }, + "decode-uri-component": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz", + "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=", + "dev": true + }, + "define-property": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", + "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", + "dev": true, + "requires": { + "is-descriptor": "^1.0.2", + "isobject": "^3.0.1" + }, + "dependencies": { + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "dev": true, + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + } + } + }, + "electron-to-chromium": { + "version": "1.3.172", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.172.tgz", + "integrity": "sha512-bHgFvYeHBiQNNuY/WvoX37zLosPgMbR8nKU1r4mylHptLvuMMny/KG/L28DTIlcoOCJjMAhEimy3DHDgDayPbg==", + "dev": true + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "dev": true + }, + "esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true + }, + "esutils": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz", + "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=", + "dev": true + }, + "expand-brackets": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", + "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=", + "dev": true, + "requires": { + "debug": "^2.3.3", + "define-property": "^0.2.5", + "extend-shallow": "^2.0.1", + "posix-character-classes": "^0.1.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "requires": { + "is-descriptor": "^0.1.0" + } + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + } + } + }, + "expression-eval": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/expression-eval/-/expression-eval-2.0.0.tgz", + "integrity": "sha512-8cFzfco37CdZQd4DTyZ+ncxQtPUTE0dcxvbGXYc17Ji+3MQSBkT+11GdfC7eO2duvLNuWjN7Ejqb0kLX/u2bBw==", + "dev": true, + "requires": { + "jsep": "^0.3.0" + } + }, + "extend-shallow": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", + "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", + "dev": true, + "requires": { + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" + }, + "dependencies": { + "is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "dev": true, + "requires": { + "is-plain-object": "^2.0.4" + } + } + } + }, + "extglob": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", + "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==", + "dev": true, + "requires": { + "array-unique": "^0.3.2", + "define-property": "^1.0.0", + "expand-brackets": "^2.1.4", + "extend-shallow": "^2.0.1", + "fragment-cache": "^0.2.1", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "dependencies": { + "define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "dev": true, + "requires": { + "is-descriptor": "^1.0.0" + } + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + }, + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "dev": true, + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + } + } + }, + "fill-range": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", + "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", + "dev": true, + "requires": { + "extend-shallow": "^2.0.1", + "is-number": "^3.0.0", + "repeat-string": "^1.6.1", + "to-regex-range": "^2.1.0" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "find-cache-dir": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-2.1.0.tgz", + "integrity": "sha512-Tq6PixE0w/VMFfCgbONnkiQIVol/JJL7nRMi20fqzA4NRs9AfeqMGeRdPi3wIhYkxjeBaWh2rxwapn5Tu3IqOQ==", + "dev": true, + "requires": { + "commondir": "^1.0.1", + "make-dir": "^2.0.0", + "pkg-dir": "^3.0.0" + } + }, + "find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "dev": true, + "requires": { + "locate-path": "^3.0.0" + } + }, + "flow-parser": { + "version": "0.101.1", + "resolved": "https://registry.npmjs.org/flow-parser/-/flow-parser-0.101.1.tgz", + "integrity": "sha512-5XI7KnnndL1E0bmZp+SURCeNe0mZ86QHtwnmmn91J7Q3VptG26QEpH8pEecN+UgKRFm23K9zzTeesJhmuGA+mg==", + "dev": true + }, + "for-in": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", + "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=", + "dev": true + }, + "fragment-cache": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz", + "integrity": "sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk=", + "dev": true, + "requires": { + "map-cache": "^0.2.2" + } + }, + "get-value": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz", + "integrity": "sha1-3BXKHGcjh8p2vTesCjlbogQqLCg=", + "dev": true + }, + "globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "dev": true + }, + "graceful-fs": { + "version": "4.1.15", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.15.tgz", + "integrity": "sha512-6uHUhOPEBgQ24HM+r6b/QwWfZq+yiFcipKFrOFiBEnWdy5sdzYoi+pJeQaPI5qOLRFqWmAXUPQNsielzdLoecA==", + "dev": true + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "dev": true + }, + "has-value": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz", + "integrity": "sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc=", + "dev": true, + "requires": { + "get-value": "^2.0.6", + "has-values": "^1.0.0", + "isobject": "^3.0.0" + } + }, + "has-values": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-values/-/has-values-1.0.0.tgz", + "integrity": "sha1-lbC2P+whRmGab+V/51Yo1aOe/k8=", + "dev": true, + "requires": { + "is-number": "^3.0.0", + "kind-of": "^4.0.0" + }, + "dependencies": { + "is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", + "dev": true + }, + "kind-of": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz", + "integrity": "sha1-IIE989cSkosgc3hpGkUGb65y3Vc=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", + "dev": true + }, + "invariant": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz", + "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==", + "dev": true, + "requires": { + "loose-envify": "^1.0.0" + } + }, + "ip": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/ip/-/ip-1.1.5.tgz", + "integrity": "sha1-vd7XARQpCCjAoDnnLvJfWq7ENUo=", + "dev": true + }, + "is-accessor-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", + "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", + "dev": true + }, + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "is-data-descriptor": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", + "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", + "dev": true + }, + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "is-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", + "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", + "dev": true, + "requires": { + "is-accessor-descriptor": "^0.1.6", + "is-data-descriptor": "^0.1.4", + "kind-of": "^5.0.0" + }, + "dependencies": { + "kind-of": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", + "dev": true + } + } + }, + "is-extendable": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=", + "dev": true + }, + "is-number": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", + "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", + "dev": true + }, + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "dev": true, + "requires": { + "isobject": "^3.0.1" + } + }, + "is-windows": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", + "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==", + "dev": true + }, + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", + "dev": true + }, + "isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", + "dev": true + }, + "js-levenshtein": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/js-levenshtein/-/js-levenshtein-1.1.6.tgz", + "integrity": "sha512-X2BB11YZtrRqY4EnQcLX5Rh373zbK4alC1FW7D7MBhL2gtcC17cTnr6DmfHZeS0s2rTHjUTMMHfG7gO8SSdw+g==", + "dev": true + }, + "js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true + }, + "jscodeshift": { + "version": "0.6.4", + "resolved": "https://registry.npmjs.org/jscodeshift/-/jscodeshift-0.6.4.tgz", + "integrity": "sha512-+NF/tlNbc2WEhXUuc4WEJLsJumF84tnaMUZW2hyJw3jThKKRvsPX4sPJVgO1lPE28z0gNL+gwniLG9d8mYvQCQ==", + "dev": true, + "requires": { + "@babel/core": "^7.1.6", + "@babel/parser": "^7.1.6", + "@babel/plugin-proposal-class-properties": "^7.1.0", + "@babel/plugin-proposal-object-rest-spread": "^7.0.0", + "@babel/preset-env": "^7.1.6", + "@babel/preset-flow": "^7.0.0", + "@babel/preset-typescript": "^7.1.0", + "@babel/register": "^7.0.0", + "babel-core": "^7.0.0-bridge.0", + "colors": "^1.1.2", + "flow-parser": "0.*", + "graceful-fs": "^4.1.11", + "micromatch": "^3.1.10", + "neo-async": "^2.5.0", + "node-dir": "^0.1.17", + "recast": "^0.16.1", + "temp": "^0.8.1", + "write-file-atomic": "^2.3.0" + } + }, + "jsep": { + "version": "0.3.4", + "resolved": "https://registry.npmjs.org/jsep/-/jsep-0.3.4.tgz", + "integrity": "sha512-ovGD9wE+wvudIIYxZGrRcZCxNyZ3Cl1N7Bzyp7/j4d/tA0BaUwcVM9bu0oZaSrefMiNwv6TwZ9X15gvZosteCQ==", + "dev": true + }, + "jsesc": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", + "dev": true + }, + "json5": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.1.0.tgz", + "integrity": "sha512-8Mh9h6xViijj36g7Dxi+Y4S6hNGV96vcJZr/SrlHh1LR/pEn/8j/+qIBbs44YKl69Lrfctp4QD+AdWLTMqEZAQ==", + "dev": true, + "requires": { + "minimist": "^1.2.0" + }, + "dependencies": { + "minimist": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", + "dev": true + } + } + }, + "kind-of": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", + "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", + "dev": true + }, + "locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", "dev": true, "requires": { - "expression-eval": "^1.3.0", - "ip": "^1.1.5", - "lodash": "^4.17.10" + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" } }, - "debug": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", - "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "lodash": { + "version": "4.17.11", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz", + "integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==", + "dev": true + }, + "loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "dev": true, "requires": { - "ms": "^2.1.1" + "js-tokens": "^3.0.0 || ^4.0.0" } }, - "expression-eval": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/expression-eval/-/expression-eval-1.4.0.tgz", - "integrity": "sha512-CvpqG2feKjGcr+6NB/ZOA2csOeVL+2DSiWrF/4h0mrdYv4SxR2vCZhLHSst4Sp+xHtN/LQtPfi6i7K9EJwzRGw==", + "make-dir": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz", + "integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==", "dev": true, "requires": { - "jsep": "^0.3.0" + "pify": "^4.0.1", + "semver": "^5.6.0" + }, + "dependencies": { + "semver": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.0.tgz", + "integrity": "sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA==", + "dev": true + } } }, - "ip": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/ip/-/ip-1.1.5.tgz", - "integrity": "sha1-vd7XARQpCCjAoDnnLvJfWq7ENUo=", + "map-cache": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz", + "integrity": "sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8=", "dev": true }, - "jsep": { - "version": "0.3.4", - "resolved": "https://registry.npmjs.org/jsep/-/jsep-0.3.4.tgz", - "integrity": "sha512-ovGD9wE+wvudIIYxZGrRcZCxNyZ3Cl1N7Bzyp7/j4d/tA0BaUwcVM9bu0oZaSrefMiNwv6TwZ9X15gvZosteCQ==", - "dev": true + "map-visit": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz", + "integrity": "sha1-7Nyo8TFE5mDxtb1B8S80edmN+48=", + "dev": true, + "requires": { + "object-visit": "^1.0.0" + } }, - "lodash": { - "version": "4.17.11", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz", - "integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==", + "micromatch": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", + "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", + "dev": true, + "requires": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "braces": "^2.3.1", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "extglob": "^2.0.4", + "fragment-cache": "^0.2.1", + "kind-of": "^6.0.2", + "nanomatch": "^1.2.9", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.2" + } + }, + "minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "minimist": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", + "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", "dev": true }, + "mixin-deep": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.1.tgz", + "integrity": "sha512-8ZItLHeEgaqEvd5lYBXfm4EZSFCX29Jb9K+lAHhDKzReKBQKj3R+7NOF6tjqYi9t4oI8VUfaWITJQm86wnXGNQ==", + "dev": true, + "requires": { + "for-in": "^1.0.2", + "is-extendable": "^1.0.1" + }, + "dependencies": { + "is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "dev": true, + "requires": { + "is-plain-object": "^2.0.4" + } + } + } + }, + "mkdirp": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", + "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", + "dev": true, + "requires": { + "minimist": "0.0.8" + } + }, "ms": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==" + }, + "nanomatch": { + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz", + "integrity": "sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==", + "dev": true, + "requires": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "fragment-cache": "^0.2.1", + "is-windows": "^1.0.2", + "kind-of": "^6.0.2", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + } + }, + "neo-async": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.1.tgz", + "integrity": "sha512-iyam8fBuCUpWeKPGpaNMetEocMt364qkCsfL9JuhjXX6dRnguRVOfk2GZaDpPjcOKiiXCPINZC1GczQ7iTq3Zw==", + "dev": true + }, + "node-dir": { + "version": "0.1.17", + "resolved": "https://registry.npmjs.org/node-dir/-/node-dir-0.1.17.tgz", + "integrity": "sha1-X1Zl2TNRM1yqvvjxxVRRbPXx5OU=", + "dev": true, + "requires": { + "minimatch": "^3.0.2" + } + }, + "node-modules-regexp": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/node-modules-regexp/-/node-modules-regexp-1.0.0.tgz", + "integrity": "sha1-jZ2+KJZKSsVxLpExZCEHxx6Q7EA=", + "dev": true + }, + "node-releases": { + "version": "1.1.23", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.23.tgz", + "integrity": "sha512-uq1iL79YjfYC0WXoHbC/z28q/9pOl8kSHaXdWmAAc8No+bDwqkZbzIJz55g/MUsPgSGm9LZ7QSUbzTcH5tz47w==", + "dev": true, + "requires": { + "semver": "^5.3.0" + } + }, + "object-copy": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz", + "integrity": "sha1-fn2Fi3gb18mRpBupde04EnVOmYw=", + "dev": true, + "requires": { + "copy-descriptor": "^0.1.0", + "define-property": "^0.2.5", + "kind-of": "^3.0.3" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "requires": { + "is-descriptor": "^0.1.0" + } + }, + "is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", + "dev": true + }, + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "object-visit": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz", + "integrity": "sha1-95xEk68MU3e1n+OdOV5BBC3QRbs=", + "dev": true, + "requires": { + "isobject": "^3.0.0" + } + }, + "object.pick": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz", + "integrity": "sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c=", + "dev": true, + "requires": { + "isobject": "^3.0.1" + } + }, + "os-tmpdir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", + "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", + "dev": true + }, + "p-limit": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.2.0.tgz", + "integrity": "sha512-pZbTJpoUsCzV48Mc9Nh51VbwO0X9cuPFE8gYwx9BTCt9SF8/b7Zljd2fVgOxhIF/HDTKgpVzs+GPhyKfjLLFRQ==", + "dev": true, + "requires": { + "p-try": "^2.0.0" + } + }, + "p-locate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "dev": true, + "requires": { + "p-limit": "^2.0.0" + } + }, + "p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true + }, + "pascalcase": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz", + "integrity": "sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ=", + "dev": true + }, + "path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", + "dev": true + }, + "path-parse": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz", + "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==", + "dev": true + }, + "pify": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", + "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", + "dev": true + }, + "pirates": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.1.tgz", + "integrity": "sha512-WuNqLTbMI3tmfef2TKxlQmAiLHKtFhlsCZnPIpuv2Ow0RDVO8lfy1Opf4NUzlMXLjPl+Men7AuVdX6TA+s+uGA==", + "dev": true, + "requires": { + "node-modules-regexp": "^1.0.0" + } + }, + "pkg-dir": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-3.0.0.tgz", + "integrity": "sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw==", + "dev": true, + "requires": { + "find-up": "^3.0.0" + } + }, + "posix-character-classes": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz", + "integrity": "sha1-AerA/jta9xoqbAL+q7jB/vfgDqs=", + "dev": true + }, + "private": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/private/-/private-0.1.8.tgz", + "integrity": "sha512-VvivMrbvd2nKkiG38qjULzlc+4Vx4wm/whI9pQD35YrARNnhxeiRktSOhSukRLFNlzg6Br/cJPet5J/u19r/mg==", + "dev": true + }, + "recast": { + "version": "0.16.2", + "resolved": "https://registry.npmjs.org/recast/-/recast-0.16.2.tgz", + "integrity": "sha512-O/7qXi51DPjRVdbrpNzoBQH5dnAPQNbfoOFyRiUwreTMJfIHYOEBzwuH+c0+/BTSJ3CQyKs6ILSWXhESH6Op3A==", + "dev": true, + "requires": { + "ast-types": "0.11.7", + "esprima": "~4.0.0", + "private": "~0.1.5", + "source-map": "~0.6.1" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + } + } + }, + "regenerate": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.0.tgz", + "integrity": "sha512-1G6jJVDWrt0rK99kBjvEtziZNCICAuvIPkSiUFIQxVP06RCVpq3dmDo2oi6ABpYaDYaTRr67BEhL8r1wgEZZKg==", + "dev": true + }, + "regenerate-unicode-properties": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-8.1.0.tgz", + "integrity": "sha512-LGZzkgtLY79GeXLm8Dp0BVLdQlWICzBnJz/ipWUgo59qBaZ+BHtq51P2q1uVZlppMuUAT37SDk39qUbjTWB7bA==", + "dev": true, + "requires": { + "regenerate": "^1.4.0" + } + }, + "regenerator-transform": { + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.14.0.tgz", + "integrity": "sha512-rtOelq4Cawlbmq9xuMR5gdFmv7ku/sFoB7sRiywx7aq53bc52b4j6zvH7Te1Vt/X2YveDKnCGUbioieU7FEL3w==", + "dev": true, + "requires": { + "private": "^0.1.6" + } + }, + "regex-not": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz", + "integrity": "sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==", + "dev": true, + "requires": { + "extend-shallow": "^3.0.2", + "safe-regex": "^1.1.0" + } + }, + "regexp-tree": { + "version": "0.1.10", + "resolved": "https://registry.npmjs.org/regexp-tree/-/regexp-tree-0.1.10.tgz", + "integrity": "sha512-K1qVSbcedffwuIslMwpe6vGlj+ZXRnGkvjAtFHfDZZZuEdA/h0dxljAPu9vhUo6Rrx2U2AwJ+nSQ6hK+lrP5MQ==", + "dev": true + }, + "regexpu-core": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-4.5.4.tgz", + "integrity": "sha512-BtizvGtFQKGPUcTy56o3nk1bGRp4SZOTYrDtGNlqCQufptV5IkkLN6Emw+yunAJjzf+C9FQFtvq7IoA3+oMYHQ==", + "dev": true, + "requires": { + "regenerate": "^1.4.0", + "regenerate-unicode-properties": "^8.0.2", + "regjsgen": "^0.5.0", + "regjsparser": "^0.6.0", + "unicode-match-property-ecmascript": "^1.0.4", + "unicode-match-property-value-ecmascript": "^1.1.0" + } + }, + "regjsgen": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.5.0.tgz", + "integrity": "sha512-RnIrLhrXCX5ow/E5/Mh2O4e/oa1/jW0eaBKTSy3LaCj+M3Bqvm97GWDp2yUtzIs4LEn65zR2yiYGFqb2ApnzDA==", + "dev": true + }, + "regjsparser": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.6.0.tgz", + "integrity": "sha512-RQ7YyokLiQBomUJuUG8iGVvkgOLxwyZM8k6d3q5SAXpg4r5TZJZigKFvC6PpD+qQ98bCDC5YelPeA3EucDoNeQ==", + "dev": true, + "requires": { + "jsesc": "~0.5.0" + }, + "dependencies": { + "jsesc": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", + "integrity": "sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0=", + "dev": true + } + } + }, + "repeat-element": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.3.tgz", + "integrity": "sha512-ahGq0ZnV5m5XtZLMb+vP76kcAM5nkLqk0lpqAuojSKGgQtn4eRi4ZZGm2olo2zKFH+sMsWaqOCW1dqAnOru72g==", + "dev": true + }, + "repeat-string": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", + "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=", + "dev": true + }, + "resolve": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.11.1.tgz", + "integrity": "sha512-vIpgF6wfuJOZI7KKKSP+HmiKggadPQAdsp5HiC1mvqnfp0gF1vdwgBWZIdrVft9pgqoMFQN+R7BSWZiBxx+BBw==", + "dev": true, + "requires": { + "path-parse": "^1.0.6" + } + }, + "resolve-url": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz", + "integrity": "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=", + "dev": true + }, + "ret": { + "version": "0.1.15", + "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz", + "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==", + "dev": true + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true + }, + "safe-regex": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz", + "integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=", + "dev": true, + "requires": { + "ret": "~0.1.10" + } + }, + "semver": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.5.0.tgz", + "integrity": "sha512-4SJ3dm0WAwWy/NVeioZh5AntkdJoWKxHxcmyP622fOkgHa4z3R0TdBJICINyaSDE6uNwVc8gZr+ZinwZAH4xIA==", + "dev": true + }, + "set-value": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.0.tgz", + "integrity": "sha512-hw0yxk9GT/Hr5yJEYnHNKYXkIA8mVJgd9ditYZCe16ZczcaELYYcfvaXesNACk2O8O0nTiPQcQhGUQj8JLzeeg==", + "dev": true, + "requires": { + "extend-shallow": "^2.0.1", + "is-extendable": "^0.1.1", + "is-plain-object": "^2.0.3", + "split-string": "^3.0.1" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "signal-exit": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", + "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=", + "dev": true + }, + "snapdragon": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz", + "integrity": "sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg==", + "dev": true, + "requires": { + "base": "^0.11.1", + "debug": "^2.2.0", + "define-property": "^0.2.5", + "extend-shallow": "^2.0.1", + "map-cache": "^0.2.2", + "source-map": "^0.5.6", + "source-map-resolve": "^0.5.0", + "use": "^3.1.0" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "requires": { + "is-descriptor": "^0.1.0" + } + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + } + } + }, + "snapdragon-node": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/snapdragon-node/-/snapdragon-node-2.1.1.tgz", + "integrity": "sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==", + "dev": true, + "requires": { + "define-property": "^1.0.0", + "isobject": "^3.0.0", + "snapdragon-util": "^3.0.1" + }, + "dependencies": { + "define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "dev": true, + "requires": { + "is-descriptor": "^1.0.0" + } + }, + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "dev": true, + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + } + } + }, + "snapdragon-util": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/snapdragon-util/-/snapdragon-util-3.0.1.tgz", + "integrity": "sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==", + "dev": true, + "requires": { + "kind-of": "^3.2.0" + }, + "dependencies": { + "is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", + "dev": true + }, + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true + }, + "source-map-resolve": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.2.tgz", + "integrity": "sha512-MjqsvNwyz1s0k81Goz/9vRBe9SZdB09Bdw+/zYyO+3CuPk6fouTaxscHkgtE8jKvf01kVfl8riHzERQ/kefaSA==", + "dev": true, + "requires": { + "atob": "^2.1.1", + "decode-uri-component": "^0.2.0", + "resolve-url": "^0.2.1", + "source-map-url": "^0.4.0", + "urix": "^0.1.0" + } + }, + "source-map-support": { + "version": "0.5.12", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.12.tgz", + "integrity": "sha512-4h2Pbvyy15EE02G+JOZpUCmqWJuqrs+sEkzewTm++BPi7Hvn/HwcqLAcNxYAyI0x13CpPPn+kMjl+hplXMHITQ==", + "dev": true, + "requires": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + } + } + }, + "source-map-url": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.0.tgz", + "integrity": "sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM=", + "dev": true + }, + "split-string": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz", + "integrity": "sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==", + "dev": true, + "requires": { + "extend-shallow": "^3.0.0" + } + }, + "static-extend": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz", + "integrity": "sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY=", + "dev": true, + "requires": { + "define-property": "^0.2.5", + "object-copy": "^0.1.0" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "requires": { + "is-descriptor": "^0.1.0" + } + } + } + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + }, + "temp": { + "version": "0.8.3", + "resolved": "https://registry.npmjs.org/temp/-/temp-0.8.3.tgz", + "integrity": "sha1-4Ma8TSa5AxJEEOT+2BEDAU38H1k=", + "dev": true, + "requires": { + "os-tmpdir": "^1.0.0", + "rimraf": "~2.2.6" + }, + "dependencies": { + "rimraf": { + "version": "2.2.8", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.2.8.tgz", + "integrity": "sha1-5Dm+Kq7jJzIZUnMPmaiSnk/FBYI=", + "dev": true + } + } + }, + "to-fast-properties": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", + "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=", + "dev": true + }, + "to-object-path": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz", + "integrity": "sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", + "dev": true + }, + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "to-regex": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/to-regex/-/to-regex-3.0.2.tgz", + "integrity": "sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==", + "dev": true, + "requires": { + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "regex-not": "^1.0.2", + "safe-regex": "^1.1.0" + } + }, + "to-regex-range": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", + "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", + "dev": true, + "requires": { + "is-number": "^3.0.0", + "repeat-string": "^1.6.1" + } + }, + "trim-right": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/trim-right/-/trim-right-1.0.1.tgz", + "integrity": "sha1-yy4SAwZ+DI3h9hQJS5/kVwTqYAM=", + "dev": true + }, + "unicode-canonical-property-names-ecmascript": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-1.0.4.tgz", + "integrity": "sha512-jDrNnXWHd4oHiTZnx/ZG7gtUTVp+gCcTTKr8L0HjlwphROEW3+Him+IpvC+xcJEFegapiMZyZe02CyuOnRmbnQ==", + "dev": true + }, + "unicode-match-property-ecmascript": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-1.0.4.tgz", + "integrity": "sha512-L4Qoh15vTfntsn4P1zqnHulG0LdXgjSO035fEpdtp6YxXhMT51Q6vgM5lYdG/5X3MjS+k/Y9Xw4SFCY9IkR0rg==", + "dev": true, + "requires": { + "unicode-canonical-property-names-ecmascript": "^1.0.4", + "unicode-property-aliases-ecmascript": "^1.0.4" + } + }, + "unicode-match-property-value-ecmascript": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-1.1.0.tgz", + "integrity": "sha512-hDTHvaBk3RmFzvSl0UVrUmC3PuW9wKVnpoUDYH0JDkSIovzw+J5viQmeYHxVSBptubnr7PbH2e0fnpDRQnQl5g==", + "dev": true + }, + "unicode-property-aliases-ecmascript": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-1.0.5.tgz", + "integrity": "sha512-L5RAqCfXqAwR3RriF8pM0lU0w4Ryf/GgzONwi6KnL1taJQa7x1TCxdJnILX59WIGOwR57IVxn7Nej0fz1Ny6fw==", + "dev": true + }, + "union-value": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.0.tgz", + "integrity": "sha1-XHHDTLW61dzr4+oM0IIHulqhrqQ=", + "dev": true, + "requires": { + "arr-union": "^3.1.0", + "get-value": "^2.0.6", + "is-extendable": "^0.1.1", + "set-value": "^0.4.3" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + }, + "set-value": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/set-value/-/set-value-0.4.3.tgz", + "integrity": "sha1-fbCPnT0i3H945Trzw79GZuzfzPE=", + "dev": true, + "requires": { + "extend-shallow": "^2.0.1", + "is-extendable": "^0.1.1", + "is-plain-object": "^2.0.1", + "to-object-path": "^0.3.0" + } + } + } + }, + "unset-value": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz", + "integrity": "sha1-g3aHP30jNRef+x5vw6jtDfyKtVk=", + "dev": true, + "requires": { + "has-value": "^0.3.1", + "isobject": "^3.0.0" + }, + "dependencies": { + "has-value": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/has-value/-/has-value-0.3.1.tgz", + "integrity": "sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8=", + "dev": true, + "requires": { + "get-value": "^2.0.3", + "has-values": "^0.1.4", + "isobject": "^2.0.0" + }, + "dependencies": { + "isobject": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", + "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=", + "dev": true, + "requires": { + "isarray": "1.0.0" + } + } + } + }, + "has-values": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/has-values/-/has-values-0.1.4.tgz", + "integrity": "sha1-bWHeldkd/Km5oCCJrThL/49it3E=", + "dev": true + } + } + }, + "urix": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz", + "integrity": "sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI=", + "dev": true + }, + "use": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz", + "integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==", + "dev": true + }, + "write-file-atomic": { + "version": "2.4.3", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-2.4.3.tgz", + "integrity": "sha512-GaETH5wwsX+GcnzhPgKcKjJ6M2Cq3/iZp1WyY/X1CSqrW+jVNM9Y7D8EC2sM4ZG/V8wZlSniJnCKWPmBYAucRQ==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.11", + "imurmurhash": "^0.1.4", + "signal-exit": "^3.0.2" + } } } } diff --git a/packages/authorization/package.json b/packages/authorization/package.json index e8a0be101a44..3880809f62ff 100644 --- a/packages/authorization/package.json +++ b/packages/authorization/package.json @@ -1,15 +1,14 @@ { "name": "@loopback/authorization", - "version": "0.1.0", + "version": "1.0.0", "description": "A LoopBack component for authorization support.", "engines": { - "node": ">=8" + "node": ">=8.9" }, "scripts": { "acceptance": "lb-mocha \"dist/__tests__/acceptance/**/*.js\"", - "build": "lb-tsc es2017 --outDir dist", - "build:apidocs": "lb-apidocs", - "clean": "lb-clean loopback-authorization*.tgz dist package api-docs", + "build": "lb-tsc", + "clean": "lb-clean loopback-authorization*.tgz dist package *.tsbuildinfo", "integration": "lb-mocha \"dist/__tests__/integration/**/*.js\"", "prepublishOnly": "npm run build && npm run build:apidocs", "pretest": "npm run build", @@ -26,10 +25,10 @@ "debug": "^4.1.1" }, "devDependencies": { - "@loopback/build": "^1.5.2", + "@loopback/build": "^2.0.2", "@loopback/testlab": "^1.2.7", "@types/debug": "^4.1.4", - "casbin": "^2.0.4" + "casbin": "^3.0.1" }, "keywords": [ "LoopBack", diff --git a/packages/authorization/src/__tests__/unit/authorize-decorator.test.ts b/packages/authorization/src/__tests__/unit/authorize-decorator.test.ts index f133c0f71439..8141010029cf 100644 --- a/packages/authorization/src/__tests__/unit/authorize-decorator.test.ts +++ b/packages/authorization/src/__tests__/unit/authorize-decorator.test.ts @@ -98,7 +98,7 @@ describe('Authentication', () => { }); }); - it('can add allowAuthenticated to target method', () => { + it('can add denyUnauthenticated to target method', () => { class TestClass { @authorize.denyUnauthenticated() getSecret() {} diff --git a/packages/authorization/tsconfig.build.json b/packages/authorization/tsconfig.build.json index 85351e10ace0..ad0770b33b6d 100644 --- a/packages/authorization/tsconfig.build.json +++ b/packages/authorization/tsconfig.build.json @@ -2,6 +2,7 @@ "$schema": "http://json.schemastore.org/tsconfig", "extends": "@loopback/build/config/tsconfig.common.json", "compilerOptions": { + "outDir": "dist", "rootDir": "src" }, "include": ["src"] From 15c64ceb81d891287bcdb118cc5d2a4583854cd8 Mon Sep 17 00:00:00 2001 From: Raymond Feng Date: Tue, 25 Jun 2019 13:58:59 -0700 Subject: [PATCH 05/10] chore(authorization): rename some types --- packages/authorization/package.json | 8 +++--- .../authorization-casbin.acceptance.ts | 6 ++--- .../acceptance/authorization.acceptance.ts | 6 ++--- .../src/authorize-interceptor.ts | 8 ++---- .../authorization/src/decorators/authorize.ts | 27 ++++++++++++++++--- packages/authorization/src/types.ts | 16 +++++------ 6 files changed, 43 insertions(+), 28 deletions(-) diff --git a/packages/authorization/package.json b/packages/authorization/package.json index 3880809f62ff..46acbf7aa539 100644 --- a/packages/authorization/package.json +++ b/packages/authorization/package.json @@ -20,13 +20,13 @@ "copyright.owner": "IBM Corp.", "license": "MIT", "dependencies": { - "@loopback/context": "^1.13.0", - "@loopback/core": "^1.6.2", + "@loopback/context": "^1.20.2", + "@loopback/core": "^1.8.5", "debug": "^4.1.1" }, "devDependencies": { - "@loopback/build": "^2.0.2", - "@loopback/testlab": "^1.2.7", + "@loopback/build": "^2.0.3", + "@loopback/testlab": "^1.6.3", "@types/debug": "^4.1.4", "casbin": "^3.0.1" }, diff --git a/packages/authorization/src/__tests__/acceptance/authorization-casbin.acceptance.ts b/packages/authorization/src/__tests__/acceptance/authorization-casbin.acceptance.ts index 09777896b846..dba3eae26301 100644 --- a/packages/authorization/src/__tests__/acceptance/authorization-casbin.acceptance.ts +++ b/packages/authorization/src/__tests__/acceptance/authorization-casbin.acceptance.ts @@ -15,7 +15,7 @@ import { AuthorizationMetadata, AuthorizationRequest, authorize, - AuthorizeFn, + Authorizer, } from '../..'; describe('Authorization', () => { @@ -120,13 +120,13 @@ describe('Authorization', () => { /** * Provider of a function which authenticates */ - class CasbinAuthorizationProvider implements Provider { + class CasbinAuthorizationProvider implements Provider { constructor(@inject('casbin.enforcer') private enforcer: casbin.Enforcer) {} /** * @returns authenticateFn */ - value(): AuthorizeFn { + value(): Authorizer { return async ( authzCtx: AuthorizationContext, metadata: AuthorizationMetadata, diff --git a/packages/authorization/src/__tests__/acceptance/authorization.acceptance.ts b/packages/authorization/src/__tests__/acceptance/authorization.acceptance.ts index fe2a754e3151..ca2582646791 100644 --- a/packages/authorization/src/__tests__/acceptance/authorization.acceptance.ts +++ b/packages/authorization/src/__tests__/acceptance/authorization.acceptance.ts @@ -12,7 +12,7 @@ import { AuthorizationDecision, AuthorizationMetadata, authorize, - AuthorizeFn, + Authorizer, EVERYONE, } from '../..'; @@ -92,13 +92,13 @@ describe('Authorization', () => { /** * Provider of a function which authenticates */ - class MyAuthorizationProvider implements Provider { + class MyAuthorizationProvider implements Provider { constructor() {} /** * @returns authenticateFn */ - value(): AuthorizeFn { + value(): Authorizer { return async ( context: AuthorizationContext, metadata: AuthorizationMetadata, diff --git a/packages/authorization/src/authorize-interceptor.ts b/packages/authorization/src/authorize-interceptor.ts index d1fabccbc02c..7f52ec189014 100644 --- a/packages/authorization/src/authorize-interceptor.ts +++ b/packages/authorization/src/authorize-interceptor.ts @@ -13,11 +13,7 @@ import { } from '@loopback/context'; import * as debugFactory from 'debug'; import {getAuthorizeMetadata} from './decorators/authorize'; -import { - AuthorizationContext, - AuthorizationDecision, - AuthorizeFn, -} from './types'; +import {AuthorizationContext, AuthorizationDecision, Authorizer} from './types'; const debug = debugFactory('loopback:authorization:interceptor'); @@ -25,7 +21,7 @@ const debug = debugFactory('loopback:authorization:interceptor'); export class AuthorizationInterceptor implements Provider { constructor( @inject(filterByTag('authorizationProvider')) - private authorizationFunctions: AuthorizeFn[], + private authorizationFunctions: Authorizer[], ) {} value(): Interceptor { diff --git a/packages/authorization/src/decorators/authorize.ts b/packages/authorization/src/decorators/authorize.ts index 80aa941e0219..405a91a47f56 100644 --- a/packages/authorization/src/decorators/authorize.ts +++ b/packages/authorization/src/decorators/authorize.ts @@ -5,11 +5,11 @@ import { BindingAddress, + MetadataAccessor, MetadataInspector, MetadataMap, MethodDecoratorFactory, } from '@loopback/context'; -import {AuthorizationBindings} from '../keys'; import { AUTHENTICATED, AuthorizationMetadata, @@ -18,6 +18,16 @@ import { Voter, } from '../types'; +export const AUTHORIZATION_METHOD_KEY = MetadataAccessor.create< + AuthorizationMetadata, + MethodDecorator +>('authorization:method'); + +export const AUTHORIZATION_CLASS_KEY = MetadataAccessor.create< + AuthorizationMetadata, + ClassDecorator +>('authorization:class'); + export class AuthorizeMethodDecoratorFactory extends MethodDecoratorFactory< AuthorizationMetadata > { @@ -79,7 +89,7 @@ export class AuthorizeMethodDecoratorFactory extends MethodDecoratorFactory< */ export function authorize(spec: AuthorizationMetadata) { return AuthorizeMethodDecoratorFactory.createDecorator( - AuthorizationBindings.METADATA, + AUTHORIZATION_METHOD_KEY, spec, ); } @@ -158,12 +168,21 @@ export function getAuthorizeMetadata( target: object, methodName: string, ): AuthorizationMetadata | undefined { + let targetClass: Function; if (typeof target === 'function') { + targetClass = target; target = target.prototype; + } else { + targetClass = target.constructor; } - return MetadataInspector.getMethodMetadata( - AuthorizationBindings.METADATA, + let metadata = MetadataInspector.getMethodMetadata( + AUTHORIZATION_METHOD_KEY, target, methodName, ); + if (metadata) return metadata; + return MetadataInspector.getClassMetadata( + AUTHORIZATION_CLASS_KEY, + targetClass, + ); } diff --git a/packages/authorization/src/types.ts b/packages/authorization/src/types.ts index 5997321f1f27..a1c74b15dd61 100644 --- a/packages/authorization/src/types.ts +++ b/packages/authorization/src/types.ts @@ -25,9 +25,9 @@ export enum VotingDecision { /** * A voter function */ -export interface Voter { - (authzCtx: AuthorizationContext): Promise; -} +export type Voter = ( + authorizationCtx: AuthorizationContext, +) => Promise; /** * Authorization metadata stored via Reflection API @@ -198,15 +198,15 @@ export interface AuthorizationContext { /** * A function to decide if access to the target should be allowed or denied */ -export interface AuthorizeFn { +export type Authorizer = /** * @param context: Context information for authorization * @param metadata: Metadata representing requirements for authorization */ - (context: AuthorizationContext, metadata: AuthorizationMetadata): Promise< - AuthorizationDecision - >; -} + ( + context: AuthorizationContext, + metadata: AuthorizationMetadata, + ) => Promise; /** * Inspired by https://github.com/casbin/node-casbin From 5675415ac09ee16f143bf0c5d3f5f5c2154d2b06 Mon Sep 17 00:00:00 2001 From: Raymond Feng Date: Fri, 28 Jun 2019 10:06:50 -0700 Subject: [PATCH 06/10] feat(authorization): allows @authorize decorator to be applied at class level --- .../unit/authorize-decorator.test.ts | 45 +++++++++++++++++++ .../authorization/src/decorators/authorize.ts | 43 +++++++++++++++--- 2 files changed, 83 insertions(+), 5 deletions(-) diff --git a/packages/authorization/src/__tests__/unit/authorize-decorator.test.ts b/packages/authorization/src/__tests__/unit/authorize-decorator.test.ts index 8141010029cf..2b4c50d9495d 100644 --- a/packages/authorization/src/__tests__/unit/authorize-decorator.test.ts +++ b/packages/authorization/src/__tests__/unit/authorize-decorator.test.ts @@ -36,6 +36,51 @@ describe('Authentication', () => { }); }); + it('can add authorize metadata to target class', () => { + @authorize({allowedRoles: ['ADMIN'], scopes: ['secret.read']}) + class TestClass { + getSecret() {} + + @authorize({allowedRoles: ['OWNER'], scopes: ['data.update']}) + update() {} + } + + let metaData = getAuthorizeMetadata(TestClass, 'getSecret'); + expect(metaData).to.eql({ + allowedRoles: ['ADMIN'], + scopes: ['secret.read'], + }); + + metaData = getAuthorizeMetadata(TestClass, 'update'); + expect(metaData).to.eql({ + allowedRoles: ['OWNER'], + scopes: ['data.update'], + }); + }); + + it('honors method level decoration over class level', () => { + @authorize({allowedRoles: ['ADMIN'], scopes: ['secret']}) + class TestClass { + @authorize({allowedRoles: ['ADMIN'], scopes: ['secret.read']}) + getSecret() {} + + @authorize({allowedRoles: ['OWNER'], scopes: ['data.update']}) + update() {} + } + + let metaData = getAuthorizeMetadata(TestClass, 'getSecret'); + expect(metaData).to.eql({ + allowedRoles: ['ADMIN'], + scopes: ['secret.read'], + }); + + metaData = getAuthorizeMetadata(TestClass, 'update'); + expect(metaData).to.eql({ + allowedRoles: ['OWNER'], + scopes: ['data.update'], + }); + }); + it('can add allowAll to target method', () => { class TestClass { @authorize.allowAll() diff --git a/packages/authorization/src/decorators/authorize.ts b/packages/authorization/src/decorators/authorize.ts index 405a91a47f56..cba0866fa99b 100644 --- a/packages/authorization/src/decorators/authorize.ts +++ b/packages/authorization/src/decorators/authorize.ts @@ -5,6 +5,8 @@ import { BindingAddress, + ClassDecoratorFactory, + DecoratorFactory, MetadataAccessor, MetadataInspector, MetadataMap, @@ -28,6 +30,10 @@ export const AUTHORIZATION_CLASS_KEY = MetadataAccessor.create< ClassDecorator >('authorization:class'); +class AuthorizeClassDecoratorFactory extends ClassDecoratorFactory< + AuthorizationMetadata +> {} + export class AuthorizeMethodDecoratorFactory extends MethodDecoratorFactory< AuthorizationMetadata > { @@ -88,10 +94,36 @@ export class AuthorizeMethodDecoratorFactory extends MethodDecoratorFactory< * @param spec Authorization metadata */ export function authorize(spec: AuthorizationMetadata) { - return AuthorizeMethodDecoratorFactory.createDecorator( - AUTHORIZATION_METHOD_KEY, - spec, - ); + return function authorizeDecoratorForClassOrMethod( + // Class or a prototype + // eslint-disable-next-line @typescript-eslint/no-explicit-any + target: any, + method?: string, + // Use `any` to for `TypedPropertyDescriptor` + // See https://github.com/strongloop/loopback-next/pull/2704 + // eslint-disable-next-line @typescript-eslint/no-explicit-any + methodDescriptor?: TypedPropertyDescriptor, + ) { + if (method && methodDescriptor) { + // Method + return AuthorizeMethodDecoratorFactory.createDecorator( + AUTHORIZATION_METHOD_KEY, + spec, + )(target, method, methodDescriptor!); + } + if (typeof target === 'function' && !method && !methodDescriptor) { + // Class + return AuthorizeClassDecoratorFactory.createDecorator( + AUTHORIZATION_CLASS_KEY, + spec, + )(target); + } + // Not on a class or method + throw new Error( + '@intercept cannot be used on a property: ' + + DecoratorFactory.getTargetName(target, method, methodDescriptor), + ); + }; } export namespace authorize { @@ -175,12 +207,13 @@ export function getAuthorizeMetadata( } else { targetClass = target.constructor; } - let metadata = MetadataInspector.getMethodMetadata( + const metadata = MetadataInspector.getMethodMetadata( AUTHORIZATION_METHOD_KEY, target, methodName, ); if (metadata) return metadata; + // Check if the class level has `@authorize` return MetadataInspector.getClassMetadata( AUTHORIZATION_CLASS_KEY, targetClass, From d90bfeb59142633a7c5a4298b5c6345913f4dca3 Mon Sep 17 00:00:00 2001 From: Raymond Feng Date: Fri, 28 Jun 2019 11:18:53 -0700 Subject: [PATCH 07/10] chore(authorization): add an architecture diagram --- packages/authorization/README.md | 2 ++ packages/authorization/authorization.png | Bin 0 -> 216915 bytes 2 files changed, 2 insertions(+) create mode 100644 packages/authorization/authorization.png diff --git a/packages/authorization/README.md b/packages/authorization/README.md index 4a9c4dd65676..bf301837d011 100644 --- a/packages/authorization/README.md +++ b/packages/authorization/README.md @@ -7,6 +7,8 @@ A LoopBack 4 component for authorization support. Authorization decides if a **subject** can perform specific **action** on an **object**. +![Authorization](authorization.png) + ### Role based ### Permission based diff --git a/packages/authorization/authorization.png b/packages/authorization/authorization.png new file mode 100644 index 0000000000000000000000000000000000000000..64cc8a9c7a527040ddd9fa86efd9314b1673efea GIT binary patch literal 216915 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 z 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

;fDiPjT_A|G_`0snzI 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

GsEe2R; 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 Date: Mon, 1 Jul 2019 09:42:08 -0700 Subject: [PATCH 08/10] chore(authorization): more refactoring --- .../authorization-casbin.acceptance.ts | 22 ++--- .../acceptance/authorization.acceptance.ts | 21 ++--- .../src/authorize-interceptor.ts | 92 ++++++++++++------- .../authorization/src/decorators/authorize.ts | 7 +- packages/authorization/src/keys.ts | 12 ++- packages/authorization/src/types.ts | 49 ++++------ 6 files changed, 113 insertions(+), 90 deletions(-) diff --git a/packages/authorization/src/__tests__/acceptance/authorization-casbin.acceptance.ts b/packages/authorization/src/__tests__/acceptance/authorization-casbin.acceptance.ts index dba3eae26301..8acc790d4ffb 100644 --- a/packages/authorization/src/__tests__/acceptance/authorization-casbin.acceptance.ts +++ b/packages/authorization/src/__tests__/acceptance/authorization-casbin.acceptance.ts @@ -17,6 +17,7 @@ import { authorize, Authorizer, } from '../..'; +import {AuthorizationTags} from '../../keys'; describe('Authorization', () => { let app: Application; @@ -24,7 +25,7 @@ describe('Authorization', () => { let reqCtx: Context; let events: string[]; - before(givenApplication); + before(givenApplicationAndAuthorizer); beforeEach(givenRequestContext); it('allows placeOrder for everyone', async () => { @@ -100,14 +101,14 @@ describe('Authorization', () => { } } - function givenApplication() { + function givenApplicationAndAuthorizer() { app = new Application(); app.component(AuthorizationComponent); app.bind('casbin.enforcer').toDynamicValue(createEnforcer); app .bind('authorizationProviders.casbin-provider') .toProvider(CasbinAuthorizationProvider) - .tag('authorizationProvider'); + .tag(AuthorizationTags.AUTHORIZER); } function givenRequestContext(user = {name: 'alice'}) { @@ -127,22 +128,17 @@ describe('Authorization', () => { * @returns authenticateFn */ value(): Authorizer { - return async ( - authzCtx: AuthorizationContext, - metadata: AuthorizationMetadata, - ) => { - return this.authorize(authzCtx, metadata); - }; + return this.authorize.bind(this); } async authorize( - authzCtx: AuthorizationContext, + authorizationCtx: AuthorizationContext, metadata: AuthorizationMetadata, ) { - events.push(authzCtx.resource); + events.push(authorizationCtx.resource); const request: AuthorizationRequest = { - subject: authzCtx.principals[0].name, - object: metadata.resource || authzCtx.resource, + subject: authorizationCtx.principals[0].name, + object: metadata.resource || authorizationCtx.resource, action: (metadata.scopes && metadata.scopes[0]) || 'execute', }; const allow = await this.enforcer.enforce( diff --git a/packages/authorization/src/__tests__/acceptance/authorization.acceptance.ts b/packages/authorization/src/__tests__/acceptance/authorization.acceptance.ts index ca2582646791..144470748cf8 100644 --- a/packages/authorization/src/__tests__/acceptance/authorization.acceptance.ts +++ b/packages/authorization/src/__tests__/acceptance/authorization.acceptance.ts @@ -15,6 +15,7 @@ import { Authorizer, EVERYONE, } from '../..'; +import {AuthorizationTags} from '../../keys'; describe('Authorization', () => { let app: Application; @@ -22,7 +23,7 @@ describe('Authorization', () => { let reqCtx: Context; let events: string[]; - before(givenApplication); + before(givenApplicationAndAuthorizer); beforeEach(givenRequestContext); it('allows placeOrder for everyone', async () => { @@ -73,13 +74,13 @@ describe('Authorization', () => { } } - function givenApplication() { + function givenApplicationAndAuthorizer() { app = new Application(); app.component(AuthorizationComponent); app .bind('authorizationProviders.my-provider') .toProvider(MyAuthorizationProvider) - .tag('authorizationProvider'); + .tag(AuthorizationTags.AUTHORIZER); } function givenRequestContext() { @@ -93,21 +94,17 @@ describe('Authorization', () => { * Provider of a function which authenticates */ class MyAuthorizationProvider implements Provider { - constructor() {} - /** * @returns authenticateFn */ value(): Authorizer { - return async ( - context: AuthorizationContext, - metadata: AuthorizationMetadata, - ) => { - return this.authorize(context, metadata); - }; + return this.authorize.bind(this); } - authorize(context: AuthorizationContext, metadata: AuthorizationMetadata) { + async authorize( + context: AuthorizationContext, + metadata: AuthorizationMetadata, + ) { events.push(context.resource); if ( context.resource === 'OrderController.prototype.cancelOrder' && diff --git a/packages/authorization/src/authorize-interceptor.ts b/packages/authorization/src/authorize-interceptor.ts index 7f52ec189014..18c8bee43dc7 100644 --- a/packages/authorization/src/authorize-interceptor.ts +++ b/packages/authorization/src/authorize-interceptor.ts @@ -6,13 +6,18 @@ import { asGlobalInterceptor, bind, + BindingAddress, + Context, filterByTag, inject, Interceptor, + InvocationContext, + Next, Provider, } from '@loopback/context'; import * as debugFactory from 'debug'; import {getAuthorizeMetadata} from './decorators/authorize'; +import {AuthorizationTags} from './keys'; import {AuthorizationContext, AuthorizationDecision, Authorizer} from './types'; const debug = debugFactory('loopback:authorization:interceptor'); @@ -20,41 +25,66 @@ const debug = debugFactory('loopback:authorization:interceptor'); @bind(asGlobalInterceptor('authorization')) export class AuthorizationInterceptor implements Provider { constructor( - @inject(filterByTag('authorizationProvider')) - private authorizationFunctions: Authorizer[], + @inject(filterByTag(AuthorizationTags.AUTHORIZER)) + private authorizers: Authorizer[], ) {} value(): Interceptor { - return async (invocationCtx, next) => { - const description = debug.enabled ? invocationCtx.description : ''; - const metadata = getAuthorizeMetadata( - invocationCtx.target, - invocationCtx.methodName, - ); - if (!metadata) { - debug('No authorization metadata is found %s', description); - return await next(); - } - debug('Authorization metadata for %s', description, metadata); - const user = await invocationCtx.get<{name: string}>('current.user', { - optional: true, - }); - debug('Current user', user); - const authCtx: AuthorizationContext = { - principals: user ? [{name: user.name, type: 'USER'}] : [], - roles: [], - scopes: [], - resource: invocationCtx.targetName, - invocationContext: invocationCtx, - }; - debug('Security context for %s', description, authCtx); - for (const fn of this.authorizationFunctions) { - const decision = await fn(authCtx, metadata); - if (decision === AuthorizationDecision.DENY) { - throw new Error('Access denied'); - } - } + return this.intercept.bind(this); + } + + async intercept(invocationCtx: InvocationContext, next: Next) { + const description = debug.enabled ? invocationCtx.description : ''; + const metadata = getAuthorizeMetadata( + invocationCtx.target, + invocationCtx.methodName, + ); + if (!metadata) { + debug('No authorization metadata is found %s', description); return await next(); + } + debug('Authorization metadata for %s', description, metadata); + const user = await invocationCtx.get<{name: string}>('current.user', { + optional: true, + }); + debug('Current user', user); + const authorizationCtx: AuthorizationContext = { + principals: user ? [{name: user.name, type: 'USER'}] : [], + roles: [], + scopes: [], + resource: invocationCtx.targetName, + invocationContext: invocationCtx, }; + debug('Security context for %s', description, authorizationCtx); + let authorizers = await loadAuthorizers( + invocationCtx, + metadata.voters || [], + ); + authorizers = authorizers.concat(this.authorizers); + for (const fn of authorizers) { + const decision = await fn(authorizationCtx, metadata); + if (decision === AuthorizationDecision.DENY) { + throw new Error('Access denied'); + } + } + return await next(); + } +} + +async function loadAuthorizers( + ctx: Context, + authorizers: (Authorizer | BindingAddress)[], +) { + const authorizerFunctions: Authorizer[] = []; + const bindings = ctx.findByTag(AuthorizationTags.AUTHORIZER); + authorizers = authorizers.concat(bindings.map(b => b.key)); + for (const keyOrFn of authorizers) { + if (typeof keyOrFn === 'function') { + authorizerFunctions.push(keyOrFn); + } else { + const fn = await ctx.get(keyOrFn); + authorizerFunctions.push(fn); + } } + return authorizerFunctions; } diff --git a/packages/authorization/src/decorators/authorize.ts b/packages/authorization/src/decorators/authorize.ts index cba0866fa99b..6ea97a7e6355 100644 --- a/packages/authorization/src/decorators/authorize.ts +++ b/packages/authorization/src/decorators/authorize.ts @@ -15,9 +15,9 @@ import { import { AUTHENTICATED, AuthorizationMetadata, + Authorizer, EVERYONE, UNAUTHENTICATED, - Voter, } from '../types'; export const AUTHORIZATION_METHOD_KEY = MetadataAccessor.create< @@ -147,8 +147,9 @@ export namespace authorize { * Shortcut to configure voters * @param voters */ - export const vote = (...voters: (Voter | BindingAddress)[]) => - authorize({voters}); + export const vote = ( + ...voters: (Authorizer | BindingAddress)[] + ) => authorize({voters}); /** * Allows all diff --git a/packages/authorization/src/keys.ts b/packages/authorization/src/keys.ts index 01b950d87001..3de0b5b3a8a6 100644 --- a/packages/authorization/src/keys.ts +++ b/packages/authorization/src/keys.ts @@ -4,8 +4,18 @@ // License text available at https://opensource.org/licenses/MIT /** - * Binding keys used by this component. + * Binding keys used by authorization component. */ export namespace AuthorizationBindings { export const METADATA = 'authorization.operationMetadata'; } + +/** + * Binding tags used by authorization component + */ +export namespace AuthorizationTags { + /** + * A tag for authorizers + */ + export const AUTHORIZER = 'authorizer'; +} diff --git a/packages/authorization/src/types.ts b/packages/authorization/src/types.ts index a1c74b15dd61..009edc13f35b 100644 --- a/packages/authorization/src/types.ts +++ b/packages/authorization/src/types.ts @@ -14,23 +14,25 @@ export const UNAUTHENTICATED = '$unauthenticated'; export const ANONYMOUS = '$anonymous'; /** - * Voting decision for the authorization decision + * Decisions for authorization */ -export enum VotingDecision { +export enum AuthorizationDecision { + /** + * Access allowed + */ ALLOW = 'Allow', + /** + * Access denied + */ DENY = 'Deny', + /** + * No decision + */ ABSTAIN = 'Abstain', } /** - * A voter function - */ -export type Voter = ( - authorizationCtx: AuthorizationContext, -) => Promise; - -/** - * Authorization metadata stored via Reflection API + * Authorization metadata supplied via `@authorize` decorator */ export interface AuthorizationMetadata { /** @@ -41,10 +43,11 @@ export interface AuthorizationMetadata { * Roles that are denied access */ deniedRoles?: string[]; + /** * Voters that help make the authorization decision */ - voters?: (Voter | BindingAddress)[]; + voters?: (Authorizer | BindingAddress)[]; /** * Name of the resource, default to the method name @@ -56,24 +59,6 @@ export interface AuthorizationMetadata { scopes?: string[]; } -/** - * Decisions for authorization - */ -export enum AuthorizationDecision { - /** - * Access allowed - */ - ALLOW = 'Allow', - /** - * Access denied - */ - DENY = 'Deny', - /** - * No decision - */ - ABSTAIN = 'Abstain', -} - /** * Represent a user, an application, or a device */ @@ -87,7 +72,7 @@ export interface Principal { */ type: string; - // organization + // organization/realm/domain/tenant // team/group // eslint-disable-next-line @typescript-eslint/no-explicit-any @@ -212,6 +197,10 @@ export type Authorizer = * Inspired by https://github.com/casbin/node-casbin */ export interface AuthorizationRequest { + /** + * The domain (realm/tenant) + */ + domain?: string; /** * The requestor that wants to access a resource. */ From 3c7ae65f2a0ea5763f57263f85aa9db6c94986d5 Mon Sep 17 00:00:00 2001 From: jannyHou Date: Fri, 9 Aug 2019 11:59:14 -0400 Subject: [PATCH 09/10] refactor(authorization): improve pr --- packages/authorization/README.md | 27 +++++++++++ packages/authorization/package-lock.json | 6 +++ packages/authorization/package.json | 4 +- .../authorization-casbin.acceptance.ts | 14 ++++-- .../acceptance/authorization.acceptance.ts | 5 +- .../src/authorize-interceptor.ts | 47 +++++++++++++++---- packages/authorization/src/types.ts | 23 ++++++++- 7 files changed, 109 insertions(+), 17 deletions(-) diff --git a/packages/authorization/README.md b/packages/authorization/README.md index bf301837d011..a7f225f9cca2 100644 --- a/packages/authorization/README.md +++ b/packages/authorization/README.md @@ -70,6 +70,33 @@ export class MyController { } ``` +## Extract common layer(TBD) + +`@loopback/authentication` and `@loopback/authorization` shares the client +information from the request. Therefore we need another module with +types/interfaces that describe the client, like `principles`, `userProfile`, +etc... A draft PR is created for this module: see branch +https://github.com/strongloop/loopback-next/tree/security/packages/security + +Since the common module is still in progress, as the first release of +`@loopback/authorization`, we have two choices to inject a user in the +interceptor: + +- `@loopback/authorization` requires `@loopback/authentication` as a dependency. + The interceptor injects the current user using + `AuthenticationBindings.CURRENT_USER`. Then we remove this dependency in the + common layer PR, two auth modules will depend on `@loopback/security`. + + - This is what's been done in my refactor PR, `Principle` and `UserProfile` + are still decoupled, I added a convertor function to turn a user profile + into a principle. + +- The interceptor injects the user using another key not related to + `@loopback/authentication`.(_Which means the code that injects the user stays + as it is in https://github.com/strongloop/loopback-next/pull/1205_). Then we + unify the user set and injection in the common layer PR: same as the 1st + choice, two auth modules will depend on `@loopback/security`. + ## Related resources ## Contributions diff --git a/packages/authorization/package-lock.json b/packages/authorization/package-lock.json index 9d8fca2d1f1c..8bfc19f38887 100644 --- a/packages/authorization/package-lock.json +++ b/packages/authorization/package-lock.json @@ -858,6 +858,12 @@ "integrity": "sha512-D9MyoQFI7iP5VdpEyPZyjjqIJ8Y8EDNQFIFVLOmeg1rI1xiHOChyUPMPRUVfqFCerxfE+yS3vMyj37F6IdtOoQ==", "dev": true }, + "@types/node": { + "version": "10.14.15", + "resolved": "https://registry.npmjs.org/@types/node/-/node-10.14.15.tgz", + "integrity": "sha512-CBR5avlLcu0YCILJiDIXeU2pTw7UK/NIxfC63m7d7CVamho1qDEzXKkOtEauQRPMy6MI8mLozth+JJkas7HY6g==", + "dev": true + }, "ansi-styles": { "version": "3.2.1", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", diff --git a/packages/authorization/package.json b/packages/authorization/package.json index 46acbf7aa539..0c10a994eefd 100644 --- a/packages/authorization/package.json +++ b/packages/authorization/package.json @@ -1,6 +1,6 @@ { "name": "@loopback/authorization", - "version": "1.0.0", + "version": "0.0.1", "description": "A LoopBack component for authorization support.", "engines": { "node": ">=8.9" @@ -27,7 +27,9 @@ "devDependencies": { "@loopback/build": "^2.0.3", "@loopback/testlab": "^1.6.3", + "@loopback/authentication": "^2.1.8", "@types/debug": "^4.1.4", + "@types/node": "10.14.15", "casbin": "^3.0.1" }, "keywords": [ diff --git a/packages/authorization/src/__tests__/acceptance/authorization-casbin.acceptance.ts b/packages/authorization/src/__tests__/acceptance/authorization-casbin.acceptance.ts index 8acc790d4ffb..766c0ccfedfb 100644 --- a/packages/authorization/src/__tests__/acceptance/authorization-casbin.acceptance.ts +++ b/packages/authorization/src/__tests__/acceptance/authorization-casbin.acceptance.ts @@ -18,6 +18,7 @@ import { Authorizer, } from '../..'; import {AuthorizationTags} from '../../keys'; +import {AuthenticationBindings, UserProfile} from '@loopback/authentication'; describe('Authorization', () => { let app: Application; @@ -26,7 +27,7 @@ describe('Authorization', () => { let events: string[]; before(givenApplicationAndAuthorizer); - beforeEach(givenRequestContext); + beforeEach(() => givenRequestContext()); it('allows placeOrder for everyone', async () => { const orderId = await invokeMethod(controller, 'placeOrder', reqCtx, [ @@ -42,6 +43,7 @@ describe('Authorization', () => { }); it('allows cancelOrder for customer_service', async () => { + givenRequestContext({id: 'customer_service', name: 'customer_service'}); const orderId = await controller.placeOrder({ customerId: 'bob', productId: 'product-a', @@ -56,7 +58,7 @@ describe('Authorization', () => { }); it('denies cancelOrder for bob', async () => { - givenRequestContext({name: 'bob'}); + givenRequestContext({id: 'bob', name: 'bob'}); const orderId = await controller.placeOrder({ customerId: 'bob', productId: 'product-a', @@ -111,10 +113,12 @@ describe('Authorization', () => { .tag(AuthorizationTags.AUTHORIZER); } - function givenRequestContext(user = {name: 'alice'}) { + function givenRequestContext( + user: UserProfile = {id: 'alice', name: 'alice'}, + ) { events = []; reqCtx = new Context(app); - reqCtx.bind('current.user').to(user); + reqCtx.bind(AuthenticationBindings.CURRENT_USER).to(user); controller = new OrderController(); } @@ -161,6 +165,6 @@ describe('Authorization', () => { __dirname, '../../../fixtures/casbin/rbac_policy.csv', ); - return await casbin.newEnforcer(conf, policy); + return casbin.newEnforcer(conf, policy); } }); diff --git a/packages/authorization/src/__tests__/acceptance/authorization.acceptance.ts b/packages/authorization/src/__tests__/acceptance/authorization.acceptance.ts index 144470748cf8..b77d9ea4788d 100644 --- a/packages/authorization/src/__tests__/acceptance/authorization.acceptance.ts +++ b/packages/authorization/src/__tests__/acceptance/authorization.acceptance.ts @@ -16,6 +16,7 @@ import { EVERYONE, } from '../..'; import {AuthorizationTags} from '../../keys'; +import {AuthenticationBindings} from '@loopback/authentication'; describe('Authorization', () => { let app: Application; @@ -86,7 +87,9 @@ describe('Authorization', () => { function givenRequestContext() { events = []; reqCtx = new Context(app); - reqCtx.bind('current.user').to({name: 'user-01'}); + reqCtx + .bind(AuthenticationBindings.CURRENT_USER) + .to({id: 'user-01', name: 'user-01'}); controller = new OrderController(); } diff --git a/packages/authorization/src/authorize-interceptor.ts b/packages/authorization/src/authorize-interceptor.ts index 18c8bee43dc7..850bea3a4569 100644 --- a/packages/authorization/src/authorize-interceptor.ts +++ b/packages/authorization/src/authorize-interceptor.ts @@ -18,7 +18,14 @@ import { import * as debugFactory from 'debug'; import {getAuthorizeMetadata} from './decorators/authorize'; import {AuthorizationTags} from './keys'; -import {AuthorizationContext, AuthorizationDecision, Authorizer} from './types'; +import { + AuthorizationContext, + AuthorizationDecision, + Authorizer, + AuthorizationError, + Principal, +} from './types'; +import {AuthenticationBindings, UserProfile} from '@loopback/authentication'; const debug = debugFactory('loopback:authorization:interceptor'); @@ -41,33 +48,46 @@ export class AuthorizationInterceptor implements Provider { ); if (!metadata) { debug('No authorization metadata is found %s', description); - return await next(); + const result = await next(); + return result; } debug('Authorization metadata for %s', description, metadata); - const user = await invocationCtx.get<{name: string}>('current.user', { - optional: true, - }); + + // retrieve it from authentication module + const user = await invocationCtx.get( + AuthenticationBindings.CURRENT_USER, + { + optional: true, + }, + ); + debug('Current user', user); + const authorizationCtx: AuthorizationContext = { - principals: user ? [{name: user.name, type: 'USER'}] : [], + principals: user ? [userToPrinciple(user)] : [], roles: [], scopes: [], resource: invocationCtx.targetName, invocationContext: invocationCtx, }; + debug('Security context for %s', description, authorizationCtx); let authorizers = await loadAuthorizers( invocationCtx, metadata.voters || [], ); + authorizers = authorizers.concat(this.authorizers); for (const fn of authorizers) { const decision = await fn(authorizationCtx, metadata); + // we can add another interceptor to process the error if (decision === AuthorizationDecision.DENY) { - throw new Error('Access denied'); + const error = new AuthorizationError('Access denied'); + error.statusCode = 401; + throw error; } } - return await next(); + return next(); } } @@ -88,3 +108,14 @@ async function loadAuthorizers( } return authorizerFunctions; } + +// This is a workaround before we extract a common layer +// for authentication and authorization. +function userToPrinciple(user: UserProfile): Principal { + return { + name: user.name || user.id, + id: user.id, + email: user.email, + type: 'USER', + }; +} diff --git a/packages/authorization/src/types.ts b/packages/authorization/src/types.ts index 009edc13f35b..fdb7aec1b497 100644 --- a/packages/authorization/src/types.ts +++ b/packages/authorization/src/types.ts @@ -183,14 +183,16 @@ export interface AuthorizationContext { /** * A function to decide if access to the target should be allowed or denied */ -export type Authorizer = +export type Authorizer< + T extends AuthorizationMetadata = AuthorizationMetadata +> = /** * @param context: Context information for authorization * @param metadata: Metadata representing requirements for authorization */ ( context: AuthorizationContext, - metadata: AuthorizationMetadata, + metadata: T, ) => Promise; /** @@ -233,3 +235,20 @@ export interface Enforcer { */ enforce(request: AuthorizationRequest): Promise; } + +/** + * The custom error class that describes the error thrown by + * the authorization module. + * Should be extracted to the common layer shared by authentication + * and authorization. + */ +export class AuthorizationError extends Error { + /** + * Machine readable code, can be understood by any clients + */ + code?: string; + /** + * The status code for HTTP requests + */ + statusCode?: number; +} From 756bacfebc900f39c3692e69aceb6d957a653c37 Mon Sep 17 00:00:00 2001 From: jannyHou Date: Tue, 13 Aug 2019 16:35:14 -0400 Subject: [PATCH 10/10] refactor: apply feedback --- .../unit/authorize-decorator.test.ts | 28 +++++++++---------- .../src/authorize-interceptor.ts | 4 +-- .../authorization/src/decorators/authorize.ts | 2 +- 3 files changed, 17 insertions(+), 17 deletions(-) diff --git a/packages/authorization/src/__tests__/unit/authorize-decorator.test.ts b/packages/authorization/src/__tests__/unit/authorize-decorator.test.ts index 2b4c50d9495d..72386abf3434 100644 --- a/packages/authorization/src/__tests__/unit/authorize-decorator.test.ts +++ b/packages/authorization/src/__tests__/unit/authorize-decorator.test.ts @@ -8,7 +8,7 @@ import { AUTHENTICATED, authorize, EVERYONE, - getAuthorizeMetadata, + getAuthorizationMetadata, UNAUTHENTICATED, } from '../..'; @@ -23,13 +23,13 @@ describe('Authentication', () => { update() {} } - let metaData = getAuthorizeMetadata(TestClass, 'getSecret'); + let metaData = getAuthorizationMetadata(TestClass, 'getSecret'); expect(metaData).to.eql({ allowedRoles: ['ADMIN'], scopes: ['secret.read'], }); - metaData = getAuthorizeMetadata(TestClass, 'update'); + metaData = getAuthorizationMetadata(TestClass, 'update'); expect(metaData).to.eql({ allowedRoles: ['OWNER'], scopes: ['data.update'], @@ -45,13 +45,13 @@ describe('Authentication', () => { update() {} } - let metaData = getAuthorizeMetadata(TestClass, 'getSecret'); + let metaData = getAuthorizationMetadata(TestClass, 'getSecret'); expect(metaData).to.eql({ allowedRoles: ['ADMIN'], scopes: ['secret.read'], }); - metaData = getAuthorizeMetadata(TestClass, 'update'); + metaData = getAuthorizationMetadata(TestClass, 'update'); expect(metaData).to.eql({ allowedRoles: ['OWNER'], scopes: ['data.update'], @@ -68,13 +68,13 @@ describe('Authentication', () => { update() {} } - let metaData = getAuthorizeMetadata(TestClass, 'getSecret'); + let metaData = getAuthorizationMetadata(TestClass, 'getSecret'); expect(metaData).to.eql({ allowedRoles: ['ADMIN'], scopes: ['secret.read'], }); - metaData = getAuthorizeMetadata(TestClass, 'update'); + metaData = getAuthorizationMetadata(TestClass, 'update'); expect(metaData).to.eql({ allowedRoles: ['OWNER'], scopes: ['data.update'], @@ -87,7 +87,7 @@ describe('Authentication', () => { getSecret() {} } - const metaData = getAuthorizeMetadata(TestClass, 'getSecret'); + const metaData = getAuthorizationMetadata(TestClass, 'getSecret'); expect(metaData).to.eql({ allowedRoles: [EVERYONE], }); @@ -99,7 +99,7 @@ describe('Authentication', () => { getSecret() {} } - const metaData = getAuthorizeMetadata(TestClass, 'getSecret'); + const metaData = getAuthorizationMetadata(TestClass, 'getSecret'); expect(metaData).to.eql({ allowedRoles: [EVERYONE], deniedRoles: ['xyz'], @@ -112,7 +112,7 @@ describe('Authentication', () => { getSecret() {} } - const metaData = getAuthorizeMetadata(TestClass, 'getSecret'); + const metaData = getAuthorizationMetadata(TestClass, 'getSecret'); expect(metaData).to.eql({ deniedRoles: [EVERYONE], }); @@ -124,7 +124,7 @@ describe('Authentication', () => { getSecret() {} } - const metaData = getAuthorizeMetadata(TestClass, 'getSecret'); + const metaData = getAuthorizationMetadata(TestClass, 'getSecret'); expect(metaData).to.eql({ allowedRoles: ['xyz'], deniedRoles: [EVERYONE], @@ -137,7 +137,7 @@ describe('Authentication', () => { getSecret() {} } - const metaData = getAuthorizeMetadata(TestClass, 'getSecret'); + const metaData = getAuthorizationMetadata(TestClass, 'getSecret'); expect(metaData).to.eql({ allowedRoles: [AUTHENTICATED], }); @@ -149,7 +149,7 @@ describe('Authentication', () => { getSecret() {} } - const metaData = getAuthorizeMetadata(TestClass, 'getSecret'); + const metaData = getAuthorizationMetadata(TestClass, 'getSecret'); expect(metaData).to.eql({ deniedRoles: [UNAUTHENTICATED], }); @@ -168,7 +168,7 @@ describe('Authentication', () => { getSecret() {} } - const metaData = getAuthorizeMetadata(TestClass, 'getSecret'); + const metaData = getAuthorizationMetadata(TestClass, 'getSecret'); expect(metaData).to.deepEqual({ voters: ['v1', 'v2'], allowedRoles: ['a1', 'a3', 'a2'], diff --git a/packages/authorization/src/authorize-interceptor.ts b/packages/authorization/src/authorize-interceptor.ts index 850bea3a4569..54889ca4afaa 100644 --- a/packages/authorization/src/authorize-interceptor.ts +++ b/packages/authorization/src/authorize-interceptor.ts @@ -16,7 +16,7 @@ import { Provider, } from '@loopback/context'; import * as debugFactory from 'debug'; -import {getAuthorizeMetadata} from './decorators/authorize'; +import {getAuthorizationMetadata} from './decorators/authorize'; import {AuthorizationTags} from './keys'; import { AuthorizationContext, @@ -42,7 +42,7 @@ export class AuthorizationInterceptor implements Provider { async intercept(invocationCtx: InvocationContext, next: Next) { const description = debug.enabled ? invocationCtx.description : ''; - const metadata = getAuthorizeMetadata( + const metadata = getAuthorizationMetadata( invocationCtx.target, invocationCtx.methodName, ); diff --git a/packages/authorization/src/decorators/authorize.ts b/packages/authorization/src/decorators/authorize.ts index 6ea97a7e6355..9254ce089f8c 100644 --- a/packages/authorization/src/decorators/authorize.ts +++ b/packages/authorization/src/decorators/authorize.ts @@ -197,7 +197,7 @@ export namespace authorize { * @param target Target object/class * @param methodName Target method */ -export function getAuthorizeMetadata( +export function getAuthorizationMetadata( target: object, methodName: string, ): AuthorizationMetadata | undefined {