Skip to content

Commit 0256599

Browse files
committed
Completed /api/add
1 parent 0d083c4 commit 0256599

10 files changed

+200
-34
lines changed

.env.example

+3
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,9 @@ SSH_PORT=22
4343
# true | false
4444
API_ENABLE=true
4545

46+
# api documentation
47+
API_DOCS=false
48+
4649
# Secret key for your tokens
4750
API_SECRET=S@CrET
4851

.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
users.json
55
blocked_ips.csv
6+
users.csv
67

78
# Logs
89
logs

api/controller.js

+10-2
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,22 @@
1+
const { AuthApiKey, Validator } = require("./middlewares");
12
const Model = require("./model");
2-
const Validator = require("./validator");
33
const router = require("express").Router();
44

55
const validator = new Validator();
66
const model = new Model();
77

8+
// Send your api username and password in json format to generate api_key
89
router.post("/token", validator.token, (req, res) => {
910
const result = model.token();
1011

11-
return res.json({ api_key: result });
12+
return res.json(result);
13+
});
14+
15+
// Send your proxy email and limit data in json format to be applied
16+
router.post("/add", AuthApiKey, validator.add, (req, res) => {
17+
const result = model.add(req.body);
18+
19+
return res.json(result);
1220
});
1321

1422
module.exports = router;

api/middlewares.js

+104
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
const { response } = require("./utils");
2+
const crypto = require("crypto-js");
3+
const Joi = require("joi");
4+
5+
const AuthApiKey = (req, res, next) => {
6+
let apiKey = (req.headers["api_key"] || "").trim();
7+
8+
if (!apiKey)
9+
return res.status(403).json(
10+
response({
11+
error: {
12+
type: "AUTH",
13+
reason: "api_key Not found!",
14+
},
15+
}),
16+
);
17+
18+
let decryptedKey = crypto.AES.decrypt(
19+
apiKey,
20+
process.env.API_SECRET,
21+
).toString(crypto.enc.Utf8);
22+
23+
const parseKey = JSON.parse(decryptedKey);
24+
25+
if (Date.now() > +parseKey.expireAt)
26+
return res.status(403).json(
27+
response({
28+
error: {
29+
type: "AUTH",
30+
reason: "api_key expired Please get a new api_key",
31+
},
32+
}),
33+
);
34+
35+
return next();
36+
};
37+
38+
class Validator {
39+
token(req, res, next) {
40+
/**
41+
* @type {ApiSetTokenType}
42+
*/
43+
const data = req.body;
44+
45+
const schema = Joi.object({
46+
username: Joi.string().required(),
47+
password: Joi.string().required(),
48+
});
49+
50+
const { error } = schema.validate(data);
51+
52+
if (error) {
53+
return res.status(403).json(
54+
response({
55+
error: {
56+
type: "INVALID",
57+
reason: error.message,
58+
},
59+
}),
60+
);
61+
}
62+
63+
if (process.env.API_LOGIN !== `${data.username}:${data.password}`)
64+
return res.status(403).json(
65+
response({
66+
error: {
67+
type: "NOT_MATCH",
68+
reason: "Username or password doesn't match",
69+
},
70+
}),
71+
);
72+
73+
return next();
74+
}
75+
76+
add(req, res, next) {
77+
const schema = Joi.object({
78+
email: Joi.string().required(),
79+
limit: Joi.number().required(),
80+
});
81+
82+
const data = req.body;
83+
84+
const { error } = schema.validate(data);
85+
86+
if (error) {
87+
return res.status(403).json(
88+
response({
89+
error: {
90+
type: "INVALID",
91+
reason: error.message,
92+
},
93+
}),
94+
);
95+
}
96+
97+
return next();
98+
}
99+
}
100+
101+
module.exports = {
102+
AuthApiKey,
103+
Validator,
104+
};

api/model.js

+42-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,14 @@
11
const crypto = require("crypto-js");
2+
const { File } = require("../utils");
3+
const { join } = require("path");
4+
const fs = require("fs");
5+
const { response } = require("./utils");
26

37
class Model {
8+
constructor() {
9+
this.usersCsvPath = join(__dirname, "../", "users.csv");
10+
}
11+
412
token() {
513
const expireAt =
614
Date.now() + 1000 * 60 * 60 * 24 * +process.env.API_EXPIRE_TOKEN_AT;
@@ -12,7 +20,40 @@ class Model {
1220
process.env.API_SECRET,
1321
).toString();
1422

15-
return token;
23+
return response({
24+
data: { api_key: token },
25+
status: 1,
26+
});
27+
}
28+
29+
/**
30+
* @typedef {Object} ApiAddDataType
31+
* @property {string} email
32+
* @property {string} limit
33+
*
34+
* @param {ApiAddDataType} data
35+
*/
36+
37+
add(data) {
38+
let file = new File().GetCsvFile(this.usersCsvPath).toString();
39+
40+
if (file.includes(data.email))
41+
return response({
42+
error: {
43+
type: "DUPLICATE",
44+
reason: "This email already exists",
45+
},
46+
});
47+
48+
const dataToCsv = `${data.email},${data.limit}\r\n`;
49+
50+
file += dataToCsv;
51+
52+
fs.writeFileSync(this.usersCsvPath, file);
53+
54+
return response({
55+
status: 1,
56+
});
1657
}
1758
}
1859

api/utils.js

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
/**
2+
*
3+
* @param {ApiResponseType} params
4+
*/
5+
6+
const response = (params) => {
7+
if (!params?.data) params.data = null;
8+
if (!params?.error) params.error = null;
9+
if (!params?.status) params.status = 0;
10+
11+
return params;
12+
};
13+
14+
module.exports = { response };

api/validator.js

-28
This file was deleted.

db/DBSqlite3.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ class DBSqlite3 extends DBInterface {
8787
const indexOfIp = ips.findIndex((item) => item.ip === ipData.ip);
8888

8989
// Get the users.json file
90-
const usersJson = new File().GetFilesJson(join("users.json"));
90+
const usersJson = new File().GetJsonFile(join("users.json"));
9191
const indexOfUser = usersJson.findIndex((item) => item[0] === email);
9292

9393
const userJson = usersJson[indexOfUser] || [

types.js

+17
Original file line numberDiff line numberDiff line change
@@ -45,3 +45,20 @@
4545
* @property {string} username
4646
* @property {string} password
4747
*/
48+
49+
/**
50+
* @typedef {"INVALID" | "NOT_MATCH" | "AUTH" | "DUPLICATE"} ApiErrorTypes
51+
*/
52+
53+
/**
54+
* @typedef {Object} ApiResponseErrorType
55+
* @property {ApiErrorTypes} type
56+
* @property {string} reason
57+
*/
58+
59+
/**
60+
* @typedef {Object} ApiResponseType
61+
* @property {Object | null} data
62+
* @property {ApiResponseErrorType} error
63+
* @property {0|1} status
64+
*/

utils.js

+8-2
Original file line numberDiff line numberDiff line change
@@ -145,11 +145,17 @@ class File {
145145
return;
146146
}
147147

148-
GetFilesJson(path) {
148+
GetJsonFile(path) {
149149
this.ForceExistsFile(path);
150150

151151
return JSON.parse(fs.readFileSync(path));
152152
}
153+
154+
GetCsvFile(path) {
155+
this.ForceExistsFile(path, "");
156+
157+
return fs.readFileSync(path);
158+
}
153159
}
154160

155161
/**
@@ -174,7 +180,7 @@ class IPGuard {
174180

175181
const indexOfIp = data.ips.findIndex((item) => item.ip === `${ip}`);
176182

177-
const users = new File().GetFilesJson("users.json");
183+
const users = new File().GetJsonFile("users.json");
178184
const user = users.filter((item) => item[0] === data.email)[0] || null;
179185

180186
const maxAllowConnection = user ? +user[1] : +process.env.MAX_ALLOW_USERS;

0 commit comments

Comments
 (0)