mbkauthe 1.0.7 → 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 +31 -37
- package/lib/pool.js +0 -16
- package/lib/validateSessionAndRole.js +18 -0
- 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,27 +8,9 @@ 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
16
|
let COOKIE_EXPIRE_TIME = 2 * 24 * 60 * 60 * 1000; // 2 days
|
|
@@ -146,26 +128,26 @@ router.post("/mbkauthe/api/login", async (req, res) => {
|
|
|
146
128
|
const secretKey = mbkautheVar.RECAPTCHA_SECRET_KEY;
|
|
147
129
|
const verificationUrl = `https://www.google.com/recaptcha/api/siteverify?secret=${secretKey}&response=${recaptcha}`;
|
|
148
130
|
|
|
149
|
-
let BypassUsers = [
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
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" });
|
|
165
150
|
}
|
|
166
|
-
} catch (err) {
|
|
167
|
-
console.log("Error during reCAPTCHA verification:", err);
|
|
168
|
-
return res.status(500).json({ success: false, message: "Internal Server Error" });
|
|
169
151
|
}
|
|
170
152
|
}
|
|
171
153
|
|
|
@@ -202,6 +184,18 @@ router.post("/mbkauthe/api/login", async (req, res) => {
|
|
|
202
184
|
return res.status(403).json({ success: false, message: "Account is inactive" });
|
|
203
185
|
}
|
|
204
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
|
+
|
|
205
199
|
if ((mbkautheVar.MBKAUTH_TWO_FA_ENABLE || "").toLocaleLowerCase() === "true") {
|
|
206
200
|
let sharedSecret;
|
|
207
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,4 +1,5 @@
|
|
|
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) {
|
|
4
5
|
// First check if we have a session cookie
|
|
@@ -53,6 +54,23 @@ async function validateSession(req, res, next) {
|
|
|
53
54
|
});
|
|
54
55
|
}
|
|
55
56
|
|
|
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
|
+
|
|
56
74
|
next();
|
|
57
75
|
} catch (err) {
|
|
58
76
|
console.error("Session validation error:", err);
|