namirasoft-node 1.4.2 → 1.4.4
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/BaseApplication.js +2 -1
- package/dist/BaseApplication.js.map +1 -1
- package/dist/BaseDatabase.d.ts +2 -1
- package/dist/BaseDatabase.js.map +1 -1
- package/dist/BaseTable.js +1 -1
- package/dist/BaseTable.js.map +1 -1
- package/dist/EmptyDatabase.d.ts +2 -1
- package/dist/EmptyDatabase.js +6 -1
- package/dist/EmptyDatabase.js.map +1 -1
- package/package.json +4 -4
- package/src/AnomalyDetector.ts +84 -84
- package/src/BaseApplication.ts +427 -426
- package/src/BaseApplicationLink.ts +6 -6
- package/src/BaseController.ts +193 -193
- package/src/BaseCron.ts +54 -54
- package/src/BaseDatabase.ts +193 -192
- package/src/BaseEmailService.ts +38 -38
- package/src/BaseTable.ts +104 -104
- package/src/CommandOperation.ts +32 -32
- package/src/EmptyDatabase.ts +8 -7
- package/src/GmailService.ts +22 -22
- package/src/IPOperation.ts +38 -38
- package/src/Meta.ts +40 -40
- package/src/OTPOperation.ts +64 -64
- package/src/RequestHeaderService.ts +27 -27
- package/src/SMTPService.ts +26 -26
- package/src/ServerToServerOperation.ts +23 -23
- package/src/index.ts +16 -16
package/src/BaseTable.ts
CHANGED
|
@@ -1,105 +1,105 @@
|
|
|
1
|
-
import { ArraySchema, BaseTypeSchema, BaseVariableSchema, ObjectSchema } from "namirasoft-schema";
|
|
2
|
-
import { BaseDatabase } from "./BaseDatabase";
|
|
3
|
-
import { ErrorOperation } from "namirasoft-core";
|
|
4
|
-
|
|
5
|
-
export abstract class BaseTable<D extends BaseDatabase, ModelColumnOption>
|
|
6
|
-
{
|
|
7
|
-
database: D;
|
|
8
|
-
constructor(database: D)
|
|
9
|
-
{
|
|
10
|
-
this.database = database;
|
|
11
|
-
}
|
|
12
|
-
public abstract getName(): string;
|
|
13
|
-
protected addSecureColumns(columns: string[]): string[]
|
|
14
|
-
{
|
|
15
|
-
return columns;
|
|
16
|
-
}
|
|
17
|
-
protected addReadOnlyColumns(columns: string[]): string[]
|
|
18
|
-
{
|
|
19
|
-
return columns;
|
|
20
|
-
}
|
|
21
|
-
public getSecureColumns(): string[]
|
|
22
|
-
{
|
|
23
|
-
let columns: string[] = [];
|
|
24
|
-
return this.addSecureColumns(columns);
|
|
25
|
-
}
|
|
26
|
-
public getReadOnlyColumns(): string[]
|
|
27
|
-
{
|
|
28
|
-
let columns: string[] = [];
|
|
29
|
-
return this.addReadOnlyColumns(columns);
|
|
30
|
-
}
|
|
31
|
-
public secure(obj: any)
|
|
32
|
-
{
|
|
33
|
-
if (obj.dataValues)
|
|
34
|
-
obj = obj.dataValues;
|
|
35
|
-
let secureColumns: string[] = this.getSecureColumns();
|
|
36
|
-
secureColumns.forEach(col => delete obj[col]);
|
|
37
|
-
return obj;
|
|
38
|
-
}
|
|
39
|
-
public getArraySchema(require: boolean, name?: string): ArraySchema
|
|
40
|
-
{
|
|
41
|
-
let ans = this.getSchema(require, name);
|
|
42
|
-
return new ArraySchema(require, [ans]);
|
|
43
|
-
}
|
|
44
|
-
public getSchema(require: boolean, name?: string): ObjectSchema
|
|
45
|
-
{
|
|
46
|
-
let secureColumns: string[] = this.getSecureColumns();
|
|
47
|
-
let readOnlyColumns: string[] = this.getReadOnlyColumns();
|
|
48
|
-
let ans = new ObjectSchema(name ?? this.getName(), require, null);
|
|
49
|
-
this.forEachColumn((name, element) =>
|
|
50
|
-
{
|
|
51
|
-
if (!secureColumns.includes(name))
|
|
52
|
-
ans.addField(this.getVariableSchema(name, element, readOnlyColumns.includes(name)));
|
|
53
|
-
});
|
|
54
|
-
return ans;
|
|
55
|
-
}
|
|
56
|
-
public checkColumn(column: string)
|
|
57
|
-
{
|
|
58
|
-
let columns: string[] = [];
|
|
59
|
-
this.forEachColumn(name => columns.push(name));
|
|
60
|
-
if (!columns.includes(column))
|
|
61
|
-
ErrorOperation.throwHTTP(404, `Column '${column}' not found`);
|
|
62
|
-
}
|
|
63
|
-
public abstract forEachColumn(handler: (name: string, column: ModelColumnOption) => void): void;
|
|
64
|
-
private getVariableSchema(name: string, element: ModelColumnOption, read_only: boolean): BaseVariableSchema
|
|
65
|
-
{
|
|
66
|
-
let schema = this.getTypeSchema(element);
|
|
67
|
-
schema.read_only = read_only;
|
|
68
|
-
let es = this.getExamples();
|
|
69
|
-
schema.example = es[name] ?? "";
|
|
70
|
-
return new BaseVariableSchema(name, schema);
|
|
71
|
-
}
|
|
72
|
-
protected abstract getTypeSchema(element: ModelColumnOption): BaseTypeSchema;
|
|
73
|
-
protected getExamples(): { [name: string]: string }
|
|
74
|
-
{
|
|
75
|
-
return {};
|
|
76
|
-
}
|
|
77
|
-
public getSchemaNames(): string[]
|
|
78
|
-
{
|
|
79
|
-
return [];
|
|
80
|
-
}
|
|
81
|
-
public getSchemaByName(require: boolean, name?: string): ObjectSchema
|
|
82
|
-
{
|
|
83
|
-
let ans = this.getSchema(require, name);
|
|
84
|
-
if (name)
|
|
85
|
-
{
|
|
86
|
-
let names = this.getSchemaNames();
|
|
87
|
-
if (!names.includes(name))
|
|
88
|
-
throw new Error("Wrong schema name was provided: " + name);
|
|
89
|
-
this.setSchemaByName(ans);
|
|
90
|
-
}
|
|
91
|
-
return ans;
|
|
92
|
-
}
|
|
93
|
-
public getArraySchemaByName(require: boolean, name?: string): ArraySchema
|
|
94
|
-
{
|
|
95
|
-
let ans = this.getSchemaByName(require, name);
|
|
96
|
-
return new ArraySchema(require, [ans]);
|
|
97
|
-
}
|
|
98
|
-
protected setSchemaByName(_: ObjectSchema): void
|
|
99
|
-
{
|
|
100
|
-
}
|
|
101
|
-
public getNotFoundError(conditions: any | null)
|
|
102
|
-
{
|
|
103
|
-
return ErrorOperation.getHTTP(404, "Could not
|
|
104
|
-
}
|
|
1
|
+
import { ArraySchema, BaseTypeSchema, BaseVariableSchema, ObjectSchema } from "namirasoft-schema";
|
|
2
|
+
import { BaseDatabase } from "./BaseDatabase";
|
|
3
|
+
import { ErrorOperation } from "namirasoft-core";
|
|
4
|
+
|
|
5
|
+
export abstract class BaseTable<D extends BaseDatabase, ModelColumnOption>
|
|
6
|
+
{
|
|
7
|
+
database: D;
|
|
8
|
+
constructor(database: D)
|
|
9
|
+
{
|
|
10
|
+
this.database = database;
|
|
11
|
+
}
|
|
12
|
+
public abstract getName(): string;
|
|
13
|
+
protected addSecureColumns(columns: string[]): string[]
|
|
14
|
+
{
|
|
15
|
+
return columns;
|
|
16
|
+
}
|
|
17
|
+
protected addReadOnlyColumns(columns: string[]): string[]
|
|
18
|
+
{
|
|
19
|
+
return columns;
|
|
20
|
+
}
|
|
21
|
+
public getSecureColumns(): string[]
|
|
22
|
+
{
|
|
23
|
+
let columns: string[] = [];
|
|
24
|
+
return this.addSecureColumns(columns);
|
|
25
|
+
}
|
|
26
|
+
public getReadOnlyColumns(): string[]
|
|
27
|
+
{
|
|
28
|
+
let columns: string[] = [];
|
|
29
|
+
return this.addReadOnlyColumns(columns);
|
|
30
|
+
}
|
|
31
|
+
public secure(obj: any)
|
|
32
|
+
{
|
|
33
|
+
if (obj.dataValues)
|
|
34
|
+
obj = obj.dataValues;
|
|
35
|
+
let secureColumns: string[] = this.getSecureColumns();
|
|
36
|
+
secureColumns.forEach(col => delete obj[col]);
|
|
37
|
+
return obj;
|
|
38
|
+
}
|
|
39
|
+
public getArraySchema(require: boolean, name?: string): ArraySchema
|
|
40
|
+
{
|
|
41
|
+
let ans = this.getSchema(require, name);
|
|
42
|
+
return new ArraySchema(require, [ans]);
|
|
43
|
+
}
|
|
44
|
+
public getSchema(require: boolean, name?: string): ObjectSchema
|
|
45
|
+
{
|
|
46
|
+
let secureColumns: string[] = this.getSecureColumns();
|
|
47
|
+
let readOnlyColumns: string[] = this.getReadOnlyColumns();
|
|
48
|
+
let ans = new ObjectSchema(name ?? this.getName(), require, null);
|
|
49
|
+
this.forEachColumn((name, element) =>
|
|
50
|
+
{
|
|
51
|
+
if (!secureColumns.includes(name))
|
|
52
|
+
ans.addField(this.getVariableSchema(name, element, readOnlyColumns.includes(name)));
|
|
53
|
+
});
|
|
54
|
+
return ans;
|
|
55
|
+
}
|
|
56
|
+
public checkColumn(column: string)
|
|
57
|
+
{
|
|
58
|
+
let columns: string[] = [];
|
|
59
|
+
this.forEachColumn(name => columns.push(name));
|
|
60
|
+
if (!columns.includes(column))
|
|
61
|
+
ErrorOperation.throwHTTP(404, `Column '${column}' not found`);
|
|
62
|
+
}
|
|
63
|
+
public abstract forEachColumn(handler: (name: string, column: ModelColumnOption) => void): void;
|
|
64
|
+
private getVariableSchema(name: string, element: ModelColumnOption, read_only: boolean): BaseVariableSchema
|
|
65
|
+
{
|
|
66
|
+
let schema = this.getTypeSchema(element);
|
|
67
|
+
schema.read_only = read_only;
|
|
68
|
+
let es = this.getExamples();
|
|
69
|
+
schema.example = es[name] ?? "";
|
|
70
|
+
return new BaseVariableSchema(name, schema);
|
|
71
|
+
}
|
|
72
|
+
protected abstract getTypeSchema(element: ModelColumnOption): BaseTypeSchema;
|
|
73
|
+
protected getExamples(): { [name: string]: string }
|
|
74
|
+
{
|
|
75
|
+
return {};
|
|
76
|
+
}
|
|
77
|
+
public getSchemaNames(): string[]
|
|
78
|
+
{
|
|
79
|
+
return [];
|
|
80
|
+
}
|
|
81
|
+
public getSchemaByName(require: boolean, name?: string): ObjectSchema
|
|
82
|
+
{
|
|
83
|
+
let ans = this.getSchema(require, name);
|
|
84
|
+
if (name)
|
|
85
|
+
{
|
|
86
|
+
let names = this.getSchemaNames();
|
|
87
|
+
if (!names.includes(name))
|
|
88
|
+
throw new Error("Wrong schema name was provided: " + name);
|
|
89
|
+
this.setSchemaByName(ans);
|
|
90
|
+
}
|
|
91
|
+
return ans;
|
|
92
|
+
}
|
|
93
|
+
public getArraySchemaByName(require: boolean, name?: string): ArraySchema
|
|
94
|
+
{
|
|
95
|
+
let ans = this.getSchemaByName(require, name);
|
|
96
|
+
return new ArraySchema(require, [ans]);
|
|
97
|
+
}
|
|
98
|
+
protected setSchemaByName(_: ObjectSchema): void
|
|
99
|
+
{
|
|
100
|
+
}
|
|
101
|
+
public getNotFoundError(conditions: any | null)
|
|
102
|
+
{
|
|
103
|
+
return ErrorOperation.getHTTP(404, "Could not find " + this.getName() + " for " + JSON.stringify(conditions));
|
|
104
|
+
}
|
|
105
105
|
}
|
package/src/CommandOperation.ts
CHANGED
|
@@ -1,33 +1,33 @@
|
|
|
1
|
-
import { ExecException, exec, execSync } from 'child_process';
|
|
2
|
-
import { ConsoleOperation } from 'namirasoft-core';
|
|
3
|
-
export class CommandOperation
|
|
4
|
-
{
|
|
5
|
-
static exec(command: string, cwd: string | undefined)
|
|
6
|
-
{
|
|
7
|
-
exec(command, { cwd }, (error: ExecException | null, stdout: string, stderr: string) =>
|
|
8
|
-
{
|
|
9
|
-
if (error)
|
|
10
|
-
{
|
|
11
|
-
ConsoleOperation.error(`error: ${error.message}`);
|
|
12
|
-
return;
|
|
13
|
-
}
|
|
14
|
-
if (stderr)
|
|
15
|
-
{
|
|
16
|
-
ConsoleOperation.error(`stderr: ${stderr}`);
|
|
17
|
-
return;
|
|
18
|
-
}
|
|
19
|
-
ConsoleOperation.log(`stdout:\n${stdout}`);
|
|
20
|
-
});
|
|
21
|
-
}
|
|
22
|
-
static execSync(command: string, cwd: string | undefined)
|
|
23
|
-
{
|
|
24
|
-
try
|
|
25
|
-
{
|
|
26
|
-
return execSync(command, { cwd, encoding: 'utf-8' });
|
|
27
|
-
} catch (error: any)
|
|
28
|
-
{
|
|
29
|
-
ConsoleOperation.error(error.stdout);
|
|
30
|
-
throw error;
|
|
31
|
-
}
|
|
32
|
-
}
|
|
1
|
+
import { ExecException, exec, execSync } from 'child_process';
|
|
2
|
+
import { ConsoleOperation } from 'namirasoft-core';
|
|
3
|
+
export class CommandOperation
|
|
4
|
+
{
|
|
5
|
+
static exec(command: string, cwd: string | undefined)
|
|
6
|
+
{
|
|
7
|
+
exec(command, { cwd }, (error: ExecException | null, stdout: string, stderr: string) =>
|
|
8
|
+
{
|
|
9
|
+
if (error)
|
|
10
|
+
{
|
|
11
|
+
ConsoleOperation.error(`error: ${error.message}`);
|
|
12
|
+
return;
|
|
13
|
+
}
|
|
14
|
+
if (stderr)
|
|
15
|
+
{
|
|
16
|
+
ConsoleOperation.error(`stderr: ${stderr}`);
|
|
17
|
+
return;
|
|
18
|
+
}
|
|
19
|
+
ConsoleOperation.log(`stdout:\n${stdout}`);
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
static execSync(command: string, cwd: string | undefined)
|
|
23
|
+
{
|
|
24
|
+
try
|
|
25
|
+
{
|
|
26
|
+
return execSync(command, { cwd, encoding: 'utf-8' });
|
|
27
|
+
} catch (error: any)
|
|
28
|
+
{
|
|
29
|
+
ConsoleOperation.error(error.stdout);
|
|
30
|
+
throw error;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
33
|
}
|
package/src/EmptyDatabase.ts
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
import { BaseDatabase } from "./BaseDatabase";
|
|
2
|
-
|
|
3
|
-
export class EmptyDatabase extends BaseDatabase
|
|
4
|
-
{
|
|
5
|
-
override init() { }
|
|
6
|
-
override connect() { }
|
|
7
|
-
override async sync(_: boolean) { }
|
|
1
|
+
import { BaseDatabase } from "./BaseDatabase";
|
|
2
|
+
|
|
3
|
+
export class EmptyDatabase extends BaseDatabase
|
|
4
|
+
{
|
|
5
|
+
override async init() { }
|
|
6
|
+
override connect() { }
|
|
7
|
+
override async sync(_: boolean) { }
|
|
8
|
+
override async fill() { }
|
|
8
9
|
}
|
package/src/GmailService.ts
CHANGED
|
@@ -1,23 +1,23 @@
|
|
|
1
|
-
import smtpTransport from 'nodemailer-smtp-transport';
|
|
2
|
-
import { BaseEmailService } from './BaseEmailService';
|
|
3
|
-
|
|
4
|
-
export class GmailService extends BaseEmailService
|
|
5
|
-
{
|
|
6
|
-
password: string;
|
|
7
|
-
constructor(username: string, password: string)
|
|
8
|
-
{
|
|
9
|
-
super(username);
|
|
10
|
-
this.password = password;
|
|
11
|
-
}
|
|
12
|
-
protected override getTransform(): any
|
|
13
|
-
{
|
|
14
|
-
return smtpTransport({
|
|
15
|
-
service: 'gmail',
|
|
16
|
-
host: 'smtp.gmail.com',
|
|
17
|
-
auth: {
|
|
18
|
-
user: this.username,
|
|
19
|
-
pass: this.password
|
|
20
|
-
}
|
|
21
|
-
});
|
|
22
|
-
}
|
|
1
|
+
import smtpTransport from 'nodemailer-smtp-transport';
|
|
2
|
+
import { BaseEmailService } from './BaseEmailService';
|
|
3
|
+
|
|
4
|
+
export class GmailService extends BaseEmailService
|
|
5
|
+
{
|
|
6
|
+
password: string;
|
|
7
|
+
constructor(username: string, password: string)
|
|
8
|
+
{
|
|
9
|
+
super(username);
|
|
10
|
+
this.password = password;
|
|
11
|
+
}
|
|
12
|
+
protected override getTransform(): any
|
|
13
|
+
{
|
|
14
|
+
return smtpTransport({
|
|
15
|
+
service: 'gmail',
|
|
16
|
+
host: 'smtp.gmail.com',
|
|
17
|
+
auth: {
|
|
18
|
+
user: this.username,
|
|
19
|
+
pass: this.password
|
|
20
|
+
}
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
23
|
}
|
package/src/IPOperation.ts
CHANGED
|
@@ -1,39 +1,39 @@
|
|
|
1
|
-
import * as express from 'express';
|
|
2
|
-
import { getClientIp } from '@supercharge/request-ip';
|
|
3
|
-
import { RequestHeaderService } from './RequestHeaderService';
|
|
4
|
-
import { ErrorOperation } from 'namirasoft-core';
|
|
5
|
-
|
|
6
|
-
export class IPOperation
|
|
7
|
-
{
|
|
8
|
-
static ERROR_MESSAGE_IP_IS_NOT_WHITELIST = `Ip does not match the whitelisted IP address: {0}`;
|
|
9
|
-
static getIP(req: express.Request): string
|
|
10
|
-
{
|
|
11
|
-
let ip = new RequestHeaderService(req, 'cf-connecting-ip').getString();
|
|
12
|
-
if (!ip)
|
|
13
|
-
ip = new RequestHeaderService(req, 'x-forwarded-for').getString();
|
|
14
|
-
if (!ip)
|
|
15
|
-
ip = getClientIp(req) ?? "";
|
|
16
|
-
ip = ip.split(',')[0];
|
|
17
|
-
return ip;
|
|
18
|
-
}
|
|
19
|
-
static isWhitelist(req: express.Request, whitelist: string[])
|
|
20
|
-
{
|
|
21
|
-
let ip = this.getIP(req);
|
|
22
|
-
if (!whitelist)
|
|
23
|
-
return true;
|
|
24
|
-
if (whitelist.length === 0)
|
|
25
|
-
return true;
|
|
26
|
-
if (whitelist.includes(ip))
|
|
27
|
-
return true;
|
|
28
|
-
for (let item of whitelist)
|
|
29
|
-
if (ip.substring(0, item.length) === item)
|
|
30
|
-
return true;
|
|
31
|
-
return false;
|
|
32
|
-
}
|
|
33
|
-
static checkWhitelist(req: express.Request, whitelist: string[])
|
|
34
|
-
{
|
|
35
|
-
let valid = this.isWhitelist(req, whitelist);
|
|
36
|
-
if (!valid)
|
|
37
|
-
ErrorOperation.throwHTTP(403, this.ERROR_MESSAGE_IP_IS_NOT_WHITELIST, this.getIP(req));
|
|
38
|
-
}
|
|
1
|
+
import * as express from 'express';
|
|
2
|
+
import { getClientIp } from '@supercharge/request-ip';
|
|
3
|
+
import { RequestHeaderService } from './RequestHeaderService';
|
|
4
|
+
import { ErrorOperation } from 'namirasoft-core';
|
|
5
|
+
|
|
6
|
+
export class IPOperation
|
|
7
|
+
{
|
|
8
|
+
static ERROR_MESSAGE_IP_IS_NOT_WHITELIST = `Ip does not match the whitelisted IP address: {0}`;
|
|
9
|
+
static getIP(req: express.Request): string
|
|
10
|
+
{
|
|
11
|
+
let ip = new RequestHeaderService(req, 'cf-connecting-ip').getString();
|
|
12
|
+
if (!ip)
|
|
13
|
+
ip = new RequestHeaderService(req, 'x-forwarded-for').getString();
|
|
14
|
+
if (!ip)
|
|
15
|
+
ip = getClientIp(req) ?? "";
|
|
16
|
+
ip = ip.split(',')[0];
|
|
17
|
+
return ip;
|
|
18
|
+
}
|
|
19
|
+
static isWhitelist(req: express.Request, whitelist: string[])
|
|
20
|
+
{
|
|
21
|
+
let ip = this.getIP(req);
|
|
22
|
+
if (!whitelist)
|
|
23
|
+
return true;
|
|
24
|
+
if (whitelist.length === 0)
|
|
25
|
+
return true;
|
|
26
|
+
if (whitelist.includes(ip))
|
|
27
|
+
return true;
|
|
28
|
+
for (let item of whitelist)
|
|
29
|
+
if (ip.substring(0, item.length) === item)
|
|
30
|
+
return true;
|
|
31
|
+
return false;
|
|
32
|
+
}
|
|
33
|
+
static checkWhitelist(req: express.Request, whitelist: string[])
|
|
34
|
+
{
|
|
35
|
+
let valid = this.isWhitelist(req, whitelist);
|
|
36
|
+
if (!valid)
|
|
37
|
+
ErrorOperation.throwHTTP(403, this.ERROR_MESSAGE_IP_IS_NOT_WHITELIST, this.getIP(req));
|
|
38
|
+
}
|
|
39
39
|
}
|
package/src/Meta.ts
CHANGED
|
@@ -1,41 +1,41 @@
|
|
|
1
|
-
import * as express from 'express';
|
|
2
|
-
import { IncomingHttpHeaders } from "http";
|
|
3
|
-
import { IPOperation } from './IPOperation';
|
|
4
|
-
import { HTTPMethod } from 'namirasoft-core';
|
|
5
|
-
|
|
6
|
-
export class Meta
|
|
7
|
-
{
|
|
8
|
-
info: { name: string, tag: string, method: HTTPMethod, path: string, summary: string };
|
|
9
|
-
ip: string;
|
|
10
|
-
method: string;
|
|
11
|
-
url: string;
|
|
12
|
-
headers?: IncomingHttpHeaders;
|
|
13
|
-
body?: any;
|
|
14
|
-
start_time: Date | null = null;
|
|
15
|
-
end_time: Date | null = null;
|
|
16
|
-
duration: number | null = null;
|
|
17
|
-
code: number = 200;
|
|
18
|
-
message: string = "Success";
|
|
19
|
-
error: Error | null = null;
|
|
20
|
-
constructor(info: { name: string, tag: string, method: HTTPMethod, path: string, summary: string }, req: express.Request, sensitive: boolean)
|
|
21
|
-
{
|
|
22
|
-
this.info = info;
|
|
23
|
-
this.ip = IPOperation.getIP(req);
|
|
24
|
-
this.method = req.method;
|
|
25
|
-
this.url = req.originalUrl;
|
|
26
|
-
if (!sensitive)
|
|
27
|
-
{
|
|
28
|
-
this.headers = req.headers;
|
|
29
|
-
this.body = req.body;
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
onStart()
|
|
33
|
-
{
|
|
34
|
-
this.start_time = new Date();
|
|
35
|
-
}
|
|
36
|
-
onFinish()
|
|
37
|
-
{
|
|
38
|
-
this.end_time = new Date();
|
|
39
|
-
this.duration = (this.end_time?.getTime() ?? 0) - (this.start_time?.getTime() ?? 0);
|
|
40
|
-
}
|
|
1
|
+
import * as express from 'express';
|
|
2
|
+
import { IncomingHttpHeaders } from "http";
|
|
3
|
+
import { IPOperation } from './IPOperation';
|
|
4
|
+
import { HTTPMethod } from 'namirasoft-core';
|
|
5
|
+
|
|
6
|
+
export class Meta
|
|
7
|
+
{
|
|
8
|
+
info: { name: string, tag: string, method: HTTPMethod, path: string, summary: string };
|
|
9
|
+
ip: string;
|
|
10
|
+
method: string;
|
|
11
|
+
url: string;
|
|
12
|
+
headers?: IncomingHttpHeaders;
|
|
13
|
+
body?: any;
|
|
14
|
+
start_time: Date | null = null;
|
|
15
|
+
end_time: Date | null = null;
|
|
16
|
+
duration: number | null = null;
|
|
17
|
+
code: number = 200;
|
|
18
|
+
message: string = "Success";
|
|
19
|
+
error: Error | null = null;
|
|
20
|
+
constructor(info: { name: string, tag: string, method: HTTPMethod, path: string, summary: string }, req: express.Request, sensitive: boolean)
|
|
21
|
+
{
|
|
22
|
+
this.info = info;
|
|
23
|
+
this.ip = IPOperation.getIP(req);
|
|
24
|
+
this.method = req.method;
|
|
25
|
+
this.url = req.originalUrl;
|
|
26
|
+
if (!sensitive)
|
|
27
|
+
{
|
|
28
|
+
this.headers = req.headers;
|
|
29
|
+
this.body = req.body;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
onStart()
|
|
33
|
+
{
|
|
34
|
+
this.start_time = new Date();
|
|
35
|
+
}
|
|
36
|
+
onFinish()
|
|
37
|
+
{
|
|
38
|
+
this.end_time = new Date();
|
|
39
|
+
this.duration = (this.end_time?.getTime() ?? 0) - (this.start_time?.getTime() ?? 0);
|
|
40
|
+
}
|
|
41
41
|
}
|
package/src/OTPOperation.ts
CHANGED
|
@@ -1,65 +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>, min_wait_time: number, max_wait_time: number, min_try_count: number, user_tried_time: Date, user_tried_count: number, increase_power_base: number = 2)
|
|
28
|
-
{
|
|
29
|
-
// check wait time
|
|
30
|
-
let wait_time = this.getWaitTime(min_wait_time, max_wait_time, min_try_count, user_tried_count, increase_power_base);
|
|
31
|
-
let wait_date = TimeOperation.minutesAgo(wait_time, new Date());
|
|
32
|
-
let next_time = TimeOperation.diffInSecond(user_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_try_count, user_tried_count + 1, increase_power_base);
|
|
42
|
-
next_time = wait_time * 60;
|
|
43
|
-
return { next_time };
|
|
44
|
-
}
|
|
45
|
-
static async onSafeVerify(handler: () => Promise<void>, errorHandler: () => Promise<void>,
|
|
46
|
-
valid_otp: string, valid_otp_time: Date, otp_expire_time: number, max_try_count: number,
|
|
47
|
-
entered_otp: string, user_tried_count: number)
|
|
48
|
-
{
|
|
49
|
-
if (!entered_otp)
|
|
50
|
-
ErrorOperation.throwHTTP(403, "The OTP not generated yet.");
|
|
51
|
-
|
|
52
|
-
if (valid_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 (valid_otp !== entered_otp)
|
|
59
|
-
{
|
|
60
|
-
await errorHandler();
|
|
61
|
-
ErrorOperation.throwHTTP(403, "Wrong code.");
|
|
62
|
-
}
|
|
63
|
-
await handler();
|
|
64
|
-
}
|
|
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>, min_wait_time: number, max_wait_time: number, min_try_count: number, user_tried_time: Date, user_tried_count: number, increase_power_base: number = 2)
|
|
28
|
+
{
|
|
29
|
+
// check wait time
|
|
30
|
+
let wait_time = this.getWaitTime(min_wait_time, max_wait_time, min_try_count, user_tried_count, increase_power_base);
|
|
31
|
+
let wait_date = TimeOperation.minutesAgo(wait_time, new Date());
|
|
32
|
+
let next_time = TimeOperation.diffInSecond(user_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_try_count, user_tried_count + 1, increase_power_base);
|
|
42
|
+
next_time = wait_time * 60;
|
|
43
|
+
return { next_time };
|
|
44
|
+
}
|
|
45
|
+
static async onSafeVerify(handler: () => Promise<void>, errorHandler: () => Promise<void>,
|
|
46
|
+
valid_otp: string, valid_otp_time: Date, otp_expire_time: number, max_try_count: number,
|
|
47
|
+
entered_otp: string, user_tried_count: number)
|
|
48
|
+
{
|
|
49
|
+
if (!entered_otp)
|
|
50
|
+
ErrorOperation.throwHTTP(403, "The OTP not generated yet.");
|
|
51
|
+
|
|
52
|
+
if (valid_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 (valid_otp !== entered_otp)
|
|
59
|
+
{
|
|
60
|
+
await errorHandler();
|
|
61
|
+
ErrorOperation.throwHTTP(403, "Wrong code.");
|
|
62
|
+
}
|
|
63
|
+
await handler();
|
|
64
|
+
}
|
|
65
65
|
}
|