namirasoft-node 1.0.11 → 1.0.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/BaseController.d.ts +7 -0
- package/dist/BaseController.js +96 -0
- package/dist/BaseController.js.map +1 -1
- package/dist/OTPOperation.d.ts +12 -0
- package/dist/OTPOperation.js +70 -0
- package/dist/OTPOperation.js.map +1 -0
- package/dist/index.d.ts +0 -1
- package/dist/index.js +0 -1
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/BaseController.ts +110 -0
- package/src/OTPOperation.ts +65 -0
- package/src/index.ts +0 -1
- package/dist/BaseMiddleware.d.ts +0 -14
- package/dist/BaseMiddleware.js +0 -108
- package/dist/BaseMiddleware.js.map +0 -1
- package/src/BaseMiddleware.ts +0 -121
package/dist/BaseController.d.ts
CHANGED
|
@@ -2,14 +2,21 @@ import * as express from 'express';
|
|
|
2
2
|
import { BaseDatabase } from './BaseDatabase';
|
|
3
3
|
import { SchemaLike } from 'joi';
|
|
4
4
|
import { AnomalyDetector } from './AnomalyDetector';
|
|
5
|
+
import { ILogger } from 'namirasoft-log';
|
|
5
6
|
export declare abstract class BaseController<D extends BaseDatabase, State, Props> {
|
|
6
7
|
showLogAtTheBeginning: boolean;
|
|
7
8
|
showLogAtTheEnd: boolean;
|
|
9
|
+
protected logger: ILogger;
|
|
10
|
+
constructor();
|
|
11
|
+
abstract getLogger(): ILogger;
|
|
12
|
+
abstract getDatabase(): Promise<D>;
|
|
8
13
|
abstract getAnomaly(): AnomalyDetector | null;
|
|
9
14
|
abstract getBodySchema(): SchemaLike | null;
|
|
10
15
|
abstract getQuerySchema(): SchemaLike | null;
|
|
11
16
|
abstract getState(): State;
|
|
17
|
+
abstract getProps(req: express.Request, res: express.Response, database: D, state: State): Promise<Props>;
|
|
12
18
|
abstract preHandle(req: express.Request, res: express.Response, database: D, props: Props): Promise<void>;
|
|
13
19
|
abstract handle(req: express.Request, res: express.Response, database: D, props: Props): Promise<any>;
|
|
14
20
|
abstract postHandle(req: express.Request, res: express.Response, database: D, props: Props): Promise<void>;
|
|
21
|
+
getHandler(): (req: express.Request, res: express.Response) => Promise<express.Response<any, Record<string, any>>>;
|
|
15
22
|
}
|
package/dist/BaseController.js
CHANGED
|
@@ -1,10 +1,106 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
12
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
13
|
+
};
|
|
2
14
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
15
|
exports.BaseController = void 0;
|
|
16
|
+
const Meta_1 = require("./Meta");
|
|
17
|
+
const joi_1 = __importDefault(require("joi"));
|
|
18
|
+
const namirasoft_core_1 = require("namirasoft-core");
|
|
4
19
|
class BaseController {
|
|
5
20
|
constructor() {
|
|
6
21
|
this.showLogAtTheBeginning = false;
|
|
7
22
|
this.showLogAtTheEnd = true;
|
|
23
|
+
this.logger = this.getLogger();
|
|
24
|
+
}
|
|
25
|
+
getHandler() {
|
|
26
|
+
return (req, res) => __awaiter(this, void 0, void 0, function* () {
|
|
27
|
+
// meta
|
|
28
|
+
let meta = new Meta_1.Meta(req);
|
|
29
|
+
// result
|
|
30
|
+
let result = {};
|
|
31
|
+
try {
|
|
32
|
+
// meta
|
|
33
|
+
meta.onStart();
|
|
34
|
+
if (this.showLogAtTheBeginning)
|
|
35
|
+
this.logger.info(JSON.stringify(meta));
|
|
36
|
+
// init controller
|
|
37
|
+
let database = yield this.getDatabase();
|
|
38
|
+
let state = this.getState();
|
|
39
|
+
let props = yield this.getProps(req, res, database, state);
|
|
40
|
+
// preHandle
|
|
41
|
+
yield this.preHandle(req, res, database, props);
|
|
42
|
+
// check for anomaly
|
|
43
|
+
let anomaly = this.getAnomaly();
|
|
44
|
+
if (anomaly != null)
|
|
45
|
+
if (anomaly.isAnomaly(meta.ip, meta.url))
|
|
46
|
+
namirasoft_core_1.ErrorOperation.throwHTTP(403, 'Suspicious activity detected.');
|
|
47
|
+
// check body validation
|
|
48
|
+
let bodySchema = this.getBodySchema();
|
|
49
|
+
if (bodySchema != null) {
|
|
50
|
+
const validation = yield joi_1.default.compile(bodySchema)
|
|
51
|
+
.prefs({ errors: { label: 'key' } })
|
|
52
|
+
.validate(req.body);
|
|
53
|
+
if (validation.error) {
|
|
54
|
+
let message = validation.error.details.map((details) => details.message).join(', ');
|
|
55
|
+
namirasoft_core_1.ErrorOperation.throwHTTP(400, message);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
// check query validation
|
|
59
|
+
let querySchema = this.getQuerySchema();
|
|
60
|
+
if (querySchema != null) {
|
|
61
|
+
const validation = yield joi_1.default.compile(querySchema)
|
|
62
|
+
.prefs({ errors: { label: 'key' } })
|
|
63
|
+
.validate(req.query);
|
|
64
|
+
if (validation.error) {
|
|
65
|
+
let message = validation.error.details.map((details) => details.message).join(', ');
|
|
66
|
+
namirasoft_core_1.ErrorOperation.throwHTTP(400, message);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
// call controller
|
|
70
|
+
result = yield this.handle(req, res, database, props);
|
|
71
|
+
if (result == null)
|
|
72
|
+
result = "Success";
|
|
73
|
+
// postHandle
|
|
74
|
+
yield this.postHandle(req, res, database, props);
|
|
75
|
+
}
|
|
76
|
+
catch (error) {
|
|
77
|
+
let message;
|
|
78
|
+
if (error instanceof Error) {
|
|
79
|
+
meta.error = error;
|
|
80
|
+
message = error.message;
|
|
81
|
+
}
|
|
82
|
+
else
|
|
83
|
+
message = error + "";
|
|
84
|
+
if (error instanceof namirasoft_core_1.HTTPError) {
|
|
85
|
+
meta.code = error.code;
|
|
86
|
+
this.logger.error(error.message + "\n" + JSON.stringify(meta), undefined, error.stack);
|
|
87
|
+
}
|
|
88
|
+
else {
|
|
89
|
+
meta.code = 500;
|
|
90
|
+
if (error instanceof Error)
|
|
91
|
+
this.logger.critical(error.message + "\n" + JSON.stringify(meta), undefined, error.stack);
|
|
92
|
+
}
|
|
93
|
+
meta.message = message;
|
|
94
|
+
if (error instanceof namirasoft_core_1.HTTPError)
|
|
95
|
+
result = meta.message;
|
|
96
|
+
else
|
|
97
|
+
result = "Sorry, internl server error.";
|
|
98
|
+
}
|
|
99
|
+
meta.onFinish();
|
|
100
|
+
if (this.showLogAtTheEnd)
|
|
101
|
+
this.logger.info(JSON.stringify(meta));
|
|
102
|
+
return res.status(meta.code).send(result);
|
|
103
|
+
});
|
|
8
104
|
}
|
|
9
105
|
}
|
|
10
106
|
exports.BaseController = BaseController;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"BaseController.js","sourceRoot":"","sources":["../src/BaseController.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"BaseController.js","sourceRoot":"","sources":["../src/BaseController.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export declare class OTPOperation {
|
|
2
|
+
static generate(length?: number, digit?: number): string;
|
|
3
|
+
static getWaitTime(min_wait_time: number, max_wait_time: number, min_attempt: number, user_attemptted: number, increase_power_base?: number): number;
|
|
4
|
+
static onSafeRequest(handler: () => Promise<void>, last_tried_time: Date, min_wait_time: number, max_wait_time: number, min_attempt: number, user_attemptted: number, increase_power_base?: number): Promise<{
|
|
5
|
+
error: string;
|
|
6
|
+
next_time: number;
|
|
7
|
+
} | {
|
|
8
|
+
next_time: number;
|
|
9
|
+
error?: undefined;
|
|
10
|
+
}>;
|
|
11
|
+
static onSafeVerify(otp: string, otp_expire_time: number, max_try_count: number, user_otp: string, user_otp_time: Date, user_tried_count: number, handler: () => Promise<void>, errorHandler: () => Promise<void>): Promise<void>;
|
|
12
|
+
}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.OTPOperation = void 0;
|
|
13
|
+
const namirasoft_core_1 = require("namirasoft-core");
|
|
14
|
+
class OTPOperation {
|
|
15
|
+
static generate(length = 6, digit = 3) {
|
|
16
|
+
if (!length)
|
|
17
|
+
length = 6;
|
|
18
|
+
if (!digit)
|
|
19
|
+
digit = 3;
|
|
20
|
+
let dig = [];
|
|
21
|
+
for (let i = 0; i < digit; i++)
|
|
22
|
+
dig[i] = parseInt((Math.random() * 9 + 1) + "");
|
|
23
|
+
let ans = '';
|
|
24
|
+
for (let i = 0; i < length; i++)
|
|
25
|
+
ans = ans + '' + dig[parseInt((Math.random() * dig.length) + "")];
|
|
26
|
+
return ans;
|
|
27
|
+
}
|
|
28
|
+
static getWaitTime(min_wait_time, max_wait_time, min_attempt, user_attemptted, increase_power_base = 2) {
|
|
29
|
+
let wait_time = min_wait_time;
|
|
30
|
+
let extra_attempt = user_attemptted - min_attempt;
|
|
31
|
+
if (extra_attempt > 0)
|
|
32
|
+
wait_time = Math.min(Math.pow(increase_power_base, extra_attempt) * 60, max_wait_time);
|
|
33
|
+
return parseInt(wait_time + "");
|
|
34
|
+
}
|
|
35
|
+
static onSafeRequest(handler, last_tried_time, min_wait_time, max_wait_time, min_attempt, user_attemptted, increase_power_base = 2) {
|
|
36
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
37
|
+
// check wait time
|
|
38
|
+
let wait_time = this.getWaitTime(min_wait_time, max_wait_time, min_attempt, user_attemptted, increase_power_base);
|
|
39
|
+
let wait_date = namirasoft_core_1.TimeOperation.minutesAgo(wait_time, new Date());
|
|
40
|
+
let next_time = namirasoft_core_1.TimeOperation.diffInSecond(last_tried_time, wait_date, false);
|
|
41
|
+
if (next_time > 0) {
|
|
42
|
+
return {
|
|
43
|
+
error: 'Too many request, please try again in ' + next_time + ' seconds.',
|
|
44
|
+
next_time
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
yield handler();
|
|
48
|
+
wait_time = this.getWaitTime(min_wait_time, max_wait_time, min_attempt, user_attemptted + 1, increase_power_base);
|
|
49
|
+
next_time = wait_time * 60;
|
|
50
|
+
return { next_time };
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
static onSafeVerify(otp, otp_expire_time, max_try_count, user_otp, user_otp_time, user_tried_count, handler, errorHandler) {
|
|
54
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
55
|
+
if (!otp)
|
|
56
|
+
namirasoft_core_1.ErrorOperation.throwHTTP(403, "The OTP not generated yet.");
|
|
57
|
+
if (user_otp_time < namirasoft_core_1.TimeOperation.minutesAgo(otp_expire_time, new Date()))
|
|
58
|
+
namirasoft_core_1.ErrorOperation.throwHTTP(403, "The OTP code expired. Please request again.");
|
|
59
|
+
if (user_tried_count > max_try_count)
|
|
60
|
+
namirasoft_core_1.ErrorOperation.throwHTTP(403, "The try limit attempt exceeded. Please request again.");
|
|
61
|
+
if (user_otp !== otp) {
|
|
62
|
+
yield errorHandler();
|
|
63
|
+
namirasoft_core_1.ErrorOperation.throwHTTP(403, "Wrong code.");
|
|
64
|
+
}
|
|
65
|
+
yield handler();
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
exports.OTPOperation = OTPOperation;
|
|
70
|
+
//# sourceMappingURL=OTPOperation.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"OTPOperation.js","sourceRoot":"","sources":["../src/OTPOperation.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -2,7 +2,6 @@ export * from "./AnomalyDetector";
|
|
|
2
2
|
export * from "./BaseApplication";
|
|
3
3
|
export * from "./BaseController";
|
|
4
4
|
export * from "./BaseDatabase";
|
|
5
|
-
export * from "./BaseMiddleware";
|
|
6
5
|
export * from "./BaseSequelizeModel";
|
|
7
6
|
export * from "./BaseMySqlDatabase";
|
|
8
7
|
export * from "./BaseSequelizeTable";
|
package/dist/index.js
CHANGED
|
@@ -18,7 +18,6 @@ __exportStar(require("./AnomalyDetector"), exports);
|
|
|
18
18
|
__exportStar(require("./BaseApplication"), exports);
|
|
19
19
|
__exportStar(require("./BaseController"), exports);
|
|
20
20
|
__exportStar(require("./BaseDatabase"), exports);
|
|
21
|
-
__exportStar(require("./BaseMiddleware"), exports);
|
|
22
21
|
__exportStar(require("./BaseSequelizeModel"), exports);
|
|
23
22
|
__exportStar(require("./BaseMySqlDatabase"), exports);
|
|
24
23
|
__exportStar(require("./BaseSequelizeTable"), exports);
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,oDAAkC;AAClC,oDAAkC;AAClC,mDAAiC;AACjC,iDAA+B;AAC/B,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,oDAAkC;AAClC,oDAAkC;AAClC,mDAAiC;AACjC,iDAA+B;AAC/B,uDAAqC;AACrC,sDAAoC;AACpC,uDAAqC;AACrC,0DAAwC;AACxC,8CAA4B;AAC5B,iDAA+B;AAC/B,+CAA6B;AAC7B,gDAA8B;AAC9B,yDAAuC;AACvC,4DAA0C"}
|
package/package.json
CHANGED
package/src/BaseController.ts
CHANGED
|
@@ -2,15 +2,125 @@ import * as express from 'express';
|
|
|
2
2
|
import { BaseDatabase } from './BaseDatabase';
|
|
3
3
|
import { SchemaLike } from 'joi';
|
|
4
4
|
import { AnomalyDetector } from './AnomalyDetector';
|
|
5
|
+
import { ILogger } from 'namirasoft-log';
|
|
6
|
+
import { Meta } from './Meta';
|
|
7
|
+
import Joi from 'joi';
|
|
8
|
+
import { ErrorOperation, HTTPError } from 'namirasoft-core';
|
|
9
|
+
|
|
5
10
|
export abstract class BaseController<D extends BaseDatabase, State, Props>
|
|
6
11
|
{
|
|
7
12
|
showLogAtTheBeginning: boolean = false;
|
|
8
13
|
showLogAtTheEnd: boolean = true;
|
|
14
|
+
protected logger: ILogger;
|
|
15
|
+
constructor()
|
|
16
|
+
{
|
|
17
|
+
this.logger = this.getLogger();
|
|
18
|
+
}
|
|
19
|
+
abstract getLogger(): ILogger;
|
|
20
|
+
abstract getDatabase(): Promise<D>;
|
|
9
21
|
abstract getAnomaly(): AnomalyDetector | null;
|
|
10
22
|
abstract getBodySchema(): SchemaLike | null;
|
|
11
23
|
abstract getQuerySchema(): SchemaLike | null;
|
|
12
24
|
abstract getState(): State;
|
|
25
|
+
abstract getProps(req: express.Request, res: express.Response, database: D, state: State): Promise<Props>;
|
|
13
26
|
abstract preHandle(req: express.Request, res: express.Response, database: D, props: Props): Promise<void>;
|
|
14
27
|
abstract handle(req: express.Request, res: express.Response, database: D, props: Props): Promise<any>;
|
|
15
28
|
abstract postHandle(req: express.Request, res: express.Response, database: D, props: Props): Promise<void>;
|
|
29
|
+
|
|
30
|
+
getHandler()
|
|
31
|
+
{
|
|
32
|
+
return async (req: express.Request, res: express.Response) =>
|
|
33
|
+
{
|
|
34
|
+
// meta
|
|
35
|
+
let meta = new Meta(req);
|
|
36
|
+
// result
|
|
37
|
+
let result = {};
|
|
38
|
+
try
|
|
39
|
+
{
|
|
40
|
+
// meta
|
|
41
|
+
meta.onStart();
|
|
42
|
+
if (this.showLogAtTheBeginning)
|
|
43
|
+
this.logger.info(JSON.stringify(meta));
|
|
44
|
+
// init controller
|
|
45
|
+
let database = await this.getDatabase();
|
|
46
|
+
let state = this.getState();
|
|
47
|
+
let props = await this.getProps(req, res, database, state);
|
|
48
|
+
|
|
49
|
+
// preHandle
|
|
50
|
+
await this.preHandle(req, res, database, props);
|
|
51
|
+
|
|
52
|
+
// check for anomaly
|
|
53
|
+
let anomaly: AnomalyDetector | null = this.getAnomaly();
|
|
54
|
+
if (anomaly != null)
|
|
55
|
+
if (anomaly.isAnomaly(meta.ip, meta.url))
|
|
56
|
+
ErrorOperation.throwHTTP(403, 'Suspicious activity detected.');
|
|
57
|
+
|
|
58
|
+
// check body validation
|
|
59
|
+
let bodySchema = this.getBodySchema();
|
|
60
|
+
if (bodySchema != null)
|
|
61
|
+
{
|
|
62
|
+
const validation = await Joi.compile(bodySchema)
|
|
63
|
+
.prefs({ errors: { label: 'key' } })
|
|
64
|
+
.validate(req.body);
|
|
65
|
+
if (validation.error)
|
|
66
|
+
{
|
|
67
|
+
let message = validation.error.details.map((details) => details.message).join(', ');
|
|
68
|
+
ErrorOperation.throwHTTP(400, message);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
// check query validation
|
|
72
|
+
let querySchema = this.getQuerySchema();
|
|
73
|
+
if (querySchema != null)
|
|
74
|
+
{
|
|
75
|
+
const validation = await Joi.compile(querySchema)
|
|
76
|
+
.prefs({ errors: { label: 'key' } })
|
|
77
|
+
.validate(req.query);
|
|
78
|
+
if (validation.error)
|
|
79
|
+
{
|
|
80
|
+
let message = validation.error.details.map((details) => details.message).join(', ');
|
|
81
|
+
ErrorOperation.throwHTTP(400, message);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// call controller
|
|
86
|
+
result = await this.handle(req, res, database, props);
|
|
87
|
+
if (result == null)
|
|
88
|
+
result = "Success";
|
|
89
|
+
|
|
90
|
+
// postHandle
|
|
91
|
+
await this.postHandle(req, res, database, props);
|
|
92
|
+
} catch (error)
|
|
93
|
+
{
|
|
94
|
+
let message: string;
|
|
95
|
+
if (error instanceof Error)
|
|
96
|
+
{
|
|
97
|
+
meta.error = error;
|
|
98
|
+
message = error.message;
|
|
99
|
+
}
|
|
100
|
+
else
|
|
101
|
+
message = error + "";
|
|
102
|
+
|
|
103
|
+
if (error instanceof HTTPError)
|
|
104
|
+
{
|
|
105
|
+
meta.code = error.code;
|
|
106
|
+
this.logger.error(error.message + "\n" + JSON.stringify(meta), undefined, error.stack);
|
|
107
|
+
}
|
|
108
|
+
else
|
|
109
|
+
{
|
|
110
|
+
meta.code = 500;
|
|
111
|
+
if (error instanceof Error)
|
|
112
|
+
this.logger.critical(error.message + "\n" + JSON.stringify(meta), undefined, error.stack);
|
|
113
|
+
}
|
|
114
|
+
meta.message = message;
|
|
115
|
+
if (error instanceof HTTPError)
|
|
116
|
+
result = meta.message;
|
|
117
|
+
else
|
|
118
|
+
result = "Sorry, internl server error.";
|
|
119
|
+
}
|
|
120
|
+
meta.onFinish();
|
|
121
|
+
if (this.showLogAtTheEnd)
|
|
122
|
+
this.logger.info(JSON.stringify(meta));
|
|
123
|
+
return res.status(meta.code).send(result);
|
|
124
|
+
};
|
|
125
|
+
}
|
|
16
126
|
}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { ErrorOperation, TimeOperation } from "namirasoft-core";
|
|
2
|
+
|
|
3
|
+
export class OTPOperation
|
|
4
|
+
{
|
|
5
|
+
static generate(length: number = 6, digit: number = 3)
|
|
6
|
+
{
|
|
7
|
+
if (!length)
|
|
8
|
+
length = 6;
|
|
9
|
+
if (!digit)
|
|
10
|
+
digit = 3;
|
|
11
|
+
let dig = [];
|
|
12
|
+
for (let i = 0; i < digit; i++)
|
|
13
|
+
dig[i] = parseInt((Math.random() * 9 + 1) + "");
|
|
14
|
+
let ans = '';
|
|
15
|
+
for (let i = 0; i < length; i++)
|
|
16
|
+
ans = ans + '' + dig[parseInt((Math.random() * dig.length) + "")];
|
|
17
|
+
return ans;
|
|
18
|
+
}
|
|
19
|
+
static getWaitTime(min_wait_time: number, max_wait_time: number, min_attempt: number, user_attemptted: number, increase_power_base: number = 2): number
|
|
20
|
+
{
|
|
21
|
+
let wait_time = min_wait_time;
|
|
22
|
+
let extra_attempt = user_attemptted - min_attempt;
|
|
23
|
+
if (extra_attempt > 0)
|
|
24
|
+
wait_time = Math.min(Math.pow(increase_power_base, extra_attempt) * 60, max_wait_time);
|
|
25
|
+
return parseInt(wait_time + "");
|
|
26
|
+
}
|
|
27
|
+
static async onSafeRequest(handler: () => Promise<void>, last_tried_time: Date, min_wait_time: number, max_wait_time: number, min_attempt: number, user_attemptted: number, increase_power_base: number = 2)
|
|
28
|
+
{
|
|
29
|
+
// check wait time
|
|
30
|
+
let wait_time = this.getWaitTime(min_wait_time, max_wait_time, min_attempt, user_attemptted, increase_power_base);
|
|
31
|
+
let wait_date = TimeOperation.minutesAgo(wait_time, new Date());
|
|
32
|
+
let next_time = TimeOperation.diffInSecond(last_tried_time, wait_date, false);
|
|
33
|
+
if (next_time > 0)
|
|
34
|
+
{
|
|
35
|
+
return {
|
|
36
|
+
error: 'Too many request, please try again in ' + next_time + ' seconds.',
|
|
37
|
+
next_time
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
await handler();
|
|
41
|
+
wait_time = this.getWaitTime(min_wait_time, max_wait_time, min_attempt, user_attemptted + 1, increase_power_base);
|
|
42
|
+
next_time = wait_time * 60;
|
|
43
|
+
return { next_time };
|
|
44
|
+
}
|
|
45
|
+
static async onSafeVerify(otp: string, otp_expire_time: number, max_try_count: number,
|
|
46
|
+
user_otp: string, user_otp_time: Date, user_tried_count: number,
|
|
47
|
+
handler: () => Promise<void>, errorHandler: () => Promise<void>)
|
|
48
|
+
{
|
|
49
|
+
if (!otp)
|
|
50
|
+
ErrorOperation.throwHTTP(403, "The OTP not generated yet.");
|
|
51
|
+
|
|
52
|
+
if (user_otp_time < TimeOperation.minutesAgo(otp_expire_time, new Date()))
|
|
53
|
+
ErrorOperation.throwHTTP(403, "The OTP code expired. Please request again.");
|
|
54
|
+
|
|
55
|
+
if (user_tried_count > max_try_count)
|
|
56
|
+
ErrorOperation.throwHTTP(403, "The try limit attempt exceeded. Please request again.");
|
|
57
|
+
|
|
58
|
+
if (user_otp !== otp)
|
|
59
|
+
{
|
|
60
|
+
await errorHandler();
|
|
61
|
+
ErrorOperation.throwHTTP(403, "Wrong code.");
|
|
62
|
+
}
|
|
63
|
+
await handler();
|
|
64
|
+
}
|
|
65
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -2,7 +2,6 @@ export * from "./AnomalyDetector";
|
|
|
2
2
|
export * from "./BaseApplication";
|
|
3
3
|
export * from "./BaseController";
|
|
4
4
|
export * from "./BaseDatabase";
|
|
5
|
-
export * from "./BaseMiddleware";
|
|
6
5
|
export * from "./BaseSequelizeModel";
|
|
7
6
|
export * from "./BaseMySqlDatabase";
|
|
8
7
|
export * from "./BaseSequelizeTable";
|
package/dist/BaseMiddleware.d.ts
DELETED
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
import * as express from 'express';
|
|
2
|
-
import { BaseDatabase } from './BaseDatabase';
|
|
3
|
-
import { BaseController } from './BaseController';
|
|
4
|
-
import { ILogger } from "namirasoft-log";
|
|
5
|
-
export declare abstract class BaseMiddleware<D extends BaseDatabase, State, Props> {
|
|
6
|
-
protected logger: ILogger;
|
|
7
|
-
abstract getDatabase(): Promise<D>;
|
|
8
|
-
abstract getLogger(): ILogger;
|
|
9
|
-
abstract preHandle(req: express.Request, res: express.Response, database: D, props: Props): Promise<void>;
|
|
10
|
-
abstract postHandle(req: express.Request, res: express.Response, database: D, props: Props): Promise<void>;
|
|
11
|
-
abstract getProps(req: express.Request, res: express.Response, database: D, state: State): Promise<Props>;
|
|
12
|
-
constructor();
|
|
13
|
-
getHandler(controller: BaseController<D, State, Props>): (req: express.Request, res: express.Response) => Promise<express.Response<any, Record<string, any>>>;
|
|
14
|
-
}
|
package/dist/BaseMiddleware.js
DELETED
|
@@ -1,108 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
-
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
-
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
-
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
-
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
-
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
-
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
-
});
|
|
10
|
-
};
|
|
11
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
12
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
13
|
-
};
|
|
14
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
-
exports.BaseMiddleware = void 0;
|
|
16
|
-
const Meta_1 = require("./Meta");
|
|
17
|
-
const joi_1 = __importDefault(require("joi"));
|
|
18
|
-
const namirasoft_core_1 = require("namirasoft-core");
|
|
19
|
-
class BaseMiddleware {
|
|
20
|
-
constructor() {
|
|
21
|
-
this.logger = this.getLogger();
|
|
22
|
-
}
|
|
23
|
-
getHandler(controller) {
|
|
24
|
-
return (req, res) => __awaiter(this, void 0, void 0, function* () {
|
|
25
|
-
// meta
|
|
26
|
-
let meta = new Meta_1.Meta(req);
|
|
27
|
-
// result
|
|
28
|
-
let result = {};
|
|
29
|
-
try {
|
|
30
|
-
// meta
|
|
31
|
-
meta.onStart();
|
|
32
|
-
if (controller.showLogAtTheBeginning)
|
|
33
|
-
this.logger.info(JSON.stringify(meta));
|
|
34
|
-
// init controller
|
|
35
|
-
let database = yield this.getDatabase();
|
|
36
|
-
let state = controller.getState();
|
|
37
|
-
let props = yield this.getProps(req, res, database, state);
|
|
38
|
-
// preHandle
|
|
39
|
-
yield this.preHandle(req, res, database, props);
|
|
40
|
-
yield controller.preHandle(req, res, database, props);
|
|
41
|
-
// check for anomaly
|
|
42
|
-
let anomaly = controller.getAnomaly();
|
|
43
|
-
if (anomaly != null)
|
|
44
|
-
if (anomaly.isAnomaly(meta.ip, meta.url))
|
|
45
|
-
namirasoft_core_1.ErrorOperation.throwHTTP(403, 'Suspicious activity detected.');
|
|
46
|
-
// check body validation
|
|
47
|
-
let bodySchema = controller.getBodySchema();
|
|
48
|
-
if (bodySchema != null) {
|
|
49
|
-
const validation = yield joi_1.default.compile(bodySchema)
|
|
50
|
-
.prefs({ errors: { label: 'key' } })
|
|
51
|
-
.validate(req.body);
|
|
52
|
-
if (validation.error) {
|
|
53
|
-
let message = validation.error.details.map((details) => details.message).join(', ');
|
|
54
|
-
namirasoft_core_1.ErrorOperation.throwHTTP(400, message);
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
// check query validation
|
|
58
|
-
let querySchema = controller.getQuerySchema();
|
|
59
|
-
if (querySchema != null) {
|
|
60
|
-
const validation = yield joi_1.default.compile(querySchema)
|
|
61
|
-
.prefs({ errors: { label: 'key' } })
|
|
62
|
-
.validate(req.query);
|
|
63
|
-
if (validation.error) {
|
|
64
|
-
let message = validation.error.details.map((details) => details.message).join(', ');
|
|
65
|
-
namirasoft_core_1.ErrorOperation.throwHTTP(400, message);
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
// call controller
|
|
69
|
-
if (controller.handle)
|
|
70
|
-
result = yield controller.handle(req, res, database, props);
|
|
71
|
-
if (result == null)
|
|
72
|
-
result = "Success";
|
|
73
|
-
// postHandle
|
|
74
|
-
yield controller.postHandle(req, res, database, props);
|
|
75
|
-
yield this.postHandle(req, res, database, props);
|
|
76
|
-
}
|
|
77
|
-
catch (error) {
|
|
78
|
-
let message;
|
|
79
|
-
if (error instanceof Error) {
|
|
80
|
-
meta.error = error;
|
|
81
|
-
message = error.message;
|
|
82
|
-
}
|
|
83
|
-
else
|
|
84
|
-
message = error + "";
|
|
85
|
-
if (error instanceof namirasoft_core_1.HTTPError) {
|
|
86
|
-
meta.code = error.code;
|
|
87
|
-
this.logger.error(error.message + "\n" + JSON.stringify(meta), undefined, error.stack);
|
|
88
|
-
}
|
|
89
|
-
else {
|
|
90
|
-
meta.code = 500;
|
|
91
|
-
if (error instanceof Error)
|
|
92
|
-
this.logger.critical(error.message + "\n" + JSON.stringify(meta), undefined, error.stack);
|
|
93
|
-
}
|
|
94
|
-
meta.message = message;
|
|
95
|
-
if (error instanceof namirasoft_core_1.HTTPError)
|
|
96
|
-
result = meta.message;
|
|
97
|
-
else
|
|
98
|
-
result = "Sorry, internl server error.";
|
|
99
|
-
}
|
|
100
|
-
meta.onFinish();
|
|
101
|
-
if (controller.showLogAtTheEnd)
|
|
102
|
-
this.logger.info(JSON.stringify(meta));
|
|
103
|
-
return res.status(meta.code).send(result);
|
|
104
|
-
});
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
exports.BaseMiddleware = BaseMiddleware;
|
|
108
|
-
//# sourceMappingURL=BaseMiddleware.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"BaseMiddleware.js","sourceRoot":"","sources":["../src/BaseMiddleware.ts"],"names":[],"mappings":"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"}
|
package/src/BaseMiddleware.ts
DELETED
|
@@ -1,121 +0,0 @@
|
|
|
1
|
-
import * as express from 'express';
|
|
2
|
-
import { BaseDatabase } from './BaseDatabase';
|
|
3
|
-
import { Meta } from './Meta';
|
|
4
|
-
import Joi from 'joi';
|
|
5
|
-
import { AnomalyDetector } from './AnomalyDetector';
|
|
6
|
-
import { BaseController } from './BaseController';
|
|
7
|
-
import { ErrorOperation, HTTPError } from 'namirasoft-core';
|
|
8
|
-
import { ILogger } from "namirasoft-log";
|
|
9
|
-
|
|
10
|
-
export abstract class BaseMiddleware<D extends BaseDatabase, State, Props>
|
|
11
|
-
{
|
|
12
|
-
protected logger: ILogger;
|
|
13
|
-
abstract getDatabase(): Promise<D>;
|
|
14
|
-
abstract getLogger(): ILogger;
|
|
15
|
-
abstract preHandle(req: express.Request, res: express.Response, database: D, props: Props): Promise<void>;
|
|
16
|
-
abstract postHandle(req: express.Request, res: express.Response, database: D, props: Props): Promise<void>;
|
|
17
|
-
abstract getProps(req: express.Request, res: express.Response, database: D, state: State): Promise<Props>;
|
|
18
|
-
constructor()
|
|
19
|
-
{
|
|
20
|
-
this.logger = this.getLogger();
|
|
21
|
-
}
|
|
22
|
-
getHandler(controller: BaseController<D, State, Props>)
|
|
23
|
-
{
|
|
24
|
-
return async (req: express.Request, res: express.Response) =>
|
|
25
|
-
{
|
|
26
|
-
// meta
|
|
27
|
-
let meta = new Meta(req);
|
|
28
|
-
// result
|
|
29
|
-
let result = {};
|
|
30
|
-
try
|
|
31
|
-
{
|
|
32
|
-
// meta
|
|
33
|
-
meta.onStart();
|
|
34
|
-
if (controller.showLogAtTheBeginning)
|
|
35
|
-
this.logger.info(JSON.stringify(meta));
|
|
36
|
-
// init controller
|
|
37
|
-
let database = await this.getDatabase();
|
|
38
|
-
let state = controller.getState();
|
|
39
|
-
let props = await this.getProps(req, res, database, state);
|
|
40
|
-
|
|
41
|
-
// preHandle
|
|
42
|
-
await this.preHandle(req, res, database, props);
|
|
43
|
-
await controller.preHandle(req, res, database, props);
|
|
44
|
-
|
|
45
|
-
// check for anomaly
|
|
46
|
-
let anomaly: AnomalyDetector | null = controller.getAnomaly();
|
|
47
|
-
if (anomaly != null)
|
|
48
|
-
if (anomaly.isAnomaly(meta.ip, meta.url))
|
|
49
|
-
ErrorOperation.throwHTTP(403, 'Suspicious activity detected.');
|
|
50
|
-
|
|
51
|
-
// check body validation
|
|
52
|
-
let bodySchema = controller.getBodySchema();
|
|
53
|
-
if (bodySchema != null)
|
|
54
|
-
{
|
|
55
|
-
const validation = await Joi.compile(bodySchema)
|
|
56
|
-
.prefs({ errors: { label: 'key' } })
|
|
57
|
-
.validate(req.body);
|
|
58
|
-
if (validation.error)
|
|
59
|
-
{
|
|
60
|
-
let message = validation.error.details.map((details) => details.message).join(', ');
|
|
61
|
-
ErrorOperation.throwHTTP(400, message);
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
// check query validation
|
|
65
|
-
let querySchema = controller.getQuerySchema();
|
|
66
|
-
if (querySchema != null)
|
|
67
|
-
{
|
|
68
|
-
const validation = await Joi.compile(querySchema)
|
|
69
|
-
.prefs({ errors: { label: 'key' } })
|
|
70
|
-
.validate(req.query);
|
|
71
|
-
if (validation.error)
|
|
72
|
-
{
|
|
73
|
-
let message = validation.error.details.map((details) => details.message).join(', ');
|
|
74
|
-
ErrorOperation.throwHTTP(400, message);
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
// call controller
|
|
79
|
-
if (controller.handle)
|
|
80
|
-
result = await controller.handle(req, res, database, props);
|
|
81
|
-
if (result == null)
|
|
82
|
-
result = "Success";
|
|
83
|
-
|
|
84
|
-
// postHandle
|
|
85
|
-
await controller.postHandle(req, res, database, props);
|
|
86
|
-
await this.postHandle(req, res, database, props);
|
|
87
|
-
} catch (error)
|
|
88
|
-
{
|
|
89
|
-
let message: string;
|
|
90
|
-
if (error instanceof Error)
|
|
91
|
-
{
|
|
92
|
-
meta.error = error;
|
|
93
|
-
message = error.message;
|
|
94
|
-
}
|
|
95
|
-
else
|
|
96
|
-
message = error + "";
|
|
97
|
-
|
|
98
|
-
if (error instanceof HTTPError)
|
|
99
|
-
{
|
|
100
|
-
meta.code = error.code;
|
|
101
|
-
this.logger.error(error.message + "\n" + JSON.stringify(meta), undefined, error.stack);
|
|
102
|
-
}
|
|
103
|
-
else
|
|
104
|
-
{
|
|
105
|
-
meta.code = 500;
|
|
106
|
-
if (error instanceof Error)
|
|
107
|
-
this.logger.critical(error.message + "\n" + JSON.stringify(meta), undefined, error.stack);
|
|
108
|
-
}
|
|
109
|
-
meta.message = message;
|
|
110
|
-
if (error instanceof HTTPError)
|
|
111
|
-
result = meta.message;
|
|
112
|
-
else
|
|
113
|
-
result = "Sorry, internl server error.";
|
|
114
|
-
}
|
|
115
|
-
meta.onFinish();
|
|
116
|
-
if (controller.showLogAtTheEnd)
|
|
117
|
-
this.logger.info(JSON.stringify(meta));
|
|
118
|
-
return res.status(meta.code).send(result);
|
|
119
|
-
};
|
|
120
|
-
}
|
|
121
|
-
}
|