mbkauthe 1.0.5 → 1.0.6
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/.env.example +11 -0
- package/.github/workflows/publish.yml +7 -0
- package/README.md +9 -7
- package/index.js +19 -17
- package/lib/main.js +40 -22
- package/lib/pool.js +19 -2
- package/lib/validateSessionAndRole.js +15 -1
- package/package.json +1 -2
- package/lib/auth.js +0 -13
package/.env.example
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
mbkautheVar='{
|
|
2
|
+
"RECAPTCHA_SECRET_KEY": "your-recaptcha-secret-key",
|
|
3
|
+
"SESSION_SECRET_KEY": "your-session-secret-key",
|
|
4
|
+
"IS_DEPLOYED": "true",
|
|
5
|
+
"LOGIN_DB": "postgres://username:password@host:port/database",
|
|
6
|
+
"MBKAUTH_TWO_FA_ENABLE": "false",
|
|
7
|
+
"COOKIE_EXPIRE_TIME": 2,
|
|
8
|
+
"DOMAIN": "yourdomain.com"
|
|
9
|
+
}'
|
|
10
|
+
|
|
11
|
+
# See env.md for more details
|
package/README.md
CHANGED
|
@@ -55,13 +55,15 @@ app.listen(3000, () => {
|
|
|
55
55
|
|
|
56
56
|
Example `.env` file:
|
|
57
57
|
```code
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
MBKAUTH_TWO_FA_ENABLE
|
|
64
|
-
COOKIE_EXPIRE_TIME
|
|
58
|
+
mbkautheVar='{
|
|
59
|
+
"RECAPTCHA_SECRET_KEY": "your-recaptcha-secret-key",
|
|
60
|
+
"SESSION_SECRET_KEY": "your-session-secret-key",
|
|
61
|
+
"IS_DEPLOYED": "true",
|
|
62
|
+
"LOGIN_DB": "postgres://username:password@host:port/database",
|
|
63
|
+
"MBKAUTH_TWO_FA_ENABLE": "false",
|
|
64
|
+
"COOKIE_EXPIRE_TIME": 2,
|
|
65
|
+
"DOMAIN": "yourdomain.com"
|
|
66
|
+
}'
|
|
65
67
|
```
|
|
66
68
|
|
|
67
69
|
## API Endpoints
|
package/index.js
CHANGED
|
@@ -1,23 +1,25 @@
|
|
|
1
|
-
import dotenv from "dotenv";
|
|
2
|
-
import Joi from "joi";
|
|
3
1
|
import router from "./lib/main.js";
|
|
2
|
+
|
|
3
|
+
import dotenv from "dotenv";
|
|
4
4
|
dotenv.config();
|
|
5
|
+
const mbkautheVar = JSON.parse(process.env.mbkautheVar);
|
|
6
|
+
if (!mbkautheVar) {
|
|
7
|
+
throw new Error("mbkautheVar is not defined");
|
|
8
|
+
}
|
|
9
|
+
const requiredKeys = ["RECAPTCHA_SECRET_KEY", "SESSION_SECRET_KEY", "IS_DEPLOYED", "LOGIN_DB", "MBKAUTH_TWO_FA_ENABLE", "DOMAIN"];
|
|
10
|
+
requiredKeys.forEach(key => {
|
|
11
|
+
if (!mbkautheVar[key]) {
|
|
12
|
+
throw new Error(`mbkautheVar.${key} is required`);
|
|
13
|
+
}
|
|
14
|
+
});
|
|
15
|
+
if (mbkautheVar.COOKIE_EXPIRE_TIME !== undefined) {
|
|
16
|
+
const expireTime = parseFloat(mbkautheVar.COOKIE_EXPIRE_TIME);
|
|
17
|
+
if (isNaN(expireTime) || expireTime <= 0) {
|
|
18
|
+
throw new Error("mbkautheVar.COOKIE_EXPIRE_TIME must be a valid positive number");
|
|
19
|
+
}
|
|
20
|
+
}
|
|
5
21
|
|
|
6
|
-
const envSchema = Joi.object({
|
|
7
|
-
RECAPTCHA_SECRET_KEY: Joi.string().required(),
|
|
8
|
-
SESSION_SECRET_KEY: Joi.string().required(),
|
|
9
|
-
IS_DEPLOYED: Joi.string().valid("true", "false").required(),
|
|
10
|
-
LOGIN_DB: Joi.string().uri().required(),
|
|
11
|
-
MBKAUTH_TWO_FA_ENABLE: Joi.string().valid("true", "false").required(),
|
|
12
|
-
COOKIE_EXPIRE_TIME: Joi.number().integer().positive(),
|
|
13
|
-
DOMAIN: Joi.string().required(),
|
|
14
|
-
}).unknown(true);
|
|
15
22
|
|
|
16
|
-
|
|
17
|
-
if (error) {
|
|
18
|
-
throw new Error(`Environment variable validation error: ${error.message}`);
|
|
19
|
-
}
|
|
20
|
-
export { validateSession, checkRolePermission, validateSessionAndRole, getUserData } from "./lib/validateSessionAndRole.js";
|
|
21
|
-
export { authenticate } from "./lib/auth.js";
|
|
23
|
+
export { validateSession, checkRolePermission, validateSessionAndRole, getUserData, authenticate } from "./lib/validateSessionAndRole.js";
|
|
22
24
|
export { dblogin } from "./lib/pool.js";
|
|
23
25
|
export default router;
|
package/lib/main.js
CHANGED
|
@@ -3,24 +3,44 @@ import crypto from "crypto";
|
|
|
3
3
|
import session from "express-session";
|
|
4
4
|
import pgSession from "connect-pg-simple";
|
|
5
5
|
const PgSession = pgSession(session);
|
|
6
|
-
import dotenv from "dotenv";
|
|
7
6
|
import { dblogin } from "./pool.js";
|
|
8
|
-
import { authenticate } from "./
|
|
7
|
+
import { authenticate } from "./validateSessionAndRole.js";
|
|
9
8
|
import fetch from 'node-fetch';
|
|
10
|
-
import cookieParser from "cookie-parser";
|
|
9
|
+
import cookieParser from "cookie-parser";
|
|
10
|
+
|
|
11
11
|
|
|
12
|
+
|
|
13
|
+
import dotenv from "dotenv";
|
|
12
14
|
dotenv.config();
|
|
15
|
+
const mbkautheVar = JSON.parse(process.env.mbkautheVar);
|
|
16
|
+
if (!mbkautheVar) {
|
|
17
|
+
throw new Error("mbkautheVar is not defined");
|
|
18
|
+
}
|
|
19
|
+
const requiredKeys = ["RECAPTCHA_SECRET_KEY", "SESSION_SECRET_KEY", "IS_DEPLOYED", "LOGIN_DB", "MBKAUTH_TWO_FA_ENABLE", "DOMAIN"];
|
|
20
|
+
requiredKeys.forEach(key => {
|
|
21
|
+
if (!mbkautheVar[key]) {
|
|
22
|
+
throw new Error(`mbkautheVar.${key} is required`);
|
|
23
|
+
}
|
|
24
|
+
});
|
|
25
|
+
if (mbkautheVar.COOKIE_EXPIRE_TIME !== undefined) {
|
|
26
|
+
const expireTime = parseFloat(mbkautheVar.COOKIE_EXPIRE_TIME);
|
|
27
|
+
if (isNaN(expireTime) || expireTime <= 0) {
|
|
28
|
+
throw new Error("mbkautheVar.COOKIE_EXPIRE_TIME must be a valid positive number");
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
|
|
13
33
|
const router = express.Router();
|
|
14
34
|
let COOKIE_EXPIRE_TIME = 2 * 24 * 60 * 60 * 1000; //2 days
|
|
15
35
|
|
|
16
36
|
try {
|
|
17
|
-
const parsedExpireTime = parseInt(
|
|
37
|
+
const parsedExpireTime = parseInt(mbkautheVar.COOKIE_EXPIRE_TIME, 10);
|
|
18
38
|
if (!isNaN(parsedExpireTime) && parsedExpireTime > 0) {
|
|
19
39
|
COOKIE_EXPIRE_TIME = parsedExpireTime * 24 * 60 * 60 * 1000; // Convert days to milliseconds
|
|
20
40
|
} else {
|
|
21
41
|
console.warn("Invalid COOKIE_EXPIRE_TIME in environment variables, using default value");
|
|
22
42
|
}
|
|
23
|
-
console.log(`Cookie expiration time set to ${COOKIE_EXPIRE_TIME} days for deployed environment`);
|
|
43
|
+
console.log(`Cookie expiration time set to ${COOKIE_EXPIRE_TIME / (24 * 60 * 60 * 1000)} days for deployed environment`);
|
|
24
44
|
} catch (error) {
|
|
25
45
|
console.log("Error parsing COOKIE_EXPIRE_TIME:", error);
|
|
26
46
|
}
|
|
@@ -34,14 +54,14 @@ router.use(
|
|
|
34
54
|
pool: dblogin, // Connection pool
|
|
35
55
|
tableName: "session", // Use another table-name than the default "session" one
|
|
36
56
|
}),
|
|
37
|
-
secret:
|
|
57
|
+
secret: mbkautheVar.SESSION_SECRET_KEY, // Replace with your secret key
|
|
38
58
|
resave: false,
|
|
39
59
|
saveUninitialized: false,
|
|
40
60
|
cookie: {
|
|
41
61
|
maxAge: COOKIE_EXPIRE_TIME,
|
|
42
|
-
DOMAIN:
|
|
62
|
+
DOMAIN: mbkautheVar.IS_DEPLOYED === 'true' ? `.${mbkautheVar.DOMAIN}` : undefined, // Use root DOMAIN for subDOMAIN sharing
|
|
43
63
|
httpOnly: true,
|
|
44
|
-
secure:
|
|
64
|
+
secure: mbkautheVar.IS_DEPLOYED === 'true', // Use secure cookies in production
|
|
45
65
|
},
|
|
46
66
|
})
|
|
47
67
|
);
|
|
@@ -123,7 +143,7 @@ router.use(async (req, res, next) => {
|
|
|
123
143
|
|
|
124
144
|
//Invoke-RestMethod -Uri http://localhost:3030/terminateAllSessions -Method POST
|
|
125
145
|
// Terminate all sessions route
|
|
126
|
-
router.post("/mbkauthe/api/terminateAllSessions", authenticate(
|
|
146
|
+
router.post("/mbkauthe/api/terminateAllSessions", authenticate(mbkautheVar.Main_SECRET_TOKEN), async (req, res) => {
|
|
127
147
|
try {
|
|
128
148
|
await dblogin.query(`UPDATE "Users" SET "SessionId" = NULL`);
|
|
129
149
|
|
|
@@ -159,11 +179,17 @@ router.post("/mbkauthe/api/login", async (req, res) => {
|
|
|
159
179
|
const { username, password, token, recaptcha } = req.body;
|
|
160
180
|
console.log(`Login attempt for username: ${username}`); // Log username
|
|
161
181
|
|
|
162
|
-
const secretKey =
|
|
182
|
+
const secretKey = mbkautheVar.RECAPTCHA_SECRET_KEY;
|
|
163
183
|
const verificationUrl = `https://www.google.com/recaptcha/api/siteverify?secret=${secretKey}&response=${recaptcha}`;
|
|
164
184
|
|
|
185
|
+
let BypassUsers = ["ibnekhalid", "maaz.waheed", "support"];
|
|
186
|
+
|
|
165
187
|
// Bypass recaptcha for specific users
|
|
166
|
-
if (
|
|
188
|
+
if (!BypassUsers.includes(username)) {
|
|
189
|
+
if (!recaptcha) {
|
|
190
|
+
console.log("Missing reCAPTCHA token");
|
|
191
|
+
return res.status(400).json({ success: false, message: "Please complete the reCAPTCHA" });
|
|
192
|
+
}
|
|
167
193
|
try {
|
|
168
194
|
const response = await fetch(verificationUrl, { method: 'POST' });
|
|
169
195
|
const body = await response.json();
|
|
@@ -187,14 +213,6 @@ router.post("/mbkauthe/api/login", async (req, res) => {
|
|
|
187
213
|
});
|
|
188
214
|
}
|
|
189
215
|
|
|
190
|
-
console.log("RECAPTCHA_SECRET_KEY:", process.env.RECAPTCHA_SECRET_KEY); // Log reCAPTCHA secret key
|
|
191
|
-
console.log("SESSION_SECRET_KEY:", process.env.SESSION_SECRET_KEY); // Log reCAPTCHA secret key
|
|
192
|
-
console.log("LOGIN_DB:", process.env.LOGIN_DB); // Log reCAPTCHA secret key
|
|
193
|
-
console.log("COOKIE_EXPIRE_TIME:", process.env.COOKIE_EXPIRE_TIME); // Log reCAPTCHA secret key
|
|
194
|
-
console.log("DOMAIN:", process.env.DOMAIN); // Log reCAPTCHA secret key
|
|
195
|
-
console.log("IS_DEPLOYED:", process.env.IS_DEPLOYED); // Log reCAPTCHA secret key
|
|
196
|
-
console.log("MBKAUTH_TWO_FA_ENABLE:", process.env.MBKAUTH_TWO_FA_ENABLE); // Log reCAPTCHA secret key
|
|
197
|
-
|
|
198
216
|
try {
|
|
199
217
|
// Query to check if the username exists
|
|
200
218
|
const userQuery = `SELECT * FROM "Users" WHERE "UserName" = $1`;
|
|
@@ -220,7 +238,7 @@ router.post("/mbkauthe/api/login", async (req, res) => {
|
|
|
220
238
|
return res.status(403).json({ success: false, message: "Account is inactive" });
|
|
221
239
|
}
|
|
222
240
|
|
|
223
|
-
if ((
|
|
241
|
+
if ((mbkautheVar.MBKAUTH_TWO_FA_ENABLE || "").toLocaleLowerCase() === "true") {
|
|
224
242
|
let sharedSecret;
|
|
225
243
|
const query = `SELECT "TwoFAStatus", "TwoFASecret" FROM "TwoFA" WHERE "UserName" = $1`;
|
|
226
244
|
const twoFAResult = await dblogin.query(query, [username]);
|
|
@@ -267,9 +285,9 @@ router.post("/mbkauthe/api/login", async (req, res) => {
|
|
|
267
285
|
// Set a cookie accessible across subDOMAINs
|
|
268
286
|
res.cookie("sessionId", sessionId, {
|
|
269
287
|
maxAge: COOKIE_EXPIRE_TIME,
|
|
270
|
-
DOMAIN:
|
|
288
|
+
DOMAIN: mbkautheVar.IS_DEPLOYED === 'true' ? `.${mbkautheVar.DOMAIN}` : undefined, // Use DOMAIN only in production
|
|
271
289
|
httpOnly: true,
|
|
272
|
-
secure:
|
|
290
|
+
secure: mbkautheVar.IS_DEPLOYED === 'true', // Use secure cookies in production
|
|
273
291
|
});
|
|
274
292
|
console.log(`Cookie set for user: ${user.UserName}, sessionId: ${sessionId}`); // Log cookie setting
|
|
275
293
|
|
package/lib/pool.js
CHANGED
|
@@ -1,12 +1,29 @@
|
|
|
1
1
|
import pkg from "pg";
|
|
2
2
|
const { Pool } = pkg;
|
|
3
|
-
import dotenv from "dotenv";
|
|
4
3
|
|
|
4
|
+
|
|
5
|
+
import dotenv from "dotenv";
|
|
5
6
|
dotenv.config();
|
|
7
|
+
const mbkautheVar = JSON.parse(process.env.mbkautheVar);
|
|
8
|
+
if (!mbkautheVar) {
|
|
9
|
+
throw new Error("mbkautheVar is not defined");
|
|
10
|
+
}
|
|
11
|
+
const requiredKeys = ["RECAPTCHA_SECRET_KEY", "SESSION_SECRET_KEY", "IS_DEPLOYED", "LOGIN_DB", "MBKAUTH_TWO_FA_ENABLE", "DOMAIN"];
|
|
12
|
+
requiredKeys.forEach(key => {
|
|
13
|
+
if (!mbkautheVar[key]) {
|
|
14
|
+
throw new Error(`mbkautheVar.${key} is required`);
|
|
15
|
+
}
|
|
16
|
+
});
|
|
17
|
+
if (mbkautheVar.COOKIE_EXPIRE_TIME !== undefined) {
|
|
18
|
+
const expireTime = parseFloat(mbkautheVar.COOKIE_EXPIRE_TIME);
|
|
19
|
+
if (isNaN(expireTime) || expireTime <= 0) {
|
|
20
|
+
throw new Error("mbkautheVar.COOKIE_EXPIRE_TIME must be a valid positive number");
|
|
21
|
+
}
|
|
22
|
+
}
|
|
6
23
|
|
|
7
24
|
// PostgreSQL connection pool for pool
|
|
8
25
|
const poolConfig = {
|
|
9
|
-
connectionString:
|
|
26
|
+
connectionString: mbkautheVar.LOGIN_DB,
|
|
10
27
|
ssl: {
|
|
11
28
|
rejectUnauthorized: true,
|
|
12
29
|
},
|
|
@@ -149,4 +149,18 @@ async function getUserData(UserName, parameters) {
|
|
|
149
149
|
}
|
|
150
150
|
}
|
|
151
151
|
|
|
152
|
-
|
|
152
|
+
const authenticate = (authentication) => {
|
|
153
|
+
return (req, res, next) => {
|
|
154
|
+
const token = req.headers["authorization"];
|
|
155
|
+
console.log(`Received token: ${token}`);
|
|
156
|
+
if (token === authentication) {
|
|
157
|
+
console.log("Authentication successful");
|
|
158
|
+
next();
|
|
159
|
+
} else {
|
|
160
|
+
console.log("Authentication failed");
|
|
161
|
+
res.status(401).send("Unauthorized");
|
|
162
|
+
}
|
|
163
|
+
};
|
|
164
|
+
};
|
|
165
|
+
|
|
166
|
+
export { validateSession, checkRolePermission, validateSessionAndRole, getUserData , authenticate};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mbkauthe",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.6",
|
|
4
4
|
"description": "MBKTechStudio's reusable authentication system for Node.js applications.",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"type": "module",
|
|
@@ -31,7 +31,6 @@
|
|
|
31
31
|
"dotenv": "^16.4.7",
|
|
32
32
|
"express": "^5.1.0",
|
|
33
33
|
"express-session": "^1.18.1",
|
|
34
|
-
"joi": "^17.13.3",
|
|
35
34
|
"node-fetch": "^3.3.2",
|
|
36
35
|
"pg": "^8.14.1"
|
|
37
36
|
}
|
package/lib/auth.js
DELETED
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
export const authenticate = (authentication) => {
|
|
2
|
-
return (req, res, next) => {
|
|
3
|
-
const token = req.headers["authorization"];
|
|
4
|
-
console.log(`Received token: ${token}`);
|
|
5
|
-
if (token === authentication) {
|
|
6
|
-
console.log("Authentication successful");
|
|
7
|
-
next();
|
|
8
|
-
} else {
|
|
9
|
-
console.log("Authentication failed");
|
|
10
|
-
res.status(401).send("Unauthorized");
|
|
11
|
-
}
|
|
12
|
-
};
|
|
13
|
-
};
|