mbkauthe 1.0.6 → 1.0.8
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 +3 -0
- package/README.md +18 -2
- package/docs/db.md +2 -0
- package/env.md +20 -2
- package/index.js +12 -1
- package/lib/main.js +81 -123
- package/lib/pool.js +0 -16
- package/lib/validateSessionAndRole.js +49 -15
- package/package.json +1 -1
package/.env.example
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
mbkautheVar='{
|
|
2
|
+
"APP_NAME": "MBKAUTH",
|
|
2
3
|
"RECAPTCHA_SECRET_KEY": "your-recaptcha-secret-key",
|
|
4
|
+
"RECAPTCHA_Enabled": "f",
|
|
5
|
+
"BypassUsers": ["demo","user1"],
|
|
3
6
|
"SESSION_SECRET_KEY": "your-session-secret-key",
|
|
4
7
|
"IS_DEPLOYED": "true",
|
|
5
8
|
"LOGIN_DB": "postgres://username:password@host:port/database",
|
package/README.md
CHANGED
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
- [Features](#features)
|
|
9
9
|
- [Installation](#installation)
|
|
10
10
|
- [Usage](#usage)
|
|
11
|
+
- [Implementation in a Project](#implementation-in-a-project)
|
|
11
12
|
- [Basic Setup](#basic-setup)
|
|
12
13
|
- [API Endpoints](#api-endpoints)
|
|
13
14
|
- [Login](#login)
|
|
@@ -37,6 +38,18 @@ npm install mbkauthe
|
|
|
37
38
|
```
|
|
38
39
|
|
|
39
40
|
## Usage
|
|
41
|
+
|
|
42
|
+
### Implementation in a Project
|
|
43
|
+
|
|
44
|
+
For a practical example of how to use this package, check out the [ProjectImplementation branch](https://github.com/MIbnEKhalid/mbkauthe/tree/ProjectImplementation) of the repository. This branch demonstrates the integration of the package, including a login page, a protected page, and logout functionality.
|
|
45
|
+
|
|
46
|
+
You can explore the functionality of `mbkAuthe` using the following demo account on [mbkauthe.mbktechstudio.com](https://mbkauthe.mbktechstudio.com):
|
|
47
|
+
|
|
48
|
+
- **Username**: `demo`
|
|
49
|
+
- **Password**: `demo`
|
|
50
|
+
|
|
51
|
+
This demo provides a hands-on experience with the authentication system, including login, session management, and other features.
|
|
52
|
+
|
|
40
53
|
### Basic Setup
|
|
41
54
|
1. Import and configure the router in your Express application:
|
|
42
55
|
```javascript
|
|
@@ -51,17 +64,20 @@ app.listen(3000, () => {
|
|
|
51
64
|
console.log("Server is running on port 3000");
|
|
52
65
|
});
|
|
53
66
|
```
|
|
54
|
-
2. Ensure your
|
|
67
|
+
2. Ensure your `.env` file is properly configured. Refer to the [Configuration Guide(env.md)](env.md) for details.
|
|
55
68
|
|
|
56
69
|
Example `.env` file:
|
|
57
70
|
```code
|
|
58
71
|
mbkautheVar='{
|
|
72
|
+
"APP_NAME": "MBKAUTH",
|
|
59
73
|
"RECAPTCHA_SECRET_KEY": "your-recaptcha-secret-key",
|
|
74
|
+
"RECAPTCHA_Enabled": "false",
|
|
75
|
+
"BypassUsers": ["user1","user2"],
|
|
60
76
|
"SESSION_SECRET_KEY": "your-session-secret-key",
|
|
61
77
|
"IS_DEPLOYED": "true",
|
|
62
78
|
"LOGIN_DB": "postgres://username:password@host:port/database",
|
|
63
79
|
"MBKAUTH_TWO_FA_ENABLE": "false",
|
|
64
|
-
"COOKIE_EXPIRE_TIME":
|
|
80
|
+
"COOKIE_EXPIRE_TIME": "1",
|
|
65
81
|
"DOMAIN": "yourdomain.com"
|
|
66
82
|
}'
|
|
67
83
|
```
|
package/docs/db.md
CHANGED
|
@@ -22,6 +22,7 @@
|
|
|
22
22
|
- `HaveMailAccount` (BOOLEAN)(optional): Indicates if the user has a linked mail account.
|
|
23
23
|
- `SessionId` (TEXT): The session ID associated with the user.
|
|
24
24
|
- `GuestRole` (JSONB): Stores additional guest-specific role information in binary JSON format.
|
|
25
|
+
- `AllowedApps`(JSONB):
|
|
25
26
|
|
|
26
27
|
- **Schema:**
|
|
27
28
|
```sql
|
|
@@ -34,6 +35,7 @@
|
|
|
34
35
|
"HaveMailAccount" BOOLEAN NOT NULL DEFAULT false,
|
|
35
36
|
"SessionId" TEXT,
|
|
36
37
|
"GuestRole" JSONB DEFAULT '{"allowPages": [""], "NotallowPages": [""]}'::jsonb
|
|
38
|
+
"AllowedApps" JSONB DEFAULT '{"allowPages": [""], "NotallowPages": [""]}'::jsonb
|
|
37
39
|
);
|
|
38
40
|
```
|
|
39
41
|
|
package/env.md
CHANGED
|
@@ -2,11 +2,29 @@
|
|
|
2
2
|
|
|
3
3
|
[<- Back](README.md)
|
|
4
4
|
|
|
5
|
+
## Application Settings
|
|
6
|
+
|
|
7
|
+
```properties
|
|
8
|
+
APP_NAME=mbkauthe
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
> **APP_NAME**: Specifies the name of the application. This is used to distinguish one project from another and is critical for ensuring users are restricted to specific apps. It corresponds to the `AllowedApp` column in the Users table.
|
|
12
|
+
|
|
5
13
|
## reCAPTCHA Settings
|
|
14
|
+
|
|
6
15
|
```properties
|
|
7
|
-
|
|
16
|
+
RECAPTCHA_ENABLED=true
|
|
17
|
+
RECAPTCHA_SECRET_KEY=your-secret-key
|
|
18
|
+
BYPASS_USERS=["demo", "user1"]
|
|
8
19
|
```
|
|
9
|
-
|
|
20
|
+
|
|
21
|
+
> **RECAPTCHA_ENABLED**: Set to `true` to enable reCAPTCHA verification.
|
|
22
|
+
|
|
23
|
+
> **RECAPTCHA_SECRET_KEY**: Provide the secret key obtained from the [Google reCAPTCHA Admin Console](https://www.google.com/recaptcha/admin).
|
|
24
|
+
|
|
25
|
+
> **BYPASS_USERS**: Specify an array of usernames (e.g., `["demo", "user1"]`) that will bypass reCAPTCHA verification.
|
|
26
|
+
|
|
27
|
+
> **Note**: Ensure `RECAPTCHA_SECRET_KEY` is set when `RECAPTCHA_ENABLED=true`.
|
|
10
28
|
|
|
11
29
|
|
|
12
30
|
## Session Settings
|
package/index.js
CHANGED
|
@@ -6,18 +6,29 @@ const mbkautheVar = JSON.parse(process.env.mbkautheVar);
|
|
|
6
6
|
if (!mbkautheVar) {
|
|
7
7
|
throw new Error("mbkautheVar is not defined");
|
|
8
8
|
}
|
|
9
|
-
const requiredKeys = ["
|
|
9
|
+
const requiredKeys = ["APP_NAME", "RECAPTCHA_Enabled", "SESSION_SECRET_KEY", "IS_DEPLOYED", "LOGIN_DB", "MBKAUTH_TWO_FA_ENABLE", "DOMAIN"];
|
|
10
10
|
requiredKeys.forEach(key => {
|
|
11
11
|
if (!mbkautheVar[key]) {
|
|
12
12
|
throw new Error(`mbkautheVar.${key} is required`);
|
|
13
13
|
}
|
|
14
14
|
});
|
|
15
|
+
if (mbkautheVar.RECAPTCHA_Enabled === "true") {
|
|
16
|
+
if (mbkautheVar.RECAPTCHA_SECRET_KEY === undefined) {
|
|
17
|
+
throw new Error("mbkautheVar.RECAPTCHA_SECRET_KEY is required");
|
|
18
|
+
}
|
|
19
|
+
}
|
|
15
20
|
if (mbkautheVar.COOKIE_EXPIRE_TIME !== undefined) {
|
|
16
21
|
const expireTime = parseFloat(mbkautheVar.COOKIE_EXPIRE_TIME);
|
|
17
22
|
if (isNaN(expireTime) || expireTime <= 0) {
|
|
18
23
|
throw new Error("mbkautheVar.COOKIE_EXPIRE_TIME must be a valid positive number");
|
|
19
24
|
}
|
|
20
25
|
}
|
|
26
|
+
if (mbkautheVar.BypassUsers !== undefined) {
|
|
27
|
+
if (!Array.isArray(mbkautheVar.BypassUsers)) {
|
|
28
|
+
throw new Error("mbkautheVar.BypassUsers must be a valid array");
|
|
29
|
+
}
|
|
30
|
+
const BypassUsers = mbkautheVar.BypassUsers;
|
|
31
|
+
}
|
|
21
32
|
|
|
22
33
|
|
|
23
34
|
export { validateSession, checkRolePermission, validateSessionAndRole, getUserData, authenticate } from "./lib/validateSessionAndRole.js";
|
package/lib/main.js
CHANGED
|
@@ -8,134 +8,80 @@ import { authenticate } from "./validateSessionAndRole.js";
|
|
|
8
8
|
import fetch from 'node-fetch';
|
|
9
9
|
import cookieParser from "cookie-parser";
|
|
10
10
|
|
|
11
|
-
|
|
12
|
-
|
|
13
11
|
import dotenv from "dotenv";
|
|
14
12
|
dotenv.config();
|
|
15
13
|
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
14
|
|
|
33
15
|
const router = express.Router();
|
|
34
|
-
let COOKIE_EXPIRE_TIME = 2 * 24 * 60 * 60 * 1000; //2 days
|
|
16
|
+
let COOKIE_EXPIRE_TIME = 2 * 24 * 60 * 60 * 1000; // 2 days
|
|
35
17
|
|
|
36
18
|
try {
|
|
37
19
|
const parsedExpireTime = parseInt(mbkautheVar.COOKIE_EXPIRE_TIME, 10);
|
|
38
20
|
if (!isNaN(parsedExpireTime) && parsedExpireTime > 0) {
|
|
39
|
-
COOKIE_EXPIRE_TIME = parsedExpireTime * 24 * 60 * 60 * 1000;
|
|
21
|
+
COOKIE_EXPIRE_TIME = parsedExpireTime * 24 * 60 * 60 * 1000;
|
|
40
22
|
} else {
|
|
41
|
-
console.warn("Invalid COOKIE_EXPIRE_TIME
|
|
23
|
+
console.warn("Invalid COOKIE_EXPIRE_TIME, using default value");
|
|
42
24
|
}
|
|
43
|
-
console.log(`Cookie expiration time set to ${COOKIE_EXPIRE_TIME / (24 * 60 * 60 * 1000)} days for deployed environment`);
|
|
44
25
|
} catch (error) {
|
|
45
26
|
console.log("Error parsing COOKIE_EXPIRE_TIME:", error);
|
|
46
27
|
}
|
|
47
28
|
|
|
48
|
-
|
|
49
|
-
router.use(express.urlencoded({ extended: true }));
|
|
50
|
-
|
|
51
|
-
router.use(
|
|
52
|
-
session({
|
|
53
|
-
store: new PgSession({
|
|
54
|
-
pool: dblogin, // Connection pool
|
|
55
|
-
tableName: "session", // Use another table-name than the default "session" one
|
|
56
|
-
}),
|
|
57
|
-
secret: mbkautheVar.SESSION_SECRET_KEY, // Replace with your secret key
|
|
58
|
-
resave: false,
|
|
59
|
-
saveUninitialized: false,
|
|
60
|
-
cookie: {
|
|
61
|
-
maxAge: COOKIE_EXPIRE_TIME,
|
|
62
|
-
DOMAIN: mbkautheVar.IS_DEPLOYED === 'true' ? `.${mbkautheVar.DOMAIN}` : undefined, // Use root DOMAIN for subDOMAIN sharing
|
|
63
|
-
httpOnly: true,
|
|
64
|
-
secure: mbkautheVar.IS_DEPLOYED === 'true', // Use secure cookies in production
|
|
65
|
-
},
|
|
66
|
-
})
|
|
67
|
-
);
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
router.use(cookieParser()); // Use cookie-parser middleware
|
|
72
|
-
|
|
29
|
+
// Enable CORS for subdomains
|
|
73
30
|
router.use((req, res, next) => {
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
req.session.otherInfo = {
|
|
81
|
-
ip: formattedIp,
|
|
82
|
-
browser: userAgent,
|
|
83
|
-
};
|
|
84
|
-
|
|
85
|
-
next();
|
|
86
|
-
} else {
|
|
87
|
-
next();
|
|
31
|
+
const origin = req.headers.origin;
|
|
32
|
+
if (origin && origin.endsWith(`.${mbkautheVar.DOMAIN}`)) {
|
|
33
|
+
res.header('Access-Control-Allow-Origin', origin);
|
|
34
|
+
res.header('Access-Control-Allow-Credentials', 'true');
|
|
35
|
+
res.header('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE');
|
|
36
|
+
res.header('Access-Control-Allow-Headers', 'Content-Type, Authorization');
|
|
88
37
|
}
|
|
38
|
+
next();
|
|
89
39
|
});
|
|
90
40
|
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
41
|
+
router.use(express.json());
|
|
42
|
+
router.use(express.urlencoded({ extended: true }));
|
|
43
|
+
router.use(cookieParser());
|
|
44
|
+
|
|
45
|
+
// Configure session with proper domain settings
|
|
46
|
+
const sessionConfig = {
|
|
47
|
+
store: new PgSession({
|
|
48
|
+
pool: dblogin,
|
|
49
|
+
tableName: "session",
|
|
50
|
+
}),
|
|
51
|
+
secret: mbkautheVar.SESSION_SECRET_KEY,
|
|
52
|
+
resave: false,
|
|
53
|
+
saveUninitialized: false,
|
|
54
|
+
cookie: {
|
|
55
|
+
maxAge: COOKIE_EXPIRE_TIME,
|
|
56
|
+
domain: mbkautheVar.IS_DEPLOYED === 'true' ? `.${mbkautheVar.DOMAIN}` : undefined,
|
|
57
|
+
httpOnly: true,
|
|
58
|
+
secure: mbkautheVar.IS_DEPLOYED === 'true',
|
|
59
|
+
sameSite: 'lax',
|
|
60
|
+
},
|
|
61
|
+
name: 'mbkauthe.sid' // Unique session cookie name
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
router.use(session(sessionConfig));
|
|
65
|
+
|
|
66
|
+
// Middleware to handle session restoration from sessionId cookie
|
|
94
67
|
router.use(async (req, res, next) => {
|
|
95
|
-
if (req.session && req.
|
|
68
|
+
if (!req.session.user && req.cookies.sessionId) {
|
|
96
69
|
try {
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
});
|
|
101
|
-
|
|
102
|
-
const query = `SELECT "Role" FROM "Users" WHERE "UserName" = $1`;
|
|
103
|
-
const result = await dblogin.query(query, [req.session.user.username]);
|
|
70
|
+
const sessionId = req.cookies.sessionId;
|
|
71
|
+
const query = `SELECT * FROM "Users" WHERE "SessionId" = $1`;
|
|
72
|
+
const result = await dblogin.query(query, [sessionId]);
|
|
104
73
|
|
|
105
74
|
if (result.rows.length > 0) {
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
75
|
+
const user = result.rows[0];
|
|
76
|
+
req.session.user = {
|
|
77
|
+
id: user.id,
|
|
78
|
+
username: user.UserName,
|
|
79
|
+
sessionId,
|
|
80
|
+
};
|
|
81
|
+
console.log(`Session restored for user: ${user.UserName}`);
|
|
112
82
|
}
|
|
113
|
-
} catch (
|
|
114
|
-
console.
|
|
115
|
-
req.session.user.role = null; // Fallback to null role
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
|
-
next();
|
|
119
|
-
});
|
|
120
|
-
|
|
121
|
-
router.use(async (req, res, next) => {
|
|
122
|
-
// Check for sessionId cookie if session is not initialized
|
|
123
|
-
if (!req.session.user && req.cookies && req.cookies.sessionId) {
|
|
124
|
-
console.log("Restoring session from sessionId cookie"); // Log session restoration
|
|
125
|
-
const sessionId = req.cookies.sessionId;
|
|
126
|
-
const query = `SELECT * FROM "Users" WHERE "SessionId" = $1`;
|
|
127
|
-
const result = await dblogin.query(query, [sessionId]);
|
|
128
|
-
|
|
129
|
-
if (result.rows.length > 0) {
|
|
130
|
-
const user = result.rows[0];
|
|
131
|
-
req.session.user = {
|
|
132
|
-
id: user.id,
|
|
133
|
-
username: user.UserName,
|
|
134
|
-
sessionId,
|
|
135
|
-
};
|
|
136
|
-
console.log(`Session restored for user: ${user.UserName}`); // Log successful session restoration
|
|
137
|
-
} else {
|
|
138
|
-
console.warn("No matching session found for sessionId"); // Log if no session is found
|
|
83
|
+
} catch (err) {
|
|
84
|
+
console.error("Session restoration error:", err);
|
|
139
85
|
}
|
|
140
86
|
}
|
|
141
87
|
next();
|
|
@@ -182,26 +128,26 @@ router.post("/mbkauthe/api/login", async (req, res) => {
|
|
|
182
128
|
const secretKey = mbkautheVar.RECAPTCHA_SECRET_KEY;
|
|
183
129
|
const verificationUrl = `https://www.google.com/recaptcha/api/siteverify?secret=${secretKey}&response=${recaptcha}`;
|
|
184
130
|
|
|
185
|
-
let BypassUsers = [
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
131
|
+
let BypassUsers = [mbkautheVar.BypassUsers];
|
|
132
|
+
if (mbkautheVar.RECAPTCHA_Enabled === "true") {
|
|
133
|
+
if (!BypassUsers.includes(username)) {
|
|
134
|
+
if (!recaptcha) {
|
|
135
|
+
console.log("Missing reCAPTCHA token");
|
|
136
|
+
return res.status(400).json({ success: false, message: "Please complete the reCAPTCHA" });
|
|
137
|
+
}
|
|
138
|
+
try {
|
|
139
|
+
const response = await fetch(verificationUrl, { method: 'POST' });
|
|
140
|
+
const body = await response.json();
|
|
141
|
+
console.log("reCAPTCHA verification response:", body); // Log reCAPTCHA response
|
|
142
|
+
|
|
143
|
+
if (!body.success) {
|
|
144
|
+
console.log("Failed reCAPTCHA verification");
|
|
145
|
+
return res.status(400).json({ success: false, message: "Failed reCAPTCHA verification" });
|
|
146
|
+
}
|
|
147
|
+
} catch (err) {
|
|
148
|
+
console.log("Error during reCAPTCHA verification:", err);
|
|
149
|
+
return res.status(500).json({ success: false, message: "Internal Server Error" });
|
|
201
150
|
}
|
|
202
|
-
} catch (err) {
|
|
203
|
-
console.log("Error during reCAPTCHA verification:", err);
|
|
204
|
-
return res.status(500).json({ success: false, message: "Internal Server Error" });
|
|
205
151
|
}
|
|
206
152
|
}
|
|
207
153
|
|
|
@@ -238,6 +184,18 @@ router.post("/mbkauthe/api/login", async (req, res) => {
|
|
|
238
184
|
return res.status(403).json({ success: false, message: "Account is inactive" });
|
|
239
185
|
}
|
|
240
186
|
|
|
187
|
+
|
|
188
|
+
if (mbkautheVar.test === "true") {
|
|
189
|
+
// Check if the user is authorized to use the application
|
|
190
|
+
if (result.rows[0].Role !== "SuperAdmin") {
|
|
191
|
+
const allowedApps = result.rows[0].AllowedApps;
|
|
192
|
+
if (!allowedApps || !allowedApps.includes(mbkautheVar.APP_NAME)) {
|
|
193
|
+
console.warn(`User \"${req.session.user.username}\" is not authorized to use the application \"${mbkautheVar.APP_NAME}\"`);
|
|
194
|
+
return res.status(403).json({ success: false, message: `You are not authorized to use the application \"${mbkautheVar.APP_NAME}\"` });
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
|
|
241
199
|
if ((mbkautheVar.MBKAUTH_TWO_FA_ENABLE || "").toLocaleLowerCase() === "true") {
|
|
242
200
|
let sharedSecret;
|
|
243
201
|
const query = `SELECT "TwoFAStatus", "TwoFASecret" FROM "TwoFA" WHERE "UserName" = $1`;
|
package/lib/pool.js
CHANGED
|
@@ -1,25 +1,9 @@
|
|
|
1
1
|
import pkg from "pg";
|
|
2
2
|
const { Pool } = pkg;
|
|
3
3
|
|
|
4
|
-
|
|
5
4
|
import dotenv from "dotenv";
|
|
6
5
|
dotenv.config();
|
|
7
6
|
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
|
-
}
|
|
23
7
|
|
|
24
8
|
// PostgreSQL connection pool for pool
|
|
25
9
|
const poolConfig = {
|
|
@@ -1,6 +1,28 @@
|
|
|
1
1
|
import { dblogin } from "./pool.js";
|
|
2
|
+
const mbkautheVar = JSON.parse(process.env.mbkautheVar);
|
|
2
3
|
|
|
3
4
|
async function validateSession(req, res, next) {
|
|
5
|
+
// First check if we have a session cookie
|
|
6
|
+
if (!req.session.user && req.cookies.sessionId) {
|
|
7
|
+
try {
|
|
8
|
+
const sessionId = req.cookies.sessionId;
|
|
9
|
+
const query = `SELECT * FROM "Users" WHERE "SessionId" = $1`;
|
|
10
|
+
const result = await dblogin.query(query, [sessionId]);
|
|
11
|
+
|
|
12
|
+
if (result.rows.length > 0) {
|
|
13
|
+
const user = result.rows[0];
|
|
14
|
+
req.session.user = {
|
|
15
|
+
id: user.id,
|
|
16
|
+
username: user.UserName,
|
|
17
|
+
sessionId,
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
} catch (err) {
|
|
21
|
+
console.error("Session validation error:", err);
|
|
22
|
+
return res.status(500).json({ success: false, message: "Internal Server Error" });
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
4
26
|
if (!req.session.user) {
|
|
5
27
|
return res.render("templates/Error/NotLoggedIn.handlebars", {
|
|
6
28
|
currentUrl: req.originalUrl,
|
|
@@ -12,37 +34,49 @@ async function validateSession(req, res, next) {
|
|
|
12
34
|
const query = `SELECT "SessionId", "Active" FROM "Users" WHERE "id" = $1`;
|
|
13
35
|
const result = await dblogin.query(query, [id]);
|
|
14
36
|
|
|
15
|
-
// Check if user exists and session ID matches
|
|
16
37
|
if (result.rows.length === 0 || result.rows[0].SessionId !== sessionId) {
|
|
17
|
-
console.log(
|
|
18
|
-
`Session invalidated for user \"${req.session.user.username}\"`
|
|
19
|
-
);
|
|
38
|
+
console.log(`Session invalidated for user "${req.session.user.username}"`);
|
|
20
39
|
req.session.destroy();
|
|
21
|
-
|
|
40
|
+
res.clearCookie("mbkauthe.sid", { domain: `.${mbkautheVar.DOMAIN}` });
|
|
41
|
+
res.clearCookie("sessionId", { domain: `.${mbkautheVar.DOMAIN}` });
|
|
22
42
|
return res.render("templates/Error/SessionExpire.handlebars", {
|
|
23
43
|
currentUrl: req.originalUrl,
|
|
24
44
|
});
|
|
25
|
-
// ...existing code...
|
|
26
45
|
}
|
|
27
46
|
|
|
28
|
-
// Check if the user account is inactive
|
|
29
47
|
if (!result.rows[0].Active) {
|
|
30
|
-
console.log(
|
|
31
|
-
`Account is inactive for user \"${req.session.user.username}\"`
|
|
32
|
-
);
|
|
48
|
+
console.log(`Account is inactive for user "${req.session.user.username}"`);
|
|
33
49
|
req.session.destroy();
|
|
34
|
-
res.clearCookie("
|
|
50
|
+
res.clearCookie("mbkauthe.sid", { domain: `.${mbkautheVar.DOMAIN}` });
|
|
51
|
+
res.clearCookie("sessionId", { domain: `.${mbkautheVar.DOMAIN}` });
|
|
35
52
|
return res.render("templates/Error/AccountInactive.handlebars", {
|
|
36
53
|
currentUrl: req.originalUrl,
|
|
37
54
|
});
|
|
38
55
|
}
|
|
39
56
|
|
|
40
|
-
|
|
57
|
+
if (mbkautheVar.test === "true") {
|
|
58
|
+
if (result.rows[0].Role !== "SuperAdmin") {
|
|
59
|
+
const allowedApps = result.rows[0].AllowedApps;
|
|
60
|
+
if (!allowedApps || !allowedApps.includes(mbkautheVar.APP_NAME)) {
|
|
61
|
+
console.warn(
|
|
62
|
+
`User \"${req.session.user.username}\" is not authorized to use the application \"${mbkautheVar.APP_NAME}\"`
|
|
63
|
+
);
|
|
64
|
+
req.session.destroy();
|
|
65
|
+
res.clearCookie("connect.sid");
|
|
66
|
+
return res.render("templates/Error/AccountInactive.handlebars", {
|
|
67
|
+
currentUrl: req.originalUrl,
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
next();
|
|
41
75
|
} catch (err) {
|
|
42
76
|
console.error("Session validation error:", err);
|
|
43
77
|
res.status(500).json({ success: false, message: "Internal Server Error" });
|
|
44
78
|
}
|
|
45
|
-
}
|
|
79
|
+
}
|
|
46
80
|
|
|
47
81
|
const checkRolePermission = (requiredRole) => {
|
|
48
82
|
return async (req, res, next) => {
|
|
@@ -86,7 +120,7 @@ const checkRolePermission = (requiredRole) => {
|
|
|
86
120
|
.json({ success: false, message: "Internal Server Error" });
|
|
87
121
|
}
|
|
88
122
|
};
|
|
89
|
-
};
|
|
123
|
+
};
|
|
90
124
|
|
|
91
125
|
const validateSessionAndRole = (requiredRole) => {
|
|
92
126
|
return async (req, res, next) => {
|
|
@@ -163,4 +197,4 @@ const authenticate = (authentication) => {
|
|
|
163
197
|
};
|
|
164
198
|
};
|
|
165
199
|
|
|
166
|
-
export { validateSession, checkRolePermission, validateSessionAndRole, getUserData
|
|
200
|
+
export { validateSession, checkRolePermission, validateSessionAndRole, getUserData, authenticate };
|