From f8d475cb53d64c153fadde74bd40ad137e9bcf97 Mon Sep 17 00:00:00 2001 From: peter Date: Thu, 5 Mar 2020 18:14:40 +0100 Subject: [PATCH] sesamefilter --- src/Backend.ts | 17 ++++++++++++----- src/Frontend.ts | 6 +++--- src/Types.ts | 5 +++-- test/Test.ts | 29 +++++++++++++++++++++++++---- 4 files changed, 43 insertions(+), 14 deletions(-) diff --git a/src/Backend.ts b/src/Backend.ts index 9d18900..b707258 100644 --- a/src/Backend.ts +++ b/src/Backend.ts @@ -25,6 +25,7 @@ export class RPCServer< private errorHandler: T.ErrorHandler private connectionHandler: T.ConnectionHandler private sesame? : T.SesameFunction + private accessFilter: T.AccessFilter /** * @throws On RPC with no name @@ -35,10 +36,12 @@ export class RPCServer< constructor( private port:number, private exporters: Exporters = [], - conf: T.ServerConf = {} + conf: T.ServerConf = {} ){ if(!conf.visibility) this.visibility = "127.0.0.1" + this.accessFilter = conf.accessFilter || (async () => true) + if(conf.sesame){ this.sesame = U.makeSesameFunction(conf.sesame) } @@ -87,10 +90,14 @@ export class RPCServer< } protected initRPCs(socket:I.Socket){ - socket.hook('info', () => rpcInfos) - const rpcInfos:T.ExtendedRpcInfo[] = [ - ...this.exporters.flatMap(exporter => U.rpcHooker(socket, exporter, this.errorHandler, this.sesame)) - ] + socket.hook('info', async (sesame? : string) => { + const rpcs = await Promise.all(this.exporters.map(async exp => { + const allowed = await this.accessFilter(sesame, exp) + if(!allowed) return [] + return U.rpcHooker(socket, exp, this.errorHandler, this.sesame) + })) + return rpcs.flat() + }) } /** diff --git a/src/Frontend.ts b/src/Frontend.ts index 2401e2a..30f8dc8 100644 --- a/src/Frontend.ts +++ b/src/Frontend.ts @@ -136,7 +136,7 @@ export class RPCSocket implements I.Socket{ this.socket.hook(kv[0], kv[1]) }) - const info:T.ExtendedRpcInfo[] = await this.info() + const info:T.ExtendedRpcInfo[] = await this.info(sesame) info.forEach(i => { let f: any @@ -159,9 +159,9 @@ export class RPCSocket implements I.Socket{ /** * Get a list of available RPCs from the server */ - public async info(){ + public async info(sesame?:string){ if(!this.socket) throw new Error("The socket is not connected! Use socket.connect() first") - return await this.socket.call('info') + return await this.socket.call('info', sesame) } /** diff --git a/src/Types.ts b/src/Types.ts index 3296e6e..f57213a 100644 --- a/src/Types.ts +++ b/src/Types.ts @@ -2,7 +2,7 @@ import * as I from "./Interfaces"; export type AnyFunction = (...args:any) => any export type HookFunction = (...args: Parameters) => Promise | ErrorResponse> - +export type AccessFilter = (sesame:string|undefined, exporter: I.RPCExporter, keyof InterfaceT, SubresT>) => Promise export type Visibility = "127.0.0.1" | "0.0.0.0" export type ConnectionHandler = (socket:I.Socket) => void export type ErrorHandler = (socket:I.Socket, error:any, rpcName: string, args: any[]) => void @@ -17,7 +17,8 @@ export type FrontEndHandlerType = { 'close' : () => void } -export type ServerConf = { +export type ServerConf = { + accessFilter?: AccessFilter connectionHandler?: ConnectionHandler errorHandler?: ErrorHandler closeHandler?: CloseHandler diff --git a/test/Test.ts b/test/Test.ts index 8b2ce54..c51984c 100644 --- a/test/Test.ts +++ b/test/Test.ts @@ -542,8 +542,9 @@ type myExporterIfc = { describe("Class binding", ()=>{ let exporter1 : MyExporter - let serv : RPCServer + let serv : RPCServer<{}, myExporterIfc> let sock: RPCSocket & myExporterIfc + let allowed = true class MyExporter implements RPCExporter{ name = "MyExporter" as "MyExporter"; @@ -563,20 +564,34 @@ describe("Class binding", ()=>{ this.myRPC ] - myRPC = async () => "Hello Borld" + myRPC = async () => { + return "Hello Borld" + } } before(done => { exporter1 = new MyExporter() - serv = new RPCServer(21004, [exporter1]) + serv = new RPCServer<{}, myExporterIfc>(21004, [exporter1], { + accessFilter: async (sesame,exporter) => { + switch(exporter.name){ + case "MyExporter": + if(!allowed) return false + allowed = false + return sesame==='xxx'; + default: + return false + } + }, + sesame: "xxx" + }) done() }) beforeEach((done)=>{ const s = new RPCSocket(21004, 'localhost') - s.connect().then(conn => { + s.connect("xxx").then(conn => { sock = conn done() }) @@ -596,6 +611,7 @@ describe("Class binding", ()=>{ done(new Error(res)) }).catch(e => { //job will time out because of setExporters + allowed = true done() }) }) @@ -608,6 +624,11 @@ describe("Class binding", ()=>{ done(new Error(res)) }) }) + + it("use sesameFilter", (done) => { + if(!sock['MyExporter']) done() + else done(new Error("RPC supposed to be gone")) + }) })