namirasoft-node 1.0.0
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/AnomalyDetector.d.ts +26 -0
- package/dist/AnomalyDetector.js +74 -0
- package/dist/AnomalyDetector.js.map +1 -0
- package/dist/BaseApplication.d.ts +22 -0
- package/dist/BaseApplication.js +104 -0
- package/dist/BaseApplication.js.map +1 -0
- package/dist/BaseController.d.ts +15 -0
- package/dist/BaseController.js +11 -0
- package/dist/BaseController.js.map +1 -0
- package/dist/BaseDatabase.d.ts +4 -0
- package/dist/BaseDatabase.js +7 -0
- package/dist/BaseDatabase.js.map +1 -0
- package/dist/BaseMiddleware.d.ts +14 -0
- package/dist/BaseMiddleware.js +108 -0
- package/dist/BaseMiddleware.js.map +1 -0
- package/dist/BaseMySqlDatabase.d.ts +4 -0
- package/dist/BaseMySqlDatabase.js +11 -0
- package/dist/BaseMySqlDatabase.js.map +1 -0
- package/dist/BaseSequelizeDatabase.d.ts +15 -0
- package/dist/BaseSequelizeDatabase.js +120 -0
- package/dist/BaseSequelizeDatabase.js.map +1 -0
- package/dist/BaseSequelizeModel.d.ts +3 -0
- package/dist/BaseSequelizeModel.js +8 -0
- package/dist/BaseSequelizeModel.js.map +1 -0
- package/dist/BaseSequelizeTable.d.ts +8 -0
- package/dist/BaseSequelizeTable.js +11 -0
- package/dist/BaseSequelizeTable.js.map +1 -0
- package/dist/BaseTable.d.ts +5 -0
- package/dist/BaseTable.js +10 -0
- package/dist/BaseTable.js.map +1 -0
- package/dist/EmailService.d.ts +16 -0
- package/dist/EmailService.js +81 -0
- package/dist/EmailService.js.map +1 -0
- package/dist/EnvService.d.ts +6 -0
- package/dist/EnvService.js +18 -0
- package/dist/EnvService.js.map +1 -0
- package/dist/IPOperation.d.ts +7 -0
- package/dist/IPOperation.js +39 -0
- package/dist/IPOperation.js.map +1 -0
- package/dist/Meta.d.ts +19 -0
- package/dist/Meta.js +29 -0
- package/dist/Meta.js.map +1 -0
- package/dist/RequestHeaderService.d.ts +8 -0
- package/dist/RequestHeaderService.js +17 -0
- package/dist/RequestHeaderService.js.map +1 -0
- package/dist/ServerToServerOperation.d.ts +5 -0
- package/dist/ServerToServerOperation.js +24 -0
- package/dist/ServerToServerOperation.js.map +1 -0
- package/dist/index.d.ts +15 -0
- package/dist/index.js +32 -0
- package/dist/index.js.map +1 -0
- package/package.json +33 -0
- package/src/AnomalyDetector.ts +85 -0
- package/src/BaseApplication.ts +112 -0
- package/src/BaseController.ts +16 -0
- package/src/BaseDatabase.ts +5 -0
- package/src/BaseMiddleware.ts +121 -0
- package/src/BaseMySqlDatabase.ts +8 -0
- package/src/BaseSequelizeDatabase.ts +132 -0
- package/src/BaseSequelizeModel.ts +7 -0
- package/src/BaseSequelizeTable.ts +13 -0
- package/src/BaseTable.ts +10 -0
- package/src/EmailService.ts +97 -0
- package/src/EnvService.ts +18 -0
- package/src/IPOperation.ts +39 -0
- package/src/Meta.ts +35 -0
- package/src/RequestHeaderService.ts +19 -0
- package/src/ServerToServerOperation.ts +24 -0
- package/src/index.ts +15 -0
- package/tsconfig.json +30 -0
|
@@ -0,0 +1,121 @@
|
|
|
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
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { BaseSequelizeDatabase } from "./BaseSequelizeDatabase";
|
|
2
|
+
export abstract class BaseMySqlDatabase extends BaseSequelizeDatabase
|
|
3
|
+
{
|
|
4
|
+
constructor(name: string, user: string, pass: string, host: string, port: number, logging: boolean = false)
|
|
5
|
+
{
|
|
6
|
+
super('mysql', name, user, pass, host, port, logging);
|
|
7
|
+
}
|
|
8
|
+
}
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
import { Sequelize, Dialect, Op } from "sequelize";
|
|
2
|
+
import { Model, ModelCtor, FindOptions, Transaction, ModelAttributes, Attributes, ModelOptions } from 'sequelize';
|
|
3
|
+
import { BaseDatabase } from "./BaseDatabase";
|
|
4
|
+
import { BaseSequelizeModel } from "./BaseSequelizeModel";
|
|
5
|
+
import { ErrorOperation } from "namirasoft-core";
|
|
6
|
+
import { Where } from "sequelize/types/utils";
|
|
7
|
+
|
|
8
|
+
export abstract class BaseSequelizeDatabase extends BaseDatabase
|
|
9
|
+
{
|
|
10
|
+
protected sequelize: Sequelize;
|
|
11
|
+
constructor(dialect: Dialect, name: string, user: string, pass: string, host: string, port: number, logging: boolean = false)
|
|
12
|
+
{
|
|
13
|
+
super();
|
|
14
|
+
this.sequelize = new Sequelize(
|
|
15
|
+
name,
|
|
16
|
+
user,
|
|
17
|
+
pass,
|
|
18
|
+
{
|
|
19
|
+
dialect,
|
|
20
|
+
host,
|
|
21
|
+
port,
|
|
22
|
+
logging
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
define<M extends Model, TAttributes = Attributes<M>>(
|
|
26
|
+
modelName: string,
|
|
27
|
+
attributes: ModelAttributes<M, TAttributes>,
|
|
28
|
+
options?: ModelOptions<M>
|
|
29
|
+
): ModelCtor<M>
|
|
30
|
+
{
|
|
31
|
+
if (!options)
|
|
32
|
+
options = {};
|
|
33
|
+
if (options.name == undefined)
|
|
34
|
+
options.name = {
|
|
35
|
+
plural: modelName,
|
|
36
|
+
singular: modelName
|
|
37
|
+
};
|
|
38
|
+
if (options.paranoid == undefined)
|
|
39
|
+
options.paranoid = true;
|
|
40
|
+
if (options.freezeTableName == undefined)
|
|
41
|
+
options.freezeTableName = true;
|
|
42
|
+
if (options.tableName == undefined)
|
|
43
|
+
options.tableName = modelName;
|
|
44
|
+
if (options.underscored == undefined)
|
|
45
|
+
options.underscored = true;
|
|
46
|
+
if (options.timestamps == undefined)
|
|
47
|
+
options.timestamps = true;
|
|
48
|
+
if (options.paranoid == undefined)
|
|
49
|
+
options.paranoid = true;
|
|
50
|
+
if (options.createdAt == undefined)
|
|
51
|
+
options.createdAt = true;
|
|
52
|
+
if (options.updatedAt == undefined)
|
|
53
|
+
options.updatedAt = true;
|
|
54
|
+
|
|
55
|
+
return this.sequelize.define(modelName, attributes, options);
|
|
56
|
+
}
|
|
57
|
+
async startTransaction<T>(handler: (trx: Transaction) => Promise<T>, trx: Transaction | null): Promise<T>
|
|
58
|
+
{
|
|
59
|
+
if (trx)
|
|
60
|
+
return await handler(trx);
|
|
61
|
+
trx = await this.sequelize.transaction();
|
|
62
|
+
try
|
|
63
|
+
{
|
|
64
|
+
let result = await handler(trx);
|
|
65
|
+
await trx.commit();
|
|
66
|
+
return result;
|
|
67
|
+
}
|
|
68
|
+
catch (error)
|
|
69
|
+
{
|
|
70
|
+
await trx.rollback();
|
|
71
|
+
throw error;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
async getModel<M extends BaseSequelizeModel>(modelName: string, options: FindOptions<Attributes<M>>, trx: Transaction | null): Promise<M>
|
|
75
|
+
{
|
|
76
|
+
let value = await this.getModelOrNull(modelName, options, trx);
|
|
77
|
+
if (value != null)
|
|
78
|
+
return value;
|
|
79
|
+
throw ErrorOperation.getHTTP(404, "Could not found " + modelName);
|
|
80
|
+
}
|
|
81
|
+
async getModelOrNull<M extends BaseSequelizeModel>(modelName: string, options: FindOptions<Attributes<M>>, trx: Transaction | null): Promise<M | null>
|
|
82
|
+
{
|
|
83
|
+
if (!options)
|
|
84
|
+
options = {};
|
|
85
|
+
options.transaction = trx;
|
|
86
|
+
let model = this.sequelize.models[modelName] as ModelCtor<M>;
|
|
87
|
+
return await model.findOne<M>(options);
|
|
88
|
+
}
|
|
89
|
+
getGoogleSearchConditions(columns: string[], search: string, conditions: Where[])
|
|
90
|
+
{
|
|
91
|
+
if (!conditions)
|
|
92
|
+
conditions = [];
|
|
93
|
+
if (search)
|
|
94
|
+
if (search.split)
|
|
95
|
+
{
|
|
96
|
+
let toks = search.split(' ');
|
|
97
|
+
if (toks.length > 0)
|
|
98
|
+
{
|
|
99
|
+
for (let i = 0; i < toks.length; i++)
|
|
100
|
+
{
|
|
101
|
+
let rOpr = { [Op.like]: '%' + toks[i].trim() + '%' };
|
|
102
|
+
let lOpr;
|
|
103
|
+
let cs = columns.map(column => Sequelize.col(column));
|
|
104
|
+
lOpr = Sequelize.fn(
|
|
105
|
+
"concat",
|
|
106
|
+
...cs
|
|
107
|
+
);
|
|
108
|
+
let condition = Sequelize.where(lOpr, rOpr);
|
|
109
|
+
conditions.push(condition);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
return conditions;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
paginate<T extends BaseSequelizeModel>(options: FindOptions<Attributes<T>>,
|
|
117
|
+
page_number: number, page_size: number, page_size_default?: number)
|
|
118
|
+
{
|
|
119
|
+
// page_number
|
|
120
|
+
if (isNaN(page_number))
|
|
121
|
+
page_number = 1;
|
|
122
|
+
// page_size
|
|
123
|
+
if (isNaN(page_size))
|
|
124
|
+
if (page_size_default)
|
|
125
|
+
page_size = page_size_default;
|
|
126
|
+
if (isNaN(page_size))
|
|
127
|
+
page_size = 20;
|
|
128
|
+
//
|
|
129
|
+
options.offset = (page_number - 1) * page_size;
|
|
130
|
+
options.limit = page_size;
|
|
131
|
+
}
|
|
132
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { ModelCtor } from "sequelize";
|
|
2
|
+
import { BaseSequelizeDatabase } from "./BaseSequelizeDatabase";
|
|
3
|
+
import { BaseSequelizeModel } from "./BaseSequelizeModel";
|
|
4
|
+
import { BaseTable } from "./BaseTable";
|
|
5
|
+
|
|
6
|
+
export class BaseSequelizeTable<D extends BaseSequelizeDatabase, M extends BaseSequelizeModel> extends BaseTable<D>
|
|
7
|
+
{
|
|
8
|
+
model!: ModelCtor<M>;
|
|
9
|
+
constructor(database: D)
|
|
10
|
+
{
|
|
11
|
+
super(database);
|
|
12
|
+
}
|
|
13
|
+
}
|
package/src/BaseTable.ts
ADDED
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import nodemailer from 'nodemailer';
|
|
2
|
+
import smtpTransport from 'nodemailer-smtp-transport';
|
|
3
|
+
import Mail, { AttachmentLike } from "nodemailer/lib/mailer";
|
|
4
|
+
import { Readable } from "stream";
|
|
5
|
+
|
|
6
|
+
export class EmailService
|
|
7
|
+
{
|
|
8
|
+
host: string;
|
|
9
|
+
username: string;
|
|
10
|
+
username_from: string;
|
|
11
|
+
password: string;
|
|
12
|
+
error_title: string;
|
|
13
|
+
error_recipients: string;
|
|
14
|
+
constructor(host: string, username: string, username_from: string, password: string, error_title: string, error_recipients: string)
|
|
15
|
+
{
|
|
16
|
+
this.host = host;
|
|
17
|
+
this.username = username;
|
|
18
|
+
this.username_from = username_from;
|
|
19
|
+
this.password = password;
|
|
20
|
+
this.error_title = error_title;
|
|
21
|
+
this.error_recipients = error_recipients;
|
|
22
|
+
}
|
|
23
|
+
sendExeption(error: Error, meta: any, callback?: (err: Error | null, info: any) => void)
|
|
24
|
+
{
|
|
25
|
+
let title = error.message;
|
|
26
|
+
let message = title;
|
|
27
|
+
if (meta)
|
|
28
|
+
message += "\r\n" + JSON.stringify(meta);
|
|
29
|
+
message += "\r\n" + error.stack;
|
|
30
|
+
this.sendError(title, message, callback);
|
|
31
|
+
}
|
|
32
|
+
sendError(title: string, message: string, callback?: (err: Error | null, info: any) => void)
|
|
33
|
+
{
|
|
34
|
+
if (!title)
|
|
35
|
+
title = '';
|
|
36
|
+
let toks = this.error_recipients.split(',');
|
|
37
|
+
for (let i = 0; i < toks.length; i++)
|
|
38
|
+
{
|
|
39
|
+
const email = toks[i];
|
|
40
|
+
this.send(
|
|
41
|
+
email,
|
|
42
|
+
this.error_title + " - " + title,
|
|
43
|
+
message, undefined, callback
|
|
44
|
+
);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
send(to: string, subject: string, text: string, html?: string | Buffer | Readable | AttachmentLike | undefined, callback?: (err: Error | null, info: any) => void)
|
|
48
|
+
{
|
|
49
|
+
if (!this.username)
|
|
50
|
+
return;
|
|
51
|
+
if (!this.password)
|
|
52
|
+
return;
|
|
53
|
+
let transform = {}
|
|
54
|
+
if (this.host === 'gmail')
|
|
55
|
+
transform = smtpTransport({
|
|
56
|
+
service: 'gmail',
|
|
57
|
+
host: 'smtp.gmail.com',
|
|
58
|
+
auth: {
|
|
59
|
+
user: this.username,
|
|
60
|
+
pass: this.password
|
|
61
|
+
}
|
|
62
|
+
});
|
|
63
|
+
else
|
|
64
|
+
transform = {
|
|
65
|
+
host: this.host,
|
|
66
|
+
port: 465,
|
|
67
|
+
secure: true,
|
|
68
|
+
auth: {
|
|
69
|
+
user: this.username,
|
|
70
|
+
pass: this.password
|
|
71
|
+
}
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
let transporter = nodemailer.createTransport(transform);
|
|
75
|
+
|
|
76
|
+
let mailOptions: Mail.Options = {
|
|
77
|
+
from: this.username_from,
|
|
78
|
+
to,
|
|
79
|
+
subject,
|
|
80
|
+
text,
|
|
81
|
+
html
|
|
82
|
+
};
|
|
83
|
+
if (html)
|
|
84
|
+
mailOptions.html = html;
|
|
85
|
+
|
|
86
|
+
transporter.sendMail(mailOptions, function (error, info)
|
|
87
|
+
{
|
|
88
|
+
if (callback)
|
|
89
|
+
callback(error, info);
|
|
90
|
+
else
|
|
91
|
+
{
|
|
92
|
+
if (error)
|
|
93
|
+
console.log(error);
|
|
94
|
+
}
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { ConvertService } from "namirasoft-core";
|
|
2
|
+
|
|
3
|
+
export class EnvService extends ConvertService
|
|
4
|
+
{
|
|
5
|
+
name: string;
|
|
6
|
+
constructor(name: string)
|
|
7
|
+
{
|
|
8
|
+
super();
|
|
9
|
+
this.name = name;
|
|
10
|
+
}
|
|
11
|
+
override getNullString(): string | null
|
|
12
|
+
{
|
|
13
|
+
let ans = process.env[this.name];
|
|
14
|
+
if (ans)
|
|
15
|
+
return ans;
|
|
16
|
+
return null;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
@@ -0,0 +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
|
+
}
|
|
39
|
+
}
|
package/src/Meta.ts
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import * as express from 'express';
|
|
2
|
+
import { IncomingHttpHeaders } from "http";
|
|
3
|
+
import { IPOperation } from './IPOperation';
|
|
4
|
+
|
|
5
|
+
export class Meta
|
|
6
|
+
{
|
|
7
|
+
ip: string;
|
|
8
|
+
method: string;
|
|
9
|
+
url: string;
|
|
10
|
+
headers: IncomingHttpHeaders;
|
|
11
|
+
body: any;
|
|
12
|
+
start_time: Date | null = null;
|
|
13
|
+
end_time: Date | null = null;
|
|
14
|
+
duration: number | null = null;
|
|
15
|
+
code: number = 200;
|
|
16
|
+
message: string = "Success";
|
|
17
|
+
error: Error | null = null;
|
|
18
|
+
constructor(req: express.Request)
|
|
19
|
+
{
|
|
20
|
+
this.ip = IPOperation.getIP(req);
|
|
21
|
+
this.method = req.method;
|
|
22
|
+
this.url = req.originalUrl;
|
|
23
|
+
this.headers = req.headers;
|
|
24
|
+
this.body = req.body;
|
|
25
|
+
}
|
|
26
|
+
onStart()
|
|
27
|
+
{
|
|
28
|
+
this.start_time = new Date();
|
|
29
|
+
}
|
|
30
|
+
onFinish()
|
|
31
|
+
{
|
|
32
|
+
this.end_time = new Date();
|
|
33
|
+
this.duration = (this.end_time?.getTime() ?? 0) - (this.start_time?.getTime() ?? 0);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import * as express from 'express';
|
|
2
|
+
import { ConvertService, ObjectService } from 'namirasoft-core';
|
|
3
|
+
|
|
4
|
+
export class RequestHeaderService extends ConvertService
|
|
5
|
+
{
|
|
6
|
+
private req: express.Request;
|
|
7
|
+
private name: string;
|
|
8
|
+
constructor(req: express.Request, name: string)
|
|
9
|
+
{
|
|
10
|
+
super();
|
|
11
|
+
this.req = req;
|
|
12
|
+
this.name = name;
|
|
13
|
+
}
|
|
14
|
+
override getNullString()
|
|
15
|
+
{
|
|
16
|
+
let item = this.req.headers[this.name];
|
|
17
|
+
return new ObjectService(item).getNullString();
|
|
18
|
+
}
|
|
19
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import * as express from 'express';
|
|
2
|
+
import { ErrorOperation, SignOperation } from "namirasoft-core";
|
|
3
|
+
import { RequestHeaderService } from './RequestHeaderService';
|
|
4
|
+
|
|
5
|
+
export class ServerToServerOperation
|
|
6
|
+
{
|
|
7
|
+
static isValid(sign_key: string, data: any, req: express.Request, sign_header: string): boolean
|
|
8
|
+
{
|
|
9
|
+
let signature = new RequestHeaderService(req, sign_header).getString();
|
|
10
|
+
return SignOperation.isValid(sign_key, data, signature);
|
|
11
|
+
}
|
|
12
|
+
static check(sign_key: string, data: any, req: express.Request, sign_header: string): void
|
|
13
|
+
{
|
|
14
|
+
if (!sign_key)
|
|
15
|
+
ErrorOperation.throwHTTP(401, "Invlid signature - No sign key.");
|
|
16
|
+
if (!sign_header)
|
|
17
|
+
ErrorOperation.throwHTTP(401, "Invlid signature - No sign header name.");
|
|
18
|
+
let signature = new RequestHeaderService(req, sign_header).getString();
|
|
19
|
+
if (!signature)
|
|
20
|
+
ErrorOperation.throwHTTP(401, "Invlid signature - No signature.");
|
|
21
|
+
if (!this.isValid(sign_key, data, req, sign_header))
|
|
22
|
+
ErrorOperation.throwHTTP(401, "Invlid signature.");
|
|
23
|
+
}
|
|
24
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export * from "./AnomalyDetector";
|
|
2
|
+
export * from "./BaseApplication";
|
|
3
|
+
export * from "./BaseController";
|
|
4
|
+
export * from "./BaseDatabase";
|
|
5
|
+
export * from "./BaseMiddleware";
|
|
6
|
+
export * from "./BaseSequelizeModel";
|
|
7
|
+
export * from "./BaseMySqlDatabase";
|
|
8
|
+
export * from "./BaseSequelizeTable";
|
|
9
|
+
export * from "./BaseSequelizeDatabase";
|
|
10
|
+
export * from "./BaseTable";
|
|
11
|
+
export * from "./EmailService";
|
|
12
|
+
export * from "./EnvService";
|
|
13
|
+
export * from "./IPOperation";
|
|
14
|
+
export * from "./RequestHeaderService";
|
|
15
|
+
export * from "./ServerToServerOperation";
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES6",
|
|
4
|
+
"module": "CommonJS",
|
|
5
|
+
"rootDir": "./src",
|
|
6
|
+
"outDir": "./dist",
|
|
7
|
+
"lib": [
|
|
8
|
+
"es6",
|
|
9
|
+
"dom"
|
|
10
|
+
],
|
|
11
|
+
"allowJs": false,
|
|
12
|
+
"checkJs": false,
|
|
13
|
+
"strict": true,
|
|
14
|
+
"esModuleInterop": true,
|
|
15
|
+
"sourceMap": true,
|
|
16
|
+
"resolveJsonModule": true,
|
|
17
|
+
"declaration": true,
|
|
18
|
+
"noUnusedLocals": true,
|
|
19
|
+
"noUnusedParameters": true,
|
|
20
|
+
"noImplicitAny": true,
|
|
21
|
+
"noImplicitOverride": true,
|
|
22
|
+
"noImplicitReturns": true,
|
|
23
|
+
"noImplicitThis": true,
|
|
24
|
+
"skipLibCheck": false,
|
|
25
|
+
"allowSyntheticDefaultImports": true,
|
|
26
|
+
"forceConsistentCasingInFileNames": true,
|
|
27
|
+
"noFallthroughCasesInSwitch": true,
|
|
28
|
+
"isolatedModules": false,
|
|
29
|
+
}
|
|
30
|
+
}
|