badmfck-api-server 2.8.4 → 2.8.5

Sign up to get free protection for your applications and to get access to all the features.
@@ -5,6 +5,10 @@ import { IBaseEndpoint } from './BaseEndpoint';
5
5
  import { HTTPRequestVO, IError, TransferPacketVO } from './structures/Interfaces';
6
6
  import { Req } from "badmfck-signal";
7
7
  import http from 'http';
8
+ export interface IMonitorUser {
9
+ login: string;
10
+ password: string;
11
+ }
8
12
  export interface APIServiceNetworkLogItem {
9
13
  id: number;
10
14
  created: number;
@@ -30,10 +34,7 @@ export interface APIServiceOptions {
30
34
  interceptor?: IBaseEndpoint;
31
35
  postproducer?: (req: HTTPRequestVO | undefined | null, res: Response, data: TransferPacketVO<any>, requestTime: number, endpoint?: string, log?: APIServiceNetworkLogItem | null) => Promise<TransferPacketVO>;
32
36
  preproducer?: (req: HTTPRequestVO | undefined | null) => any;
33
- monitor?: {
34
- login: string;
35
- password: string;
36
- }[];
37
+ monitor?: IMonitorUser[];
37
38
  appVersion?: string;
38
39
  fileTempDir: string;
39
40
  fileLimit: number;
@@ -47,15 +48,13 @@ export declare const REQ_HTTP_SERVER: Req<void, {
47
48
  http: http.Server;
48
49
  }>;
49
50
  export declare const REQ_INTERNAL_CALL: Req<HTTPRequestVO, IError | any>;
50
- export declare const REQ_MONITOR_USERS: Req<{
51
- authorization: string;
52
- }, any>;
51
+ export declare const REQ_MONITOR_USERS: Req<void, IMonitorUser[]>;
53
52
  export declare function Initializer(services: IBaseService[]): Promise<void>;
54
53
  export declare class APIService extends BaseService {
55
54
  private static nextLogID;
56
55
  private version;
57
56
  private options;
58
- private monitor?;
57
+ private monitor;
59
58
  private monitorIndexFile?;
60
59
  private started;
61
60
  private requestsCount;
@@ -46,6 +46,7 @@ const http_1 = __importDefault(require("http"));
46
46
  const MysqlService_1 = require("./MysqlService");
47
47
  const StatService_1 = require("./StatService");
48
48
  const ExternalServiceEndpoint_1 = require("./external/ExternalServiceEndpoint");
49
+ const MonitorService_1 = require("./MonitorService");
49
50
  function getDefaultOptions() {
50
51
  return {
51
52
  port: 8091,
@@ -74,7 +75,6 @@ exports.REQ_HTTP_SERVER = new badmfck_signal_1.Req(undefined, "REQ_HTTP_SERVER")
74
75
  exports.REQ_INTERNAL_CALL = new badmfck_signal_1.Req(undefined, "REQ_INTERNAL_CALL");
75
76
  exports.REQ_MONITOR_USERS = new badmfck_signal_1.Req(undefined, "REQ_MONITOR_USERS");
76
77
  const activeServices = [];
77
- const entryPoints = [];
78
78
  async function Initializer(services) {
79
79
  services.push(new StatService_1.StatService());
80
80
  for (let i of services) {
@@ -88,9 +88,9 @@ async function Initializer(services) {
88
88
  exports.Initializer = Initializer;
89
89
  class APIService extends BaseService_1.BaseService {
90
90
  static nextLogID = 0;
91
- version = "2.8.4";
91
+ version = "2.8.5";
92
92
  options;
93
- monitor;
93
+ monitor = null;
94
94
  monitorIndexFile;
95
95
  started = new Date();
96
96
  requestsCount = 0;
@@ -105,24 +105,9 @@ class APIService extends BaseService_1.BaseService {
105
105
  if (!this.options.corsHostWhiteList.find(val => val === self))
106
106
  this.options.corsHostWhiteList.push();
107
107
  if (this.options.monitor && this.options.monitor.length > 0) {
108
- this.monitor = new Monitor_1.Monitor();
109
- this.options.endpoints.push(this.monitor);
110
- console.warn("Service Monitor initialized");
111
- console.warn("monitor links:");
112
- for (let i of this.options.monitor) {
113
- const hash = crypto_1.default.createHash("sha256").update(i.login + i.password).digest().toString("hex");
114
- console.warn("Monitor link for: " + i.login + " -> /sm-" + hash);
115
- }
116
- exports.REQ_MONITOR_USERS.listener = async (req) => {
117
- const result = [];
118
- if (this.options.monitor) {
119
- for (let i of this.options.monitor) {
120
- const hash = crypto_1.default.createHash("sha256").update(i.login + i.password).digest().toString("hex");
121
- result.push(hash);
122
- }
123
- }
124
- return result;
125
- };
108
+ exports.REQ_MONITOR_USERS.listener = async () => this.options.monitor ?? [];
109
+ this.monitor = new MonitorService_1.MonitorService();
110
+ this.options.endpoints.push(new Monitor_1.Monitor());
126
111
  }
127
112
  this.options.endpoints.push(new ExternalServiceEndpoint_1.ExternalServiceEndpoint());
128
113
  this.options.endpoints.push(new Liveness_1.Liveness(this.started), new Readiness_1.Readiness(this.started));
@@ -299,8 +284,6 @@ class APIService extends BaseService_1.BaseService {
299
284
  httpRequest.interceptorResult = interceptorResult;
300
285
  }
301
286
  }
302
- if (i === this.monitor)
303
- httpRequest.precheck = { data: this.options.monitor };
304
287
  const precheck = await i.precheck(httpRequest);
305
288
  if (precheck && precheck.error) {
306
289
  this.sendResponse(req.get("Referer") ?? "", res, precheck, tme, ep, log, httpRequest);
@@ -313,8 +296,6 @@ class APIService extends BaseService_1.BaseService {
313
296
  console.error(e);
314
297
  if (this.options.onError)
315
298
  this.options.onError(e);
316
- if (this.monitor)
317
- this.monitor.registrateFatalError(ep);
318
299
  let data = {
319
300
  error: {
320
301
  code: 10002,
@@ -388,8 +369,6 @@ class APIService extends BaseService_1.BaseService {
388
369
  this.options.onNetworkLog(log);
389
370
  return;
390
371
  }
391
- if (req && req.stream) {
392
- }
393
372
  if (this.options.postproducer) {
394
373
  try {
395
374
  data = await this.options.postproducer(req, res, data, requestTime, endpoint, log);
@@ -409,15 +388,11 @@ class APIService extends BaseService_1.BaseService {
409
388
  log.time = data.responseTime;
410
389
  log.referer = ref;
411
390
  }
412
- if (this.monitor)
413
- this.monitor.registrateResponse(data.endpoint, data.responseTime);
414
391
  if (res.destroyed || res.closed) {
415
392
  if (log)
416
393
  log.error = "Connection already closed, can't send response for: " + data.endpoint;
417
394
  if (this.options.onError)
418
395
  this.options.onError("Connection already closed, can't send response: " + data.endpoint, data);
419
- if (this.monitor)
420
- this.monitor.registrateError(data.endpoint);
421
396
  }
422
397
  else {
423
398
  try {
@@ -426,8 +401,6 @@ class APIService extends BaseService_1.BaseService {
426
401
  if (err) {
427
402
  if (log)
428
403
  log.error = "Can't send file: " + data.file;
429
- if (this.monitor && data.endpoint)
430
- this.monitor.registrateAPIError(data.endpoint);
431
404
  this.sendResponse(ref, res, {
432
405
  error: DefaultErrors_1.default.CANT_SEND_FILE,
433
406
  data: null,
@@ -460,8 +433,7 @@ class APIService extends BaseService_1.BaseService {
460
433
  res.send(data);
461
434
  if (log)
462
435
  log.response = this.checkDataLength(data);
463
- if (data.error && this.monitor) {
464
- this.monitor.registrateAPIError(data.endpoint);
436
+ if (data.error) {
465
437
  if (log)
466
438
  log.error = data.error.message;
467
439
  }
@@ -473,8 +445,6 @@ class APIService extends BaseService_1.BaseService {
473
445
  this.options.onError("Can't send response", e);
474
446
  if (log)
475
447
  log.error = "Can't send response";
476
- if (this.monitor)
477
- this.monitor.registrateError(data.endpoint);
478
448
  }
479
449
  }
480
450
  if (log && log.error && this.options.onError) {
@@ -0,0 +1,4 @@
1
+ import { BaseService } from "./BaseService";
2
+ export declare class MonitorService extends BaseService {
3
+ constructor();
4
+ }
@@ -0,0 +1,10 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.MonitorService = void 0;
4
+ const BaseService_1 = require("./BaseService");
5
+ class MonitorService extends BaseService_1.BaseService {
6
+ constructor() {
7
+ super("MonitorService");
8
+ }
9
+ }
10
+ exports.MonitorService = MonitorService;
@@ -10,39 +10,15 @@ interface IStatObject {
10
10
  fatalErrors: Map<string, number>;
11
11
  apiErrors: Map<string, number>;
12
12
  }
13
- interface ISystemStat {
14
- cpuUsage: any;
15
- memoryTotal: number;
16
- memoryUsage: any;
17
- }
18
13
  export declare const S_MONITOR_REGISTRATE_ACTION: Signal<IUserAction>;
19
14
  export declare class Monitor extends BaseEndpoint {
20
15
  ignoreHttpLogging: boolean;
21
- private httpRequests;
22
- private systemStat;
23
- private userActions;
24
- private registeredActions;
16
+ users: Map<string, IStatObject>;
25
17
  constructor();
26
- registrateAction(data: IUserAction): void;
27
- addSystemStat(): void;
28
- registrateError(endpoint: string): void;
29
- registrateFatalError(endpoint: string): void;
30
- registrateAPIError(endpoint: string): void;
31
- registrateResponse(endpoint: string, responseTime: number): void;
32
- increaseStat(statObject: Map<string, number>, endpoint: string): void;
33
- createStatObj(): IStatObject;
34
- createSystemStatObj(): ISystemStat;
35
- getDateIndex(d: Date): number;
36
- getHourMinuteIndex(d: Date): string;
37
- leadZero(i: number): string;
38
- precheck(req: HTTPRequestVO): Promise<TransferPacketVO<any> | null>;
39
- logs(req: HTTPRequestVO): Promise<TransferPacketVO<any>>;
40
- netlog(req: HTTPRequestVO): Promise<TransferPacketVO<any>>;
41
- metrics(req: HTTPRequestVO): Promise<TransferPacketVO<any>>;
42
- serverStat(req: HTTPRequestVO): Promise<TransferPacketVO<any>>;
43
- mapToKeyValue(map: Map<string, string | number>): {
44
- name: string;
45
- value: string | number;
46
- }[];
18
+ logs(req: HTTPRequestVO): Promise<TransferPacketVO>;
19
+ netlog(req: HTTPRequestVO): Promise<TransferPacketVO>;
20
+ metrics(req: HTTPRequestVO): Promise<TransferPacketVO>;
21
+ serverStat(req: HTTPRequestVO): Promise<TransferPacketVO>;
22
+ checkAuthentication(req: HTTPRequestVO): Promise<boolean>;
47
23
  }
48
24
  export {};
@@ -10,254 +10,69 @@ const BaseEndpoint_1 = require("../BaseEndpoint");
10
10
  const LogService_1 = require("../LogService");
11
11
  const crypto_1 = __importDefault(require("crypto"));
12
12
  const os_1 = __importDefault(require("os"));
13
+ const DefaultErrors_1 = __importDefault(require("../structures/DefaultErrors"));
13
14
  exports.S_MONITOR_REGISTRATE_ACTION = new badmfck_signal_1.Signal();
14
15
  class Monitor extends BaseEndpoint_1.BaseEndpoint {
15
16
  ignoreHttpLogging = true;
16
- httpRequests = new Map();
17
- systemStat = new Map();
18
- userActions = new Map();
19
- registeredActions = 0;
17
+ users = new Map();
20
18
  constructor() {
21
- super("sys-monitor");
22
- exports.S_MONITOR_REGISTRATE_ACTION.subscribe(data => this.registrateAction(data));
19
+ super("--sys-monitor");
23
20
  this.registerEndpoints([
24
21
  { ignoreInterceptor: true, endpoint: "log", handler: this.logs },
25
22
  { ignoreInterceptor: true, endpoint: "netlog", handler: this.netlog },
26
23
  { ignoreInterceptor: true, endpoint: "metrics", handler: this.metrics },
27
- { ignoreInterceptor: true, endpoint: "server/stat", handler: this.serverStat }
24
+ { ignoreInterceptor: true, endpoint: "server", handler: this.serverStat }
28
25
  ]);
29
- setInterval(() => {
30
- this.addSystemStat();
31
- }, 1000 * 60 * 10);
32
- this.addSystemStat();
33
- }
34
- registrateAction(data) {
35
- if (!data.action)
36
- return;
37
- if (typeof data.action !== "string")
38
- return;
39
- if (data.action.length > 20)
40
- data.action = data.action.substring(0, 20);
41
- const d = new Date();
42
- const doy = this.getDateIndex(d);
43
- let day = this.userActions.get(doy);
44
- if (!day) {
45
- day = new Map();
46
- this.userActions.set(doy, day);
47
- if (this.userActions.size > 7) {
48
- for (let i of this.userActions) {
49
- this.userActions.delete(i[0]);
50
- break;
51
- }
52
- }
53
- }
54
- const minute = this.getHourMinuteIndex(d);
55
- let m = day.get(minute);
56
- if (!m) {
57
- m = new Map();
58
- day.set(minute, m);
59
- }
60
- let cnt = m.get(data.action);
61
- if (!cnt)
62
- cnt = 0;
63
- cnt++;
64
- m.set(data.action, cnt);
65
- }
66
- addSystemStat() {
67
- const so = this.createSystemStatObj();
68
- so.memoryUsage = process.memoryUsage();
69
- so.memoryTotal = os_1.default.totalmem();
70
- }
71
- registrateError(endpoint) {
72
- const so = this.createStatObj();
73
- this.increaseStat(so.errors, endpoint);
74
- }
75
- registrateFatalError(endpoint) {
76
- const so = this.createStatObj();
77
- this.increaseStat(so.fatalErrors, endpoint);
78
- }
79
- registrateAPIError(endpoint) {
80
- const so = this.createStatObj();
81
- this.increaseStat(so.apiErrors, endpoint);
82
- }
83
- registrateResponse(endpoint, responseTime) {
84
- const so = this.createStatObj();
85
- this.increaseStat(so.requests, endpoint);
86
- }
87
- increaseStat(statObject, endpoint) {
88
- let reqep = statObject.get(endpoint);
89
- if (!reqep)
90
- reqep = 0;
91
- reqep += 1;
92
- statObject.set(endpoint, reqep);
93
- this.registeredActions++;
94
- }
95
- createStatObj() {
96
- const d = new Date();
97
- const dtm = this.getDateIndex(d);
98
- let day = this.httpRequests.get(dtm);
99
- if (!day) {
100
- day = new Map();
101
- this.httpRequests.set(dtm, day);
102
- if (this.httpRequests.size > 7) {
103
- for (let i of this.httpRequests) {
104
- this.httpRequests.delete(i[0]);
105
- break;
106
- }
107
- }
108
- }
109
- const hourMinute = this.getHourMinuteIndex(d);
110
- let hm = day.get(hourMinute);
111
- if (!hm) {
112
- hm = {
113
- errors: new Map(),
114
- requests: new Map(),
115
- fatalErrors: new Map(),
116
- apiErrors: new Map()
117
- };
118
- day.set(hourMinute, hm);
119
- }
120
- return hm;
121
- }
122
- createSystemStatObj() {
123
- const d = new Date();
124
- const dtm = this.getDateIndex(d);
125
- let day = this.systemStat.get(dtm);
126
- if (!day) {
127
- day = new Map();
128
- this.systemStat.set(dtm, day);
129
- if (this.systemStat.size > 7) {
130
- for (let i of this.systemStat) {
131
- this.systemStat.delete(i[0]);
132
- break;
133
- }
134
- }
135
- }
136
- const hourMinute = this.getHourMinuteIndex(d);
137
- let hm = day.get(hourMinute);
138
- if (!hm) {
139
- hm = {
140
- cpuUsage: 0,
141
- memoryTotal: 0,
142
- memoryUsage: {}
143
- };
144
- day.set(hourMinute, hm);
145
- }
146
- return hm;
147
- }
148
- getDateIndex(d) {
149
- const dtm = d;
150
- return parseInt(dtm.getFullYear().toString().substring(2) + this.leadZero(dtm.getMonth() + 1) + this.leadZero(dtm.getDate()));
151
- }
152
- getHourMinuteIndex(d) {
153
- const dtm = d;
154
- return this.leadZero(dtm.getHours()) + this.leadZero(dtm.getMinutes());
155
- }
156
- leadZero(i) {
157
- if (i > 9)
158
- return i + "";
159
- return "0" + i;
160
- }
161
- async precheck(req) {
162
- if (!req.headers)
163
- return { error: { code: 10001, message: "No authorization", httpStatus: 400 } };
164
- if (!req.headers['authorization'])
165
- return { error: { code: 10002, message: "No authorization found", httpStatus: 400 } };
166
- const auth = req.headers['authorization'];
167
- if (!req.precheck || !Array.isArray(req.precheck.data)) {
168
- return { error: { code: 10003, message: "No authorization records found", httpStatus: 400 } };
169
- }
170
- let authorized = false;
171
- for (let i of req.precheck.data) {
172
- let expectationStr = "";
173
- expectationStr += req.endpoint;
174
- expectationStr += JSON.stringify(i);
175
- expectationStr += JSON.stringify(req.method);
176
- expectationStr += JSON.stringify(req.data);
177
- expectationStr += JSON.stringify(req.params);
178
- const expectation = "sha256 " + crypto_1.default.createHash("sha256").update(expectationStr).digest().toString("hex");
179
- if (auth === expectation) {
180
- authorized = true;
181
- break;
182
- }
183
- }
184
- if (!authorized) {
185
- console.error("Wrong token: " + auth);
186
- return { error: { code: 10004, message: "Unauthorized access", httpStatus: 401 } };
187
- }
188
- return null;
189
26
  }
190
27
  async logs(req) {
191
- const log = await LogService_1.REQ_LOG.request(null);
192
- return { data: log };
28
+ this.checkAuthentication(req);
29
+ const services = await LogService_1.REQ_LOG_UNIQUE_SERVICES.request();
30
+ const log = await LogService_1.REQ_LOG.request({
31
+ lastID: req.data.lastID ?? 0
32
+ });
33
+ return {
34
+ data: {
35
+ services,
36
+ log
37
+ }
38
+ };
193
39
  }
194
40
  async netlog(req) {
195
- const log = await APIService_1.REQ_HTTP_LOG.request();
196
- return { data: log };
41
+ this.checkAuthentication(req);
42
+ return {};
197
43
  }
198
44
  async metrics(req) {
199
- const date = new Date();
200
- const di = this.getDateIndex(date);
201
- const stat = this.httpRequests.get(di);
202
- let result = [];
203
- if (stat) {
204
- for (let minutes of stat) {
205
- result.push({
206
- m: minutes[0],
207
- ae: this.mapToKeyValue(minutes[1].apiErrors),
208
- e: this.mapToKeyValue(minutes[1].errors),
209
- r: this.mapToKeyValue(minutes[1].requests),
210
- fe: this.mapToKeyValue(minutes[1].fatalErrors),
211
- });
212
- }
213
- }
214
- const ua = this.userActions.get(di);
215
- let uaResult = [];
216
- if (ua) {
217
- for (let i of ua) {
218
- const minutes = i[1];
219
- const mArray = [];
220
- for (let j of i[0]) {
221
- mArray.push({
222
- action: j[0],
223
- count: j[1]
224
- });
225
- }
226
- result.push({
227
- m: i[0],
228
- data: mArray
229
- });
230
- }
231
- }
232
- return { data: { stat: result, date: +date, userActions: uaResult } };
45
+ this.checkAuthentication(req);
46
+ return {};
233
47
  }
234
48
  async serverStat(req) {
235
- const date = new Date();
236
- const di = this.getDateIndex(date);
237
- const stat = this.systemStat.get(di);
238
- if (!stat)
239
- return { data: [] };
240
- let result = [];
241
- for (let minutes of stat) {
242
- result.push({
243
- m: minutes[0],
244
- mt: minutes[1].memoryTotal,
245
- mu: minutes[1].memoryUsage,
246
- cu: minutes[1].cpuUsage,
247
- });
49
+ this.checkAuthentication(req);
50
+ let stat = {
51
+ cpuUsage: os_1.default.cpus(),
52
+ memoryTotal: os_1.default.totalmem(),
53
+ memoryUsage: os_1.default.freemem()
54
+ };
55
+ return { data: stat };
56
+ }
57
+ async checkAuthentication(req) {
58
+ const users = await APIService_1.REQ_MONITOR_USERS.request();
59
+ const header = req.headers['authorization'];
60
+ if (!header)
61
+ throw { ...DefaultErrors_1.default.UNAUTHORIZED, details: "No authorization header found" };
62
+ for (let i of users) {
63
+ let hashStr = "";
64
+ hashStr += req.endpoint;
65
+ hashStr += JSON.stringify(i);
66
+ hashStr += JSON.stringify(req.method.toUpperCase());
67
+ hashStr += JSON.stringify(req.data ?? {});
68
+ hashStr += JSON.stringify(req.params ?? {});
69
+ let token = null;
70
+ token = "sha256 " + crypto_1.default.createHash('sha256').update(hashStr).digest('hex');
71
+ if (token == header) {
72
+ return true;
73
+ }
248
74
  }
249
- return { data: {
250
- registeredActions: this.registeredActions,
251
- uptime: process.uptime(),
252
- osUptime: os_1.default.uptime(),
253
- stat: result
254
- } };
255
- }
256
- mapToKeyValue(map) {
257
- const res = [];
258
- for (let i of map)
259
- res.push({ name: i[0], value: i[1] });
260
- return res;
75
+ throw { ...DefaultErrors_1.default.UNAUTHORIZED, details: "Invalid token" };
261
76
  }
262
77
  }
263
78
  exports.Monitor = Monitor;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "badmfck-api-server",
3
- "version": "2.8.4",
3
+ "version": "2.8.5",
4
4
  "description": "Simple API http server based on express",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",