mbkauthe 1.0.4 → 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 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
@@ -4,9 +4,16 @@ on:
4
4
  branches:
5
5
  - main
6
6
 
7
+ permissions:
8
+ contents: read
9
+ packages: write
10
+
7
11
  jobs:
8
12
  publish:
9
13
  runs-on: ubuntu-latest
14
+ permissions:
15
+ contents: read
16
+ packages: write
10
17
  steps:
11
18
  - name: Checkout code
12
19
  uses: actions/checkout@v3
package/README.md CHANGED
@@ -1 +1,123 @@
1
- # mbkauthe
1
+ # mbkauthe
2
+
3
+ [![Publish to npm](https://github.com/MIbnEKhalid/mbkauthe/actions/workflows/publish.yml/badge.svg?branch=main)](https://github.com/MIbnEKhalid/mbkauthe/actions/workflows/publish.yml) [![CodeQL Advanced](https://github.com/MIbnEKhalid/mbkauthe/actions/workflows/codeql.yml/badge.svg?branch=main)](https://github.com/MIbnEKhalid/mbkauthe/actions/workflows/codeql.yml)
4
+
5
+ ## Table of Contents
6
+
7
+ - [Introduction](#mbkauth)
8
+ - [Features](#features)
9
+ - [Installation](#installation)
10
+ - [Usage](#usage)
11
+ - [Basic Setup](#basic-setup)
12
+ - [API Endpoints](#api-endpoints)
13
+ - [Login](#login)
14
+ - [Logout](#logout)
15
+ - [Terminate All Sessions](#terminate-all-sessions)
16
+ - [Database Structure](#database-structure)
17
+ - [License](#license)
18
+ - [Contact & Support](#contact--support)
19
+
20
+ `mbkAuthe` is a reusable authentication system for Node.js applications, designed to simplify session management, user authentication, and role-based access control. It integrates seamlessly with PostgreSQL and supports features like Two-Factor Authentication (2FA), session restoration, and reCAPTCHA verification.
21
+
22
+ ## Features
23
+
24
+ - **Session Management**: Secure session handling using `express-session` and `connect-pg-simple`.
25
+ - **Role-Based Access Control**: Validate user roles and permissions with ease.
26
+ - **Two-Factor Authentication (2FA)**: Optional 2FA support for enhanced security.
27
+ - **reCAPTCHA Integration**: Protect login endpoints with Google reCAPTCHA.
28
+ - **Cookie Management**: Configurable cookie expiration and domain settings.
29
+ - **PostgreSQL Integration**: Uses a connection pool for efficient database interactions.
30
+
31
+ ## Installation
32
+
33
+ Install the package via npm:
34
+
35
+ ```bash
36
+ npm install mbkauthe
37
+ ```
38
+
39
+ ## Usage
40
+ ### Basic Setup
41
+ 1. Import and configure the router in your Express application:
42
+ ```javascript
43
+ import express from "express";
44
+ import mbkAuthRouter from "mbkauthe";
45
+
46
+ const app = express();
47
+
48
+ app.use(mbkAuthRouter);
49
+
50
+ app.listen(3000, () => {
51
+ console.log("Server is running on port 3000");
52
+ });
53
+ ```
54
+ 2. Ensure your ``.env` file is properly configured. Refer to the [Configuration Guide(env.md)](env.md) for details.
55
+
56
+ Example `.env` file:
57
+ ```code
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
+ }'
67
+ ```
68
+
69
+ ## API Endpoints
70
+
71
+ ### Login
72
+
73
+ **POST** `/mbkauth/api/login`
74
+ - Request Body:
75
+ - `username`: User's username.
76
+ - `password`: User's password.
77
+ - `token`: (Optional) 2FA token.
78
+ - `recaptcha`: reCAPTCHA response.
79
+
80
+ - Response:
81
+ - `200`: Login successful.
82
+ - `400`: Missing or invalid input.
83
+ - `401`: Unauthorized (e.g., invalid credentials or 2FA token).
84
+ - `500`: Internal server error.
85
+
86
+ ### Logout
87
+
88
+ **POST** `/mbkauth/api/logout`
89
+ - Response:
90
+ - `200`: Login successful.
91
+ - `400`: User not logged in.
92
+ - `500`: Internal server error.
93
+
94
+ ### Terminate All Sessions
95
+
96
+ **POST** `/mbkauth/api/terminateAllSessions`
97
+ - Authentication: Requires a valid `Main_SECRET_TOKEN` in the `Authorization` header.
98
+ - Response:
99
+ - `200`: All sessions terminated successfully.
100
+ - `500`: Internal server error.
101
+ -
102
+
103
+
104
+ ## Database Structure
105
+
106
+ This project utilizes three primary tables:
107
+
108
+ 1. **User**: Stores the main user information.
109
+ 2. **sess**: Contains session-related data for users.
110
+ 3. **TwoFA**: Saves the Two-Factor Authentication (2FA) secrets for users.
111
+
112
+ For detailed information about table columns, schema, and queries to create these tables, refer to the [Database Guide (docs/db.md)](docs/db.md).
113
+
114
+ ## License
115
+ This project is licensed under the `Mozilla Public License 2.0`. See the [LICENSE](./LICENSE) file for details.
116
+
117
+
118
+
119
+ ## Contact & Support
120
+
121
+ For questions or contributions, please contact Muhammad Bin Khalid at [mbktechstudio.com/Support](https://mbktechstudio.com/Support/), [support@mbktechstudio.com](mailto:support@mbktechstudio.com) or [chmuhammadbinkhalid28.com](mailto:chmuhammadbinkhalid28.com).
122
+
123
+ **Developed by [Muhammad Bin Khalid](https://github.com/MIbnEKhalid)**
package/docs/db.md ADDED
@@ -0,0 +1,90 @@
1
+ ## Database structure
2
+
3
+ [<- Back](README.md)
4
+
5
+ ## Table of Contents
6
+
7
+ 1. [Users Table](#users-table)
8
+ 2. [Session Table](#session-table)
9
+ 3. [Two-Factor Authentication Table](#two-factor-authentication-table)
10
+ 4. [Query to Add a User](#query-to-add-a-user)
11
+
12
+
13
+ ### Users Table
14
+
15
+ - **Columns:**
16
+
17
+ - `id` (INTEGER, auto-increment, primary key): Unique identifier for each user.
18
+ - `UserName` (TEXT): The username of the user.
19
+ - `Password` (TEXT): The hashed password of the user.
20
+ - `Role` (ENUM): The role of the user. Possible values: `SuperAdmin`, `NormalUser`, `Guest`.
21
+ - `Active` (BOOLEAN): Indicates whether the user account is active.
22
+ - `HaveMailAccount` (BOOLEAN)(optional): Indicates if the user has a linked mail account.
23
+ - `SessionId` (TEXT): The session ID associated with the user.
24
+ - `GuestRole` (JSONB): Stores additional guest-specific role information in binary JSON format.
25
+
26
+ - **Schema:**
27
+ ```sql
28
+ CREATE TABLE "Users" (
29
+ id INTEGER PRIMARY KEY GENERATED ALWAYS AS IDENTITY,
30
+ "UserName" TEXT NOT NULL,
31
+ "Password" TEXT NOT NULL,
32
+ "Role" TEXT CHECK("Role" IN ('SuperAdmin', 'NormalUser', 'Guest')) NOT NULL DEFAULT 'NormalUser'::text,
33
+ "Active" BOOLEAN NOT NULL DEFAULT true,
34
+ "HaveMailAccount" BOOLEAN NOT NULL DEFAULT false,
35
+ "SessionId" TEXT,
36
+ "GuestRole" JSONB DEFAULT '{"allowPages": [""], "NotallowPages": [""]}'::jsonb
37
+ );
38
+ ```
39
+
40
+ ### Session Table
41
+
42
+ - **Columns:**
43
+
44
+ - `sid` (VARCHAR, primary key): Unique session identifier.
45
+ - `sess` (JSON): Session data stored in JSON format.
46
+ - `expire` (TIMESTAMP): Expiration timestamp for the session.
47
+
48
+ - **Schema:**
49
+ ```sql
50
+ CREATE TABLE session (
51
+ sid VARCHAR PRIMARY KEY,
52
+ sess JSON NOT NULL,
53
+ expire TIMESTAMP NOT NULL
54
+ );
55
+ ```
56
+
57
+ ### Two-Factor Authentication Table
58
+
59
+ - **Columns:**
60
+
61
+ - `UserName` (TEXT): The username of the user.
62
+ - `TwoFAStatus` (TEXT): The status of two-factor authentication (e.g., enabled, disabled).
63
+ - `TwoFASecret` (TEXT): The secret key used for two-factor authentication.
64
+
65
+ - **Schema:**
66
+ ```sql
67
+ CREATE TABLE "TwoFA" (
68
+ "UserName" TEXT NOT NULL PRIMARY KEY,
69
+ "TwoFAStatus" TEXT NOT NULL DEFAULT false,
70
+ "TwoFASecret" TEXT NOT NULL
71
+ );
72
+ ```
73
+
74
+ ### Query to Add a User
75
+
76
+ To add new users to the `Users` table, use the following SQL queries:
77
+
78
+ ```sql
79
+ INSERT INTO "Users" ("UserName", "Password", "Role", "Active", "HaveMailAccount", "SessionId", "GuestRole")
80
+ VALUES ('support', '12345678', 'SuperAdmin', true, false, NULL, '{"allowPages": [""], "NotallowPages": [""]}'::jsonb);
81
+
82
+ INSERT INTO "Users" ("UserName", "Password", "Role", "Active", "HaveMailAccount", "SessionId", "GuestRole")
83
+ VALUES ('test', '12345678', 'NormalUser', true, false, NULL, '{"allowPages": [""], "NotallowPages": [""]}'::jsonb);
84
+ ```
85
+
86
+ - Replace `support` and `test` with the desired usernames.
87
+ - Replace `12345678` with the actual passwords.
88
+ - Adjust the `Role` values as needed (`SuperAdmin`, `NormalUser`, or `Guest`).
89
+ - Modify the `Active` and `HaveMailAccount` values as required.
90
+ - Update the `GuestRole` JSON object if specific permissions are required(this functionality is under construction).
package/env.md ADDED
@@ -0,0 +1,55 @@
1
+ # Configuration Guide
2
+
3
+ [<- Back](README.md)
4
+
5
+ ## reCAPTCHA Settings
6
+ ```properties
7
+ RECAPTCHA_SECRET_KEY=123
8
+ ```
9
+ > Note: Obtain your secret key from Google reCAPTCHA Admin Console.
10
+
11
+
12
+ ## Session Settings
13
+ ```properties
14
+ SESSION_SECRET_KEY=123
15
+ IS_DEPLOYED=true
16
+ DOMAIN=mbktechstudio.com
17
+ ```
18
+ > **SESSION_SECRET_KEY**: Generate a secure key using [Generate Secret](https://generate-secret.vercel.app/32).
19
+
20
+ > **IS_DEPLOYED**:
21
+
22
+ > - `true`: For deployed environments. Sessions are shared across all subDOMAINs of `.mbktechstudio.com` or the DOMAIN specified in `DOMAIN`.
23
+
24
+ > - `false`: For local development.
25
+
26
+ > - Important: If set to `true`, login functionality will not work on `localhost`. Use a valid DOMAIN for proper operation.
27
+
28
+ > **DOMAIN**:
29
+
30
+ > - Set `DOMAIN` to your DOMAIN
31
+
32
+ > - If you don't have a DOMAIN, set `IS_DEPLOYED=false`.
33
+
34
+
35
+ ## Database Settings
36
+
37
+ ```properties
38
+ LOGIN_DB=postgresql://username:password@server.DOMAIN/db_name
39
+ ```
40
+ > Replace the placeholder with your PostgreSQL connection string.
41
+
42
+
43
+ ## Two-Factor Authentication (2FA)
44
+ ```properties
45
+ MBKAUTH_TWO_FA_ENABLE=false
46
+ ```
47
+ > MBKAUTH_TWO_FA_ENABLE: Set to `true` to enable Two-Factor Authentication.
48
+
49
+
50
+ ## Cookie Settings
51
+
52
+ ```properties
53
+ COOKIE_EXPIRE_TIME=5
54
+ ```
55
+ > Cookie expiration time in days. Default is `2 days`.
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
- const { error } = envSchema.validate(process.env);
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,42 +3,48 @@ 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 "./auth.js";
7
+ import { authenticate } from "./validateSessionAndRole.js";
9
8
  import fetch from 'node-fetch';
10
- import cookieParser from "cookie-parser"; // Import 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(process.env.COOKIE_EXPIRE_TIME, 10);
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
- WriteConsoleLogs(`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
- WriteConsoleLogs("Error parsing COOKIE_EXPIRE_TIME:", error);
45
+ console.log("Error parsing COOKIE_EXPIRE_TIME:", error);
26
46
  }
27
47
 
28
- async function WriteConsoleLogs(message) {
29
- const appName = process.env.AppName;
30
- try {
31
- const query = `
32
- INSERT INTO mbkauthlogs (app_name, message)
33
- VALUES ($1, $2)
34
- `;
35
- await dblogin.query(query, [appName, message]);
36
- console.log(`Logged message: ${message}`);
37
- } catch (error) {
38
- console.error("Error logging message:", error.message);
39
- }
40
- }
41
-
42
48
  router.use(express.json());
43
49
  router.use(express.urlencoded({ extended: true }));
44
50
 
@@ -48,14 +54,14 @@ router.use(
48
54
  pool: dblogin, // Connection pool
49
55
  tableName: "session", // Use another table-name than the default "session" one
50
56
  }),
51
- secret: process.env.SESSION_SECRET_KEY, // Replace with your secret key
57
+ secret: mbkautheVar.SESSION_SECRET_KEY, // Replace with your secret key
52
58
  resave: false,
53
59
  saveUninitialized: false,
54
60
  cookie: {
55
61
  maxAge: COOKIE_EXPIRE_TIME,
56
- DOMAIN: process.env.IS_DEPLOYED === 'true' ? `.${process.env.DOMAIN}` : undefined, // Use root DOMAIN for subDOMAIN sharing
62
+ DOMAIN: mbkautheVar.IS_DEPLOYED === 'true' ? `.${mbkautheVar.DOMAIN}` : undefined, // Use root DOMAIN for subDOMAIN sharing
57
63
  httpOnly: true,
58
- secure: process.env.IS_DEPLOYED === 'true', // Use secure cookies in production
64
+ secure: mbkautheVar.IS_DEPLOYED === 'true', // Use secure cookies in production
59
65
  },
60
66
  })
61
67
  );
@@ -105,7 +111,7 @@ router.use(async (req, res, next) => {
105
111
  req.session.user.role = null;
106
112
  }
107
113
  } catch (error) {
108
- WriteConsoleLogs("Error fetching user role:", error.message);
114
+ console.log("Error fetching user role:", error.message);
109
115
  req.session.user.role = null; // Fallback to null role
110
116
  }
111
117
  }
@@ -115,7 +121,7 @@ router.use(async (req, res, next) => {
115
121
  router.use(async (req, res, next) => {
116
122
  // Check for sessionId cookie if session is not initialized
117
123
  if (!req.session.user && req.cookies && req.cookies.sessionId) {
118
- WriteConsoleLogs("Restoring session from sessionId cookie"); // Log session restoration
124
+ console.log("Restoring session from sessionId cookie"); // Log session restoration
119
125
  const sessionId = req.cookies.sessionId;
120
126
  const query = `SELECT * FROM "Users" WHERE "SessionId" = $1`;
121
127
  const result = await dblogin.query(query, [sessionId]);
@@ -127,7 +133,7 @@ router.use(async (req, res, next) => {
127
133
  username: user.UserName,
128
134
  sessionId,
129
135
  };
130
- WriteConsoleLogs(`Session restored for user: ${user.UserName}`); // Log successful session restoration
136
+ console.log(`Session restored for user: ${user.UserName}`); // Log successful session restoration
131
137
  } else {
132
138
  console.warn("No matching session found for sessionId"); // Log if no session is found
133
139
  }
@@ -137,7 +143,7 @@ router.use(async (req, res, next) => {
137
143
 
138
144
  //Invoke-RestMethod -Uri http://localhost:3030/terminateAllSessions -Method POST
139
145
  // Terminate all sessions route
140
- router.post("/mbkauthe/api/terminateAllSessions", authenticate(process.env.Main_SECRET_TOKEN), async (req, res) => {
146
+ router.post("/mbkauthe/api/terminateAllSessions", authenticate(mbkautheVar.Main_SECRET_TOKEN), async (req, res) => {
141
147
  try {
142
148
  await dblogin.query(`UPDATE "Users" SET "SessionId" = NULL`);
143
149
 
@@ -147,19 +153,19 @@ router.post("/mbkauthe/api/terminateAllSessions", authenticate(process.env.Main_
147
153
  // Destroy all sessions on the server
148
154
  req.session.destroy((err) => {
149
155
  if (err) {
150
- WriteConsoleLogs("Error destroying session:", err);
156
+ console.log("Error destroying session:", err);
151
157
  return res
152
158
  .status(500)
153
159
  .json({ success: false, message: "Failed to terminate sessions" });
154
160
  }
155
- WriteConsoleLogs("All sessions terminated successfully");
161
+ console.log("All sessions terminated successfully");
156
162
  res.status(200).json({
157
163
  success: true,
158
164
  message: "All sessions terminated successfully",
159
165
  });
160
166
  });
161
167
  } catch (err) {
162
- WriteConsoleLogs("Database query error during session termination:", err);
168
+ console.log("Database query error during session termination:", err);
163
169
  res
164
170
  .status(500)
165
171
  .json({ success: false, message: "Internal Server Error" });
@@ -168,55 +174,53 @@ router.post("/mbkauthe/api/terminateAllSessions", authenticate(process.env.Main_
168
174
  );
169
175
 
170
176
  router.post("/mbkauthe/api/login", async (req, res) => {
171
- WriteConsoleLogs("Login request received"); // Log when login is initiated
177
+ console.log("Login request received"); // Log when login is initiated
172
178
 
173
179
  const { username, password, token, recaptcha } = req.body;
174
- WriteConsoleLogs(`Login attempt for username: ${username}`); // Log username
180
+ console.log(`Login attempt for username: ${username}`); // Log username
175
181
 
176
- const secretKey = process.env.RECAPTCHA_SECRET_KEY;
182
+ const secretKey = mbkautheVar.RECAPTCHA_SECRET_KEY;
177
183
  const verificationUrl = `https://www.google.com/recaptcha/api/siteverify?secret=${secretKey}&response=${recaptcha}`;
178
184
 
185
+ let BypassUsers = ["ibnekhalid", "maaz.waheed", "support"];
186
+
179
187
  // Bypass recaptcha for specific users
180
- if (username !== "ibnekhalid" && username !== "maaz.waheed" && username !== "support") {
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
+ }
181
193
  try {
182
194
  const response = await fetch(verificationUrl, { method: 'POST' });
183
195
  const body = await response.json();
184
- WriteConsoleLogs("reCAPTCHA verification response:", body); // Log reCAPTCHA response
196
+ console.log("reCAPTCHA verification response:", body); // Log reCAPTCHA response
185
197
 
186
198
  if (!body.success) {
187
- WriteConsoleLogs("Failed reCAPTCHA verification");
199
+ console.log("Failed reCAPTCHA verification");
188
200
  return res.status(400).json({ success: false, message: "Failed reCAPTCHA verification" });
189
201
  }
190
202
  } catch (err) {
191
- WriteConsoleLogs("Error during reCAPTCHA verification:", err);
203
+ console.log("Error during reCAPTCHA verification:", err);
192
204
  return res.status(500).json({ success: false, message: "Internal Server Error" });
193
205
  }
194
206
  }
195
207
 
196
208
  if (!username || !password) {
197
- WriteConsoleLogs("Missing username or password");
209
+ console.log("Missing username or password");
198
210
  return res.status(400).json({
199
211
  success: false,
200
212
  message: "Username and password are required",
201
213
  });
202
214
  }
203
215
 
204
- WriteConsoleLogs("RECAPTCHA_SECRET_KEY:", process.env.RECAPTCHA_SECRET_KEY); // Log reCAPTCHA secret key
205
- WriteConsoleLogs("SESSION_SECRET_KEY:", process.env.SESSION_SECRET_KEY); // Log reCAPTCHA secret key
206
- WriteConsoleLogs("LOGIN_DB:", process.env.LOGIN_DB); // Log reCAPTCHA secret key
207
- WriteConsoleLogs("COOKIE_EXPIRE_TIME:", process.env.COOKIE_EXPIRE_TIME); // Log reCAPTCHA secret key
208
- WriteConsoleLogs("DOMAIN:", process.env.DOMAIN); // Log reCAPTCHA secret key
209
- WriteConsoleLogs("IS_DEPLOYED:", process.env.IS_DEPLOYED); // Log reCAPTCHA secret key
210
- WriteConsoleLogs("MBKAUTH_TWO_FA_ENABLE:", process.env.MBKAUTH_TWO_FA_ENABLE); // Log reCAPTCHA secret key
211
-
212
216
  try {
213
217
  // Query to check if the username exists
214
218
  const userQuery = `SELECT * FROM "Users" WHERE "UserName" = $1`;
215
219
  const userResult = await dblogin.query(userQuery, [username]);
216
- WriteConsoleLogs("User query result:", userResult.rows); // Log user query result
220
+ console.log("User query result:", userResult.rows); // Log user query result
217
221
 
218
222
  if (userResult.rows.length === 0) {
219
- WriteConsoleLogs(`Username does not exist: ${username}`);
223
+ console.log(`Username does not exist: ${username}`);
220
224
  return res.status(404).json({ success: false, message: "Username does not exist" });
221
225
  }
222
226
 
@@ -224,25 +228,25 @@ router.post("/mbkauthe/api/login", async (req, res) => {
224
228
 
225
229
  // Check if the password matches
226
230
  if (user.Password !== password) {
227
- WriteConsoleLogs(`Incorrect password for username: ${username}`);
231
+ console.log(`Incorrect password for username: ${username}`);
228
232
  return res.status(401).json({ success: false, message: "Incorrect password" });
229
233
  }
230
234
 
231
235
  // Check if the account is inactive
232
236
  if (!user.Active) {
233
- WriteConsoleLogs(`Inactive account for username: ${username}`);
237
+ console.log(`Inactive account for username: ${username}`);
234
238
  return res.status(403).json({ success: false, message: "Account is inactive" });
235
239
  }
236
240
 
237
- if ((process.env.MBKAUTH_TWO_FA_ENABLE || "").toLocaleLowerCase() === "true") {
241
+ if ((mbkautheVar.MBKAUTH_TWO_FA_ENABLE || "").toLocaleLowerCase() === "true") {
238
242
  let sharedSecret;
239
243
  const query = `SELECT "TwoFAStatus", "TwoFASecret" FROM "TwoFA" WHERE "UserName" = $1`;
240
244
  const twoFAResult = await dblogin.query(query, [username]);
241
- WriteConsoleLogs("TwoFA query result:", twoFAResult.rows); // Log TwoFA query result
245
+ console.log("TwoFA query result:", twoFAResult.rows); // Log TwoFA query result
242
246
 
243
247
  sharedSecret = twoFAResult.rows[0]?.TwoFASecret;
244
248
  if (twoFAResult.rows.length > 0 && twoFAResult.rows[0].TwoFAStatus && !token) {
245
- WriteConsoleLogs("2FA code required but not provided");
249
+ console.log("2FA code required but not provided");
246
250
  return res.status(401).json({ success: false, message: "Please Enter 2FA code" });
247
251
  }
248
252
 
@@ -255,7 +259,7 @@ router.post("/mbkauthe/api/login", async (req, res) => {
255
259
  });
256
260
 
257
261
  if (!tokenValidates) {
258
- WriteConsoleLogs(`Invalid 2FA code for username: ${username}`);
262
+ console.log(`Invalid 2FA code for username: ${username}`);
259
263
  return res.status(401).json({ success: false, message: "Invalid 2FA code" });
260
264
  }
261
265
  }
@@ -263,7 +267,7 @@ router.post("/mbkauthe/api/login", async (req, res) => {
263
267
 
264
268
  // Generate session ID
265
269
  const sessionId = crypto.randomBytes(256).toString("hex");
266
- WriteConsoleLogs(`Generated session ID for username: ${username}`); // Log session ID
270
+ console.log(`Generated session ID for username: ${username}`); // Log session ID
267
271
 
268
272
  await dblogin.query(`UPDATE "Users" SET "SessionId" = $1 WHERE "id" = $2`, [
269
273
  sessionId,
@@ -276,25 +280,25 @@ router.post("/mbkauthe/api/login", async (req, res) => {
276
280
  username: user.UserName,
277
281
  sessionId,
278
282
  };
279
- WriteConsoleLogs(`Session stored for user: ${user.UserName}, sessionId: ${sessionId}`); // Log session storage
283
+ console.log(`Session stored for user: ${user.UserName}, sessionId: ${sessionId}`); // Log session storage
280
284
 
281
285
  // Set a cookie accessible across subDOMAINs
282
286
  res.cookie("sessionId", sessionId, {
283
287
  maxAge: COOKIE_EXPIRE_TIME,
284
- DOMAIN: process.env.IS_DEPLOYED === 'true' ? `.${process.env.DOMAIN}` : undefined, // Use DOMAIN only in production
288
+ DOMAIN: mbkautheVar.IS_DEPLOYED === 'true' ? `.${mbkautheVar.DOMAIN}` : undefined, // Use DOMAIN only in production
285
289
  httpOnly: true,
286
- secure: process.env.IS_DEPLOYED === 'true', // Use secure cookies in production
290
+ secure: mbkautheVar.IS_DEPLOYED === 'true', // Use secure cookies in production
287
291
  });
288
- WriteConsoleLogs(`Cookie set for user: ${user.UserName}, sessionId: ${sessionId}`); // Log cookie setting
292
+ console.log(`Cookie set for user: ${user.UserName}, sessionId: ${sessionId}`); // Log cookie setting
289
293
 
290
- WriteConsoleLogs(`User "${username}" logged in successfully`);
294
+ console.log(`User "${username}" logged in successfully`);
291
295
  res.status(200).json({
292
296
  success: true,
293
297
  message: "Login successful",
294
298
  sessionId,
295
299
  });
296
300
  } catch (err) {
297
- WriteConsoleLogs("Error during login process:", err);
301
+ console.log("Error during login process:", err);
298
302
  res.status(500).json({ success: false, message: "Internal Server Error" });
299
303
  }
300
304
  });
@@ -307,22 +311,22 @@ router.post("/mbkauthe/api/logout", async (req, res) => {
307
311
  const result = await dblogin.query(query, [id]);
308
312
 
309
313
  if (result.rows.length > 0 && !result.rows[0].Active) {
310
- WriteConsoleLogs("Account is inactive during logout");
314
+ console.log("Account is inactive during logout");
311
315
  }
312
316
 
313
317
  req.session.destroy((err) => {
314
318
  if (err) {
315
- WriteConsoleLogs("Error destroying session:", err);
319
+ console.log("Error destroying session:", err);
316
320
  return res.status(500).json({ success: false, message: "Logout failed" });
317
321
  }
318
322
  // Clear both session cookies
319
323
  res.clearCookie("connect.sid");
320
324
  res.clearCookie("sessionId"); // Clear the sessionId cookie used for restoration
321
- WriteConsoleLogs(`User "${username}" logged out successfully`);
325
+ console.log(`User "${username}" logged out successfully`);
322
326
  res.status(200).json({ success: true, message: "Logout successful" });
323
327
  });
324
328
  } catch (err) {
325
- WriteConsoleLogs("Database query error during logout:", err);
329
+ console.log("Database query error during logout:", err);
326
330
  res.status(500).json({ success: false, message: "Internal Server Error" });
327
331
  }
328
332
  } else {
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: process.env.LOGIN_DB,
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
- export { validateSession, checkRolePermission, validateSessionAndRole, getUserData };
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.4",
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
- };