UNPKG

rpcchannel

Version:

Easy RPC with permission controls

266 lines (255 loc) 7.61 kB
import { expect } from 'chai' import { AllowAccessController, DenyAccessController, FunctionAccessController, MultistringAddress, AccessPolicy, ChainedAccessController, LegacyAccessController, FunctionLookupAccessController, RpcChannel, AutoFunctionAccessController, RequiresPermissions, CanCallFunction, OptAccessPolicy, RequirePermissions, SetCanCallFunc } from '../src/index' describe('[accesscontrol.ts] RequirePermissions', () => { it('sets RequiresPermissions on member function', () => { class Test { @RequirePermissions(['hello', 'world']) member(): number { return 1 } } expect((new Test().member as any)[RequiresPermissions]).to.be.deep.equal( ['hello', 'world'] ) }) it('throws error when applied to non-function', () => { expect(() => { const myobj = {} RequirePermissions([])( myobj, 'test', { configurable: true, enumerable: false, value: 'hi', writable: true, get(): string { return 'hi' }, set(v: any): void { throw new Error('Should not happen') } } ) }).to.throw('Cannot require permissions for non-function') }) }) describe('[accesscontrol.ts] SetCanCallFunc', () => { it('sets CanCallFunction on member function', () => { const func = () => AccessPolicy.ALLOW class Test { @SetCanCallFunc(func) member(): number { return 1 } } expect((new Test().member as any)[CanCallFunction]).to.be.equal(func) }) it('throws error when applied to non-function', () => { expect(() => { const myobj = {} SetCanCallFunc(() => undefined)( myobj, 'test', { configurable: true, enumerable: false, value: 'hi', writable: true, get(): string { return 'hi' }, set(v: any): void { throw new Error('Should not happen') } } ) }).to.throw('Cannot set access controller func on non-function') }) }) const default_opts = { args: [{}, Symbol(), 'hi'], wc: [], channel: new RpcChannel(() => undefined), func: () => undefined } describe('[accesscontrol.ts] AllowAccessController', () => { it('always returns true', () => { expect(new AllowAccessController().can()).to.be.true }) }) describe('[accesscontrol.ts] DenyAccessController', () => { it('always returns false', () => { expect(new DenyAccessController().can()).to.be.false }) }) describe('[accesscontrol.ts] DenyAccessController', () => { it('always calls function', () => { const addr = ['net', 'kb1rd', 'test'] expect(new FunctionAccessController( (a: MultistringAddress, opts) => { expect(a).to.be.equal(addr) expect(opts).to.be.equal(default_opts) return true } ).can(addr, default_opts)).to.be.true }) }) describe('[accesscontrol.ts] ChainedAccessController', () => { it('default works', () => { expect( new ChainedAccessController(AccessPolicy.ALLOW).can([], default_opts) ).to.be.equal(AccessPolicy.ALLOW) }) it('calls in order with same data, stopping when value provided', () => { const addr = ['net', 'kb1rd', 'test'] const data = [{}, Symbol(), 'hi'] const ac = new ChainedAccessController(AccessPolicy.ALLOW) const calls: number[] = [] ac.access_chain.push(new FunctionAccessController((a, o) => { expect(a).to.be.equal(addr) expect(o).to.be.equal(default_opts) calls.push(1) return undefined })) ac.access_chain.push(new FunctionAccessController(() => { calls.push(2) return AccessPolicy.DENY })) ac.access_chain.push(new FunctionAccessController(() => { calls.push(3) return undefined })) expect(ac.can(addr, default_opts)).to.be.equal(AccessPolicy.DENY) expect(calls).to.be.deep.equal([1, 2]) }) }) describe('[accesscontrol.ts] LegacyAccessController', () => { it('matches (assumes AddressMap works)', () => { const ac = new LegacyAccessController() ac.map.put(['net', 'kb1rd', undefined], AccessPolicy.ALLOW) expect(ac.can(['net', 'kb1rd', 'test'])).to.be.equal(AccessPolicy.ALLOW) }) }) describe('[accesscontrol.ts] FunctionLookupAccessController', () => { it('returns `OptAccessPolicy.NONE` if function undefined', () => { const ac = new FunctionLookupAccessController() ac.map.put(['net', 'kb1rd', undefined], () => AccessPolicy.ALLOW) expect(ac.can(['com', 'kb1rd', 'test'], default_opts)) .to.be.equal(OptAccessPolicy.NONE) }) it('lookup works', () => { const addr = ['net', 'kb1rd', 'test'] const data = [{}, Symbol(), 'hi'] const ac = new FunctionLookupAccessController() ac.map.put(['net', 'kb1rd', undefined], (a, o) => { expect(a).to.be.equal(addr) expect(o).to.be.equal(default_opts) return AccessPolicy.ALLOW }) expect(ac.can(addr, default_opts)).to.be.equal(AccessPolicy.ALLOW) }) }) describe('[accesscontrol.ts] AutoFunctionAccessController', () => { it('defaults to none', () => { const ac = new AutoFunctionAccessController() expect(ac.can(['com', 'kb1rd', 'test'], default_opts)) .to.be.equal(OptAccessPolicy.NONE) }) it('denies if missing even one permission before calling func', () => { const ac = new AutoFunctionAccessController() ac.perms.add('net.kb1rd.teststuff') const opts = Object.assign( {}, default_opts, { func: Object.assign( () => undefined, { [RequiresPermissions]: [ 'net.kb1rd.teststuff', 'net.kb1rd.security' ], [CanCallFunction]: () => { throw new TypeError('This should never happen') } } ) } ) expect(ac.can(['com', 'kb1rd', 'test'], opts)) .to.be.equal(AccessPolicy.DENY) }) it('requesting perms in function has same effect', () => { const ac = new AutoFunctionAccessController() ac.perms.add('net.kb1rd.teststuff') const opts = Object.assign( {}, default_opts, { func: Object.assign( () => undefined, { [CanCallFunction]: ( to: MultistringAddress, { require }: { require: (s: string) => void } ) => { require('net.kb1rd.teststuff') require('net.kb1rd.security') } } ) } ) expect(ac.can(['com', 'kb1rd', 'test'], opts)) .to.be.equal(AccessPolicy.DENY) }) it('returns function value', () => { const ac = new AutoFunctionAccessController() ac.perms.add('net.kb1rd.teststuff') const opts = Object.assign( {}, default_opts, { func: Object.assign( () => undefined, { [CanCallFunction]: () => AccessPolicy.ALLOW } ) } ) expect(ac.can(['com', 'kb1rd', 'test'], opts)) .to.be.equal(AccessPolicy.ALLOW) }) it('defaults to `OptAccessPolicy.NONE` when function returns', () => { const ac = new AutoFunctionAccessController() ac.perms.add('net.kb1rd.teststuff') const opts = Object.assign( {}, default_opts, { func: Object.assign( () => undefined, { [CanCallFunction]: () => undefined } ) } ) expect(ac.can(['com', 'kb1rd', 'test'], opts)) .to.be.equal(OptAccessPolicy.NONE) }) })