Browse Source

sesame function

master
peter 4 years ago
parent
commit
217df18585
6 changed files with 78 additions and 17 deletions
  1. 1
    1
      package.json
  2. 11
    6
      src/Backend.ts
  3. 1
    1
      src/Frontend.ts
  4. 4
    2
      src/Types.ts
  5. 18
    7
      src/Utils.ts
  6. 43
    0
      test/Test.ts

+ 1
- 1
package.json View File

1
 {
1
 {
2
   "name": "rpclibrary",
2
   "name": "rpclibrary",
3
-  "version": "1.4.7",
3
+  "version": "1.5.0",
4
   "description": "rpclibrary is a websocket on steroids!",
4
   "description": "rpclibrary is a websocket on steroids!",
5
   "main": "./js/Index.js",
5
   "main": "./js/Index.js",
6
   "repository": {
6
   "repository": {

+ 11
- 6
src/Backend.ts View File

20
     private closeHandler:T.CloseHandler
20
     private closeHandler:T.CloseHandler
21
     private errorHandler: T.ErrorHandler
21
     private errorHandler: T.ErrorHandler
22
     private connectionHandler: T.ConnectionHandler
22
     private connectionHandler: T.ConnectionHandler
23
+    private sesame? : T.SesameFunction
23
 
24
 
24
     /**
25
     /**
25
      * @throws On RPC with no name
26
      * @throws On RPC with no name
30
     constructor(
31
     constructor(
31
         private port:number,
32
         private port:number,
32
         private exporters: I.RPCExporter<T.RPCInterface<InterfaceT>, keyof InterfaceT, SubResType>[] = [],
33
         private exporters: I.RPCExporter<T.RPCInterface<InterfaceT>, keyof InterfaceT, SubResType>[] = [],
33
-        private conf: T.ServerConf =  {}
34
+        conf: T.ServerConf =  {}
34
     ){
35
     ){
35
         
36
         
36
         if(!conf.visibility) this.visibility = "127.0.0.1"        
37
         if(!conf.visibility) this.visibility = "127.0.0.1"        
37
         
38
         
39
+        if(conf.sesame){
40
+            console.log("Setting Sesame")
41
+            this.sesame = U.makeSesameFunction(conf.sesame)
42
+        }
43
+
38
         this.errorHandler = (socket:I.Socket) => (error:any) => { 
44
         this.errorHandler = (socket:I.Socket) => (error:any) => { 
39
             if(conf.errorHandler) conf.errorHandler(socket, error)
45
             if(conf.errorHandler) conf.errorHandler(socket, error)
40
             socket.destroy(); 
46
             socket.destroy(); 
42
         }
48
         }
43
         
49
         
44
         this.closeHandler = (socket:I.Socket) => { 
50
         this.closeHandler = (socket:I.Socket) => { 
45
-            if(!conf.closeHandler) console.log("Socket on port "+socket.port+" closing") 
51
+            if(!conf.closeHandler) console.log("Connection on port "+socket.port+" closing") 
46
             else conf.closeHandler(socket)
52
             else conf.closeHandler(socket)
47
         }
53
         }
48
         
54
         
49
         this.connectionHandler = (socket:I.Socket) => { 
55
         this.connectionHandler = (socket:I.Socket) => { 
50
-            if(!conf.connectionHandler) console.log("New websocket connection on port "+socket.port)
56
+            if(!conf.connectionHandler) console.log("New connection on port "+socket.port)
51
             else conf.connectionHandler(socket)
57
             else conf.connectionHandler(socket)
52
         }
58
         }
53
 
59
 
74
             })
80
             })
75
             this.ws.listen(this.port, this.visibility)
81
             this.ws.listen(this.port, this.visibility)
76
         }catch(e){
82
         }catch(e){
77
-            //@ts-ignore
78
-            this.errorHandler(undefined)("Unable to connect to socket")
83
+            this.errorHandler(this.io, e)
79
         }
84
         }
80
     }
85
     }
81
 
86
 
82
     protected initRPCs(socket:I.Socket){
87
     protected initRPCs(socket:I.Socket){
83
         socket.hook('info', () => rpcInfos)
88
         socket.hook('info', () => rpcInfos)
84
         const rpcInfos:T.ExtendedRpcInfo[] = [
89
         const rpcInfos:T.ExtendedRpcInfo[] = [
85
-            ...this.exporters.flatMap(exporter => U.rpcHooker(socket, exporter, this.conf.sesame))
90
+            ...this.exporters.flatMap(exporter => U.rpcHooker(socket, exporter, this.sesame))
86
         ]
91
         ]
87
     }
92
     }
88
 
93
 

+ 1
- 1
src/Frontend.ts View File

134
         const argParams = fnArgs.map(stripAfterEquals).join(",")
134
         const argParams = fnArgs.map(stripAfterEquals).join(",")
135
         if(!sesame)
135
         if(!sesame)
136
             return eval( '( () => async ('+headerArgs+') => { return await this.socket.call("'+fnName+'", '+argParams+')} )()' )
136
             return eval( '( () => async ('+headerArgs+') => { return await this.socket.call("'+fnName+'", '+argParams+')} )()' )
137
-        else   
137
+        else 
138
             return eval( '( () => async ('+headerArgs+') => { return await this.socket.call("'+fnName+'", "'+sesame+'", '+argParams+')} )()' )
138
             return eval( '( () => async ('+headerArgs+') => { return await this.socket.call("'+fnName+'", "'+sesame+'", '+argParams+')} )()' )
139
     }
139
     }
140
 
140
 

+ 4
- 2
src/Types.ts View File

7
 export type ConnectionHandler = (socket:I.Socket) => void
7
 export type ConnectionHandler = (socket:I.Socket) => void
8
 export type ErrorHandler = (socket:I.Socket, error:any) => void
8
 export type ErrorHandler = (socket:I.Socket, error:any) => void
9
 export type CloseHandler = (socket:I.Socket) =>  void
9
 export type CloseHandler = (socket:I.Socket) =>  void
10
+export type SesameFunction = (sesame : string) => boolean
11
+
10
 export type SesameConf = {
12
 export type SesameConf = {
11
-    sesame?: string
13
+    sesame?: string | SesameFunction
12
 }
14
 }
13
 export type ServerConf = {
15
 export type ServerConf = {
14
     connectionHandler?: ConnectionHandler
16
     connectionHandler?: ConnectionHandler
65
 
67
 
66
 export type HookInfo<SubresT = {}> = BaseInfo & { 
68
 export type HookInfo<SubresT = {}> = BaseInfo & { 
67
     type: 'Hook', 
69
     type: 'Hook', 
68
-    generator: (socket?:I.Socket) => (...args:any) => SubresT
70
+    generator: (socket?:I.Socket) => (...args:any[]) => SubresT
69
 }
71
 }
70
 
72
 
71
 export type CallInfo = BaseInfo & {
73
 export type CallInfo = BaseInfo & {

+ 18
- 7
src/Utils.ts View File

10
  * @param owner The owning RPC group's name
10
  * @param owner The owning RPC group's name
11
  * @throws Error on RPC without name property
11
  * @throws Error on RPC without name property
12
  */
12
  */
13
-export const rpcToRpcinfo = <SubResT = {}>(rpc : T.RPC<any, any, SubResT>, owner: string, sesame?:string):T.RpcInfo => {
13
+export const rpcToRpcinfo = <SubResT = {}>(rpc : T.RPC<any, any, SubResT>, owner: string, sesame?:T.SesameFunction):T.RpcInfo => {
14
+    
14
     switch (typeof rpc){
15
     switch (typeof rpc){
15
         case  "object":
16
         case  "object":
16
             if(rpc['call']){
17
             if(rpc['call']){
19
                     argNames: extractArgs(rpc['call']),
20
                     argNames: extractArgs(rpc['call']),
20
                     type: "Call",
21
                     type: "Call",
21
                     name: rpc.name,
22
                     name: rpc.name,
22
-                    call: sesame?async (_sesame, ...args) => {if(sesame === _sesame) return await rpc['call'].apply({}, args)}:rpc['call'],
23
+                    call: sesame?async (_sesame, ...args) => {if(sesame(_sesame)) return await rpc['call'].apply({}, args)}:rpc['call'], // check & remove sesame 
23
                 }
24
                 }
24
             }else{
25
             }else{
25
                 const generator = hookGenerator(<T.HookRPC<any, any, any>>rpc, sesame)
26
                 const generator = hookGenerator(<T.HookRPC<any, any, any>>rpc, sesame)
44
                 argNames: extractArgs(rpc),
45
                 argNames: extractArgs(rpc),
45
                 type: "Call",
46
                 type: "Call",
46
                 name: rpc.name,
47
                 name: rpc.name,
47
-                call: async(...args) => (<Function>rpc).apply({}, args),
48
+                call: sesame?async (_sesame, ...args) => {if(sesame(_sesame)) return await rpc.apply({}, args)}:rpc, // check & remove sesame 
48
             }
49
             }
49
     }
50
     }
50
     throw new Error("Bad socketIORPC type "+ typeof rpc)
51
     throw new Error("Bad socketIORPC type "+ typeof rpc)
56
  * @param exporter The exporter
57
  * @param exporter The exporter
57
  * @param makeUnique @default true Attach a suffix to RPC names
58
  * @param makeUnique @default true Attach a suffix to RPC names
58
  */
59
  */
59
-export function rpcHooker<SubResT = {}>(socket: I.Socket, exporter:I.RPCExporter<any, any, SubResT>, sesame?:string, makeUnique = true):T.ExtendedRpcInfo[]{
60
+export function rpcHooker<SubResT = {}>(socket: I.Socket, exporter:I.RPCExporter<any, any, SubResT>, sesame?:T.SesameFunction, makeUnique = true):T.ExtendedRpcInfo[]{
60
     const owner = exporter.name
61
     const owner = exporter.name
61
     const RPCs = [...exporter.exportRPCs()]
62
     const RPCs = [...exporter.exportRPCs()]
62
 
63
 
85
  * @param rpc The RPC to transform
86
  * @param rpc The RPC to transform
86
  * @returns A {@link HookFunction}
87
  * @returns A {@link HookFunction}
87
  */
88
  */
88
-const hookGenerator = (rpc:T.HookRPC<any, any, any>, sesame?:string): T.HookInfo['generator'] => { 
89
+const hookGenerator = (rpc:T.HookRPC<any, any, any>, sesame?:T.SesameFunction): T.HookInfo['generator'] => { 
89
     const argsArr = extractArgs(rpc.hook)
90
     const argsArr = extractArgs(rpc.hook)
90
     if(sesame){
91
     if(sesame){
91
         const _sesame = argsArr.shift()
92
         const _sesame = argsArr.shift()
92
-        if(sesame !== _sesame){
93
+        if(!sesame(_sesame!)){
93
             throw new Error('Bad sesame')
94
             throw new Error('Bad sesame')
94
         }
95
         }
95
     }
96
     }
96
-    argsArr.pop()
97
+    argsArr.pop() //remove 'callback' from the end
97
     const args = argsArr.join(',')
98
     const args = argsArr.join(',')
98
 
99
 
99
     return eval(`(socket) => async (`+args+`) => { 
100
     return eval(`(socket) => async (`+args+`) => { 
131
         uuid: uuidv4(),
132
         uuid: uuidv4(),
132
         ...extension
133
         ...extension
133
     }
134
     }
135
+}
136
+
137
+export function makeSesameFunction (sesame : T.SesameFunction | string) : T.SesameFunction {
138
+    if(typeof sesame === 'function'){
139
+        return sesame
140
+    }
141
+
142
+    return (testSesame : string) => {
143
+        return testSesame === sesame 
144
+    }
134
 }
145
 }

+ 43
- 0
test/Test.ts View File

223
                 done(new Error("Results did not match: "+[r1,r2,r3,r4]))
223
                 done(new Error("Results did not match: "+[r1,r2,r3,r4]))
224
         })
224
         })
225
     })
225
     })
226
+})
227
+
228
+type SesameTestIfc = { test: { checkCandy: ()=>Promise<string>} }
229
+
230
+describe('Sesame should unlock the socket', () => {
231
+    let candy = "OK"
232
+    let client: RPCSocket & SesameTestIfc
233
+    let server: RPCServer<{topic: string}, SesameTestIfc> 
234
+
235
+    before(async() => {
236
+        server = new RPCServer<{ topic: string }, SesameTestIfc>(20004, [{
237
+            name: "test",
238
+            exportRPCs: () => [
239
+                async function checkCandy():Promise<string> { return candy },
240
+            ]}
241
+        ],{
242
+            sesame: (_sesame) => _sesame === 'sesame!' 
243
+        })
244
+        const sock = new RPCSocket(20004, "localhost")
245
+        client = await sock.connect<SesameTestIfc>('sesame!')
246
+    })
247
+
248
+    after(() => {
249
+        client.destroy()
250
+        server.destroy()
251
+    })
252
+
253
+    it('should not work without sesame', (done) => {
254
+        const sock = new RPCSocket(20004, "localhost")
255
+        sock.connect<SesameTestIfc>( /* no sesame */).then(async (c) => {
256
+            c.test.checkCandy().then(d => {
257
+                if(d === candy)
258
+                    done("should not be able to get candy")
259
+                done()
260
+            }).finally(() => {
261
+                sock.destroy()
262
+            })
263
+        })
264
+    })
265
+
266
+    it('should work with sesame', (done) => {
267
+        client.test.checkCandy().then(c => done())
268
+    })
226
 })
269
 })

Loading…
Cancel
Save