|
|
@@ -15,12 +15,14 @@ import { CharacterManager } from '../Components/Character/CharacterManager';
|
|
15
|
15
|
import { UserManager } from '../Components/User/UserManager';
|
|
16
|
16
|
import { RootComponent } from '../Injector/ServiceDecorator';
|
|
17
|
17
|
import { TableDefinitionExporter } from '../Types/Interfaces';
|
|
18
|
|
-import { AdminConf, TableDefiniton } from '../Types/Types';
|
|
|
18
|
+import { AdminConf, TableDefiniton, SomeOf } from '../Types/Types';
|
|
19
|
19
|
import { RPCConfigLoader } from '../Components/RPCConfigLoader';
|
|
20
|
20
|
import { FrontworkComponent } from '../Types/FrontworkComponent';
|
|
21
|
21
|
import { IAdmin } from './Interface';
|
|
22
|
22
|
import { Injector } from '../Injector/Injector';
|
|
23
|
23
|
import { PubSub } from '../Components/PubSub/PubSub';
|
|
|
24
|
+import { BurstyRateLimiter, RateLimiterMemory, RateLimiterAbstract } from 'rate-limiter-flexible'
|
|
|
25
|
+
|
|
24
|
26
|
|
|
25
|
27
|
@RootComponent({
|
|
26
|
28
|
injectable: IAdmin,
|
|
|
@@ -67,13 +69,24 @@ export class FrontworkAdmin
|
|
67
|
69
|
|
|
68
|
70
|
async start() {
|
|
69
|
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
|
84
|
await this.makeKnex()
|
|
72
|
|
- const app = await this.makeExpress()
|
|
|
85
|
+ const app = await this.makeExpress(rateLimiter)
|
|
73
|
86
|
const httpServer = new http.Server(app)
|
|
74
|
87
|
await this.startWebsocket(httpServer)
|
|
75
|
88
|
httpServer.listen(port)
|
|
76
|
|
- await this.attachAngularSSR(app)
|
|
|
89
|
+ await this.attachAngularSSR(app, rateLimiter)
|
|
77
|
90
|
getLogger('Admin#startWebsocket').debug("Webserver up on", port)
|
|
78
|
91
|
|
|
79
|
92
|
await Promise.all(this.frontworkComponents.map(c => c.initialize ? c.initialize() : undefined))
|
|
|
@@ -125,51 +138,53 @@ export class FrontworkAdmin
|
|
125
|
138
|
}
|
|
126
|
139
|
], {
|
|
127
|
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
|
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
|
150
|
if (this.httpServer != null || this.express != null) {
|
|
138
|
151
|
getLogger('Admin#startWebserver').warn("Webserver is already running")
|
|
139
|
152
|
return
|
|
140
|
153
|
}
|
|
141
|
154
|
|
|
142
|
155
|
this.express = express()
|
|
143
|
|
-
|
|
144
|
156
|
const distFolder = "../../../../dist"
|
|
145
|
|
-
|
|
146
|
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
|
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
|
181
|
const distFolder = "../../../../dist"
|
|
167
|
182
|
const ngExpressServer = Path.join(__dirname, distFolder, 'server.js')
|
|
168
|
183
|
let port: number = this.config.getConfig().httpPort
|
|
169
|
184
|
|
|
170
|
185
|
try {
|
|
171
|
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
|
188
|
getLogger('Admin#startWebserver').debug('Frontend from ' + ngExpressServer + " loaded")
|
|
174
|
189
|
} catch (e) {
|
|
175
|
190
|
getLogger('Admin#startWebserver').error(e)
|