浏览代码

HTTP request logging format 2

master
peter 5 年前
父节点
当前提交
f9008e67bd
共有 4 个文件被更改,包括 122 次插入35 次删除
  1. 62
    0
      package-lock.json
  2. 1
    0
      package.json
  3. 39
    24
      src/backend/Admin/Admin.ts
  4. 20
    11
      src/frontend/server.ts

+ 62
- 0
package-lock.json 查看文件

93
         }
93
         }
94
       }
94
       }
95
     },
95
     },
96
+    "@types/body-parser": {
97
+      "version": "1.19.0",
98
+      "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.0.tgz",
99
+      "integrity": "sha512-W98JrE0j2K78swW4ukqMleo8R7h/pFETjM2DQ90MF6XK2i4LO4W3gQ71Lt4w3bfm2EvVSyWHplECvB5sK22yFQ==",
100
+      "requires": {
101
+        "@types/connect": "*",
102
+        "@types/node": "*"
103
+      }
104
+    },
96
     "@types/color-name": {
105
     "@types/color-name": {
97
       "version": "1.1.1",
106
       "version": "1.1.1",
98
       "resolved": "https://registry.npmjs.org/@types/color-name/-/color-name-1.1.1.tgz",
107
       "resolved": "https://registry.npmjs.org/@types/color-name/-/color-name-1.1.1.tgz",
99
       "integrity": "sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ==",
108
       "integrity": "sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ==",
100
       "dev": true
109
       "dev": true
101
     },
110
     },
111
+    "@types/connect": {
112
+      "version": "3.4.33",
113
+      "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.33.tgz",
114
+      "integrity": "sha512-2+FrkXY4zllzTNfJth7jOqEHC+enpLeGslEhpnTAkg21GkRrWV4SsAtqchtT4YS9/nODBU2/ZfsBY2X4J/dX7A==",
115
+      "requires": {
116
+        "@types/node": "*"
117
+      }
118
+    },
102
     "@types/engine.io": {
119
     "@types/engine.io": {
103
       "version": "3.1.4",
120
       "version": "3.1.4",
104
       "resolved": "https://registry.npmjs.org/@types/engine.io/-/engine.io-3.1.4.tgz",
121
       "resolved": "https://registry.npmjs.org/@types/engine.io/-/engine.io-3.1.4.tgz",
107
         "@types/node": "*"
124
         "@types/node": "*"
108
       }
125
       }
109
     },
126
     },
127
+    "@types/express": {
128
+      "version": "4.17.8",
129
+      "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.8.tgz",
130
+      "integrity": "sha512-wLhcKh3PMlyA2cNAB9sjM1BntnhPMiM0JOBwPBqttjHev2428MLEB4AYVN+d8s2iyCVZac+o41Pflm/ZH5vLXQ==",
131
+      "requires": {
132
+        "@types/body-parser": "*",
133
+        "@types/express-serve-static-core": "*",
134
+        "@types/qs": "*",
135
+        "@types/serve-static": "*"
136
+      }
137
+    },
138
+    "@types/express-serve-static-core": {
139
+      "version": "4.17.13",
140
+      "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.13.tgz",
141
+      "integrity": "sha512-RgDi5a4nuzam073lRGKTUIaL3eF2+H7LJvJ8eUnCI0wA6SNjXc44DCmWNiTLs/AZ7QlsFWZiw/gTG3nSQGL0fA==",
142
+      "requires": {
143
+        "@types/node": "*",
144
+        "@types/qs": "*",
145
+        "@types/range-parser": "*"
146
+      }
147
+    },
110
     "@types/fs-extra": {
148
     "@types/fs-extra": {
111
       "version": "8.0.0",
149
       "version": "8.0.0",
112
       "resolved": "https://registry.npmjs.org/@types/fs-extra/-/fs-extra-8.0.0.tgz",
150
       "resolved": "https://registry.npmjs.org/@types/fs-extra/-/fs-extra-8.0.0.tgz",
133
         "@types/lodash": "*"
171
         "@types/lodash": "*"
134
       }
172
       }
135
     },
173
     },
174
+    "@types/mime": {
175
+      "version": "2.0.3",
176
+      "resolved": "https://registry.npmjs.org/@types/mime/-/mime-2.0.3.tgz",
177
+      "integrity": "sha512-Jus9s4CDbqwocc5pOAnh8ShfrnMcPHuJYzVcSUU7lrh8Ni5HuIqX3oilL86p3dlTrk0LzHRCgA/GQ7uNCw6l2Q=="
178
+    },
136
     "@types/mocha": {
179
     "@types/mocha": {
137
       "version": "5.2.7",
180
       "version": "5.2.7",
138
       "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-5.2.7.tgz",
181
       "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-5.2.7.tgz",
151
         "@types/node": "*"
194
         "@types/node": "*"
152
       }
195
       }
153
     },
196
     },
197
+    "@types/qs": {
198
+      "version": "6.9.5",
199
+      "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.5.tgz",
200
+      "integrity": "sha512-/JHkVHtx/REVG0VVToGRGH2+23hsYLHdyG+GrvoUGlGAd0ErauXDyvHtRI/7H7mzLm+tBCKA7pfcpkQ1lf58iQ=="
201
+    },
202
+    "@types/range-parser": {
203
+      "version": "1.2.3",
204
+      "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.3.tgz",
205
+      "integrity": "sha512-ewFXqrQHlFsgc09MK5jP5iR7vumV/BYayNC6PgJO2LPe8vrnNFyjQjSppfEngITi0qvfKtzFvgKymGheFM9UOA=="
206
+    },
207
+    "@types/serve-static": {
208
+      "version": "1.13.5",
209
+      "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.13.5.tgz",
210
+      "integrity": "sha512-6M64P58N+OXjU432WoLLBQxbA0LRGBCRm7aAGQJ+SMC1IMl0dgRVi9EFfoDcS2a7Xogygk/eGN94CfwU9UF7UQ==",
211
+      "requires": {
212
+        "@types/express-serve-static-core": "*",
213
+        "@types/mime": "*"
214
+      }
215
+    },
154
     "@types/socket.io": {
216
     "@types/socket.io": {
155
       "version": "2.1.10",
217
       "version": "2.1.10",
156
       "resolved": "https://registry.npmjs.org/@types/socket.io/-/socket.io-2.1.10.tgz",
218
       "resolved": "https://registry.npmjs.org/@types/socket.io/-/socket.io-2.1.10.tgz",

+ 1
- 0
package.json 查看文件

25
   "author": "frontblock.me",
25
   "author": "frontblock.me",
26
   "license": "ISC",
26
   "license": "ISC",
27
   "dependencies": {
27
   "dependencies": {
28
+    "@types/express": "^4.17.8",
28
     "@types/mocha": "^5.2.7",
29
     "@types/mocha": "^5.2.7",
29
     "@types/node": "^14.0.27",
30
     "@types/node": "^14.0.27",
30
     "bsert": "0.0.10",
31
     "bsert": "0.0.10",

+ 39
- 24
src/backend/Admin/Admin.ts 查看文件

15
 import { UserManager } from '../Components/User/UserManager';
15
 import { UserManager } from '../Components/User/UserManager';
16
 import { RootComponent } from '../Injector/ServiceDecorator';
16
 import { RootComponent } from '../Injector/ServiceDecorator';
17
 import { TableDefinitionExporter } from '../Types/Interfaces';
17
 import { TableDefinitionExporter } from '../Types/Interfaces';
18
-import { AdminConf, TableDefiniton } from '../Types/Types';
18
+import { AdminConf, TableDefiniton, SomeOf } from '../Types/Types';
19
 import { RPCConfigLoader } from '../Components/RPCConfigLoader';
19
 import { RPCConfigLoader } from '../Components/RPCConfigLoader';
20
 import { FrontworkComponent } from '../Types/FrontworkComponent';
20
 import { FrontworkComponent } from '../Types/FrontworkComponent';
21
 import { IAdmin } from './Interface';
21
 import { IAdmin } from './Interface';
22
 import { Injector } from '../Injector/Injector';
22
 import { Injector } from '../Injector/Injector';
23
 import { PubSub } from '../Components/PubSub/PubSub';
23
 import { PubSub } from '../Components/PubSub/PubSub';
24
+import { BurstyRateLimiter, RateLimiterMemory, RateLimiterAbstract } from 'rate-limiter-flexible'
25
+
24
 
26
 
25
 @RootComponent({
27
 @RootComponent({
26
     injectable: IAdmin,
28
     injectable: IAdmin,
67
 
69
 
68
     async start() {
70
     async start() {
69
         let port: number = this.config.getConfig().httpPort
71
         let port: number = this.config.getConfig().httpPort
72
+        const rateLimiter = new BurstyRateLimiter(
73
+            new RateLimiterMemory({
74
+              points: 2,
75
+              duration: 1,
76
+            }),
77
+            new RateLimiterMemory({
78
+              keyPrefix: 'burst',
79
+              points: 60,
80
+              duration: 60,
81
+            })
82
+          )
70
 
83
 
71
         await this.makeKnex()
84
         await this.makeKnex()
72
-        const app = await this.makeExpress()
85
+        const app = await this.makeExpress(rateLimiter)
73
         const httpServer = new http.Server(app)
86
         const httpServer = new http.Server(app)
74
         await this.startWebsocket(httpServer)
87
         await this.startWebsocket(httpServer)
75
         httpServer.listen(port)
88
         httpServer.listen(port)
76
-        await this.attachAngularSSR(app)
89
+        await this.attachAngularSSR(app, rateLimiter)
77
         getLogger('Admin#startWebsocket').debug("Webserver up on", port)
90
         getLogger('Admin#startWebsocket').debug("Webserver up on", port)
78
 
91
 
79
         await Promise.all(this.frontworkComponents.map(c => c.initialize ? c.initialize() : undefined))
92
         await Promise.all(this.frontworkComponents.map(c => c.initialize ? c.initialize() : undefined))
125
             }
138
             }
126
         ], {
139
         ], {
127
             errorHandler: (sock, err, rpc, args) => {
140
             errorHandler: (sock, err, rpc, args) => {
128
-                console.log("RPC", rpc)
129
-                console.log("ERR", err)
130
-                console.log("ARGS", args)
141
+                getLogger("startWebsocket#errorHandler").error("RPC", rpc)
142
+                getLogger("startWebsocket#errorHandler").error("ERR", err)
143
+                getLogger("startWebsocket#errorHandler").error("ARGS", args)
131
             }
144
             }
132
         })
145
         })
133
         .attach(httpServer)
146
         .attach(httpServer)
134
     }
147
     }
135
 
148
 
136
-    private async makeExpress() {
149
+    private async makeExpress(rateLimiter : SomeOf<RateLimiterAbstract> = new RateLimiterMemory({ points: 6, duration: 3 })) {
137
         if (this.httpServer != null || this.express != null) {
150
         if (this.httpServer != null || this.express != null) {
138
             getLogger('Admin#startWebserver').warn("Webserver is already running")
151
             getLogger('Admin#startWebserver').warn("Webserver is already running")
139
             return
152
             return
140
         }
153
         }
141
 
154
 
142
         this.express = express()
155
         this.express = express()
143
-
144
         const distFolder = "../../../../dist"
156
         const distFolder = "../../../../dist"
145
-
146
         this.express.get('*.*', (req, res) => {
157
         this.express.get('*.*', (req, res) => {
147
-            //console.log('*.*', req.path);
148
-            try{
149
-                const filepath = Path.join(__dirname, distFolder, 'browser', decodeURIComponent(req.path))
150
-                if(!existsSync(filepath)){
151
-                    throw new Error("FAILED REQUEST "+filepath+ " FROM "+req.ip)
152
-                }
153
-                res.sendFile(filepath)
154
-                res.status(200)
155
-            }catch(e){
156
-                getLogger('Admin#startWebserver#serveFile').error(String(e))
157
-                res.send("404 NOT FOUND")
158
-                res.status(404)
159
-            }
158
+            rateLimiter.consume(req.ip)
159
+            .then(_ => {
160
+                    const filepath = Path.join(__dirname, distFolder, 'browser', decodeURIComponent(req.path))
161
+                    if(!existsSync(filepath)){
162
+                        getLogger('Admin#startWebserver#serveFile').error(String(new Error("404 BAD REQUEST "+filepath+ " FROM "+req.ip)))
163
+                        res.send("404 Not found")
164
+                        res.status(404)
165
+                        return
166
+                    }
167
+                    res.sendFile(filepath)
168
+                    res.status(200)
169
+            })
170
+            .catch(_ => {
171
+                getLogger('Admin#startWebserver#serveFile').error(String(new Error("429 BAD REQUEST "+req.path+" FROM "+req.ip)))
172
+                res.send('429 Too many requests')
173
+                res.status(429)
174
+            })
160
         })
175
         })
161
 
176
 
162
         return this.express
177
         return this.express
163
     }
178
     }
164
 
179
 
165
-    attachAngularSSR = async (express : express.Application) => {
180
+    attachAngularSSR = async (express : express.Application, rateLimiter : SomeOf<RateLimiterAbstract> = new RateLimiterMemory({ points: 6, duration: 3 })) => {
166
         const distFolder = "../../../../dist"
181
         const distFolder = "../../../../dist"
167
         const ngExpressServer = Path.join(__dirname, distFolder, 'server.js')
182
         const ngExpressServer = Path.join(__dirname, distFolder, 'server.js')
168
         let port: number = this.config.getConfig().httpPort
183
         let port: number = this.config.getConfig().httpPort
169
 
184
 
170
         try {
185
         try {
171
             const req = require(distFolder + "/server.js")
186
             const req = require(distFolder + "/server.js")
172
-            await req.attachExpress(express, './dist', getLogger('angularSSR#'))
187
+            await req.attachExpress(express, './dist', getLogger('angularSSR#'), rateLimiter)
173
             getLogger('Admin#startWebserver').debug('Frontend from ' + ngExpressServer + " loaded")
188
             getLogger('Admin#startWebserver').debug('Frontend from ' + ngExpressServer + " loaded")
174
         } catch (e) {
189
         } catch (e) {
175
             getLogger('Admin#startWebserver').error(e)
190
             getLogger('Admin#startWebserver').error(e)

+ 20
- 11
src/frontend/server.ts 查看文件

15
 global['XMLHttpRequest'] = require('xmlhttprequest').XMLHttpRequest;
15
 global['XMLHttpRequest'] = require('xmlhttprequest').XMLHttpRequest;
16
 global['fetch'] = fetch.default;
16
 global['fetch'] = fetch.default;
17
 
17
 
18
-
19
-
20
-export async function attachExpress(app, staticDir = "./dist", logger = console) {
18
+/**
19
+ * Function to attach this SSR application to an express server. Exported as function due to webpack inconsistencies.
20
+ * 
21
+ * @param app express.Application to run on
22
+ * @param staticDir Where the static website content is (i.e. ./dist)
23
+ * @param logger A loggerservice or console
24
+ * @param rateLimiter a rate-limiter-flexible instance
25
+ */
26
+export async function attachExpress(app, staticDir, logger, rateLimiter) {
21
   const STATIC_FOLDER = resolve(process.cwd(), staticDir);
27
   const STATIC_FOLDER = resolve(process.cwd(), staticDir);
22
   enableProdMode();
28
   enableProdMode();
23
 
29
 
24
   const loggerService = {
30
   const loggerService = {
25
-    warn: (...args) => logger.error(...args),
26
-    error: (...args) => logger.warn(...args),
31
+    warn: (...args) => logger.warn(...args),
32
+    error: (...args) => logger.error(...args),
27
     log: (...args) => logger.info(...args),
33
     log: (...args) => logger.info(...args),
28
     table: (...args) => logger.info(...args),
34
     table: (...args) => logger.info(...args),
29
     collapsed: (msg, type, ...args) => loggerService[type](msg, ...args)
35
     collapsed: (msg, type, ...args) => loggerService[type](msg, ...args)
57
   );
63
   );
58
 
64
 
59
   app.get('*', (req, res) => {
65
   app.get('*', (req, res) => {
60
-    loggerService.log("REQUEST "+req.path +" FROM "+ req.ip)
61
-    try{
66
+    rateLimiter.consume(req.ip, 3)
67
+    .then(_ => {
62
       res.render(resolve(STATIC_FOLDER, 'browser/index'), { req, res })
68
       res.render(resolve(STATIC_FOLDER, 'browser/index'), { req, res })
63
-    }catch(e){
64
-      loggerService.error(e)
65
-    }
66
-  });
69
+    })
70
+    .catch(_ => {
71
+      loggerService.error(String(new Error("429 BAD REQUEST "+req.path+" FROM "+req.ip)))
72
+      res.send("429 Too many requests")
73
+      res.status(429)
74
+    })
75
+  })
67
 }
76
 }

正在加载...
取消
保存