mbkauthe 1.0.16 → 1.0.17

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/lib/main.js CHANGED
@@ -25,6 +25,7 @@ try {
25
25
  } catch (error) {
26
26
  console.log("Error parsing COOKIE_EXPIRE_TIME:", error);
27
27
  }
28
+
28
29
  // Enable CORS for subdomains
29
30
  router.use((req, res, next) => {
30
31
  const origin = req.headers.origin;
@@ -41,46 +42,30 @@ router.use(express.json());
41
42
  router.use(express.urlencoded({ extended: true }));
42
43
  router.use(cookieParser());
43
44
 
44
- // Configure session with proper domain settings
45
+ // Configure session with proper domain settings for cross-subdomain sharing
45
46
  const sessionConfig = {
46
47
  store: new PgSession({
47
48
  pool: dblogin,
48
49
  tableName: "session",
50
+ createTableIfMissing: true
49
51
  }),
50
52
  secret: mbkautheVar.SESSION_SECRET_KEY,
51
53
  resave: false,
52
54
  saveUninitialized: false,
55
+ proxy: true, // Trust the reverse proxy
53
56
  cookie: {
54
57
  maxAge: COOKIE_EXPIRE_TIME,
55
58
  domain: mbkautheVar.IS_DEPLOYED === 'true' ? `.${mbkautheVar.DOMAIN}` : undefined,
56
59
  httpOnly: true,
57
- secure: mbkautheVar.IS_DEPLOYED === 'true',
60
+ secure: mbkautheVar.IS_DEPLOYED === 'true' ? 'auto' : false, // 'auto' respects X-Forwarded-Proto
58
61
  sameSite: 'lax',
62
+ path: '/'
59
63
  },
60
- name: 'mbkauthe.sid' // Unique session cookie name
64
+ name: 'mbkauthe.sid'
61
65
  };
62
66
 
63
67
  router.use(session(sessionConfig));
64
68
 
65
-
66
- router.use(async (req, res, next) => {
67
- if (req.session && req.session.user) {
68
- res.cookie("username", req.session.user.username, {
69
- maxAge: COOKIE_EXPIRE_TIME,
70
- path: '/', // Ensure the cookie is available on all paths
71
- DOMAIN: mbkautheVar.IS_DEPLOYED === 'true' ? `.${mbkautheVar.DOMAIN}` : undefined,
72
- secure: mbkautheVar.IS_DEPLOYED === 'true',
73
- });
74
- res.cookie("sessionId", req.session.user.sessionId, {
75
- maxAge: COOKIE_EXPIRE_TIME,
76
- path: '/',
77
- DOMAIN: mbkautheVar.IS_DEPLOYED === 'true' ? `.${mbkautheVar.DOMAIN}` : undefined,
78
- secure: mbkautheVar.IS_DEPLOYED === 'true',
79
- });
80
- }
81
- next();
82
- });
83
-
84
69
  // Middleware to handle session restoration from sessionId cookie
85
70
  router.use(async (req, res, next) => {
86
71
  if (!req.session.user && req.cookies.sessionId) {
@@ -108,23 +93,42 @@ router.use(async (req, res, next) => {
108
93
  next();
109
94
  });
110
95
 
111
- //Invoke-RestMethod -Uri http://localhost:3030/terminateAllSessions -Method POST
112
- // Terminate all sessions route
96
+ // Set consistent cookie options for all cookies
97
+ const getCookieOptions = () => ({
98
+ maxAge: COOKIE_EXPIRE_TIME,
99
+ domain: mbkautheVar.IS_DEPLOYED === 'true' ? `.${mbkautheVar.DOMAIN}` : undefined,
100
+ secure: mbkautheVar.IS_DEPLOYED === 'true' ? 'auto' : false,
101
+ sameSite: 'lax',
102
+ path: '/',
103
+ httpOnly: true
104
+ });
105
+
106
+ router.use(async (req, res, next) => {
107
+ if (req.session && req.session.user) {
108
+ const cookieOptions = getCookieOptions();
109
+ res.cookie("username", req.session.user.username, cookieOptions);
110
+ res.cookie("sessionId", req.session.user.sessionId, cookieOptions);
111
+ }
112
+ next();
113
+ });
114
+
113
115
  router.post("/mbkauthe/api/terminateAllSessions", authenticate(mbkautheVar.Main_SECRET_TOKEN), async (req, res) => {
114
116
  try {
115
117
  await dblogin.query(`UPDATE "Users" SET "SessionId" = NULL`);
116
-
117
- // Clear the session table
118
118
  await dblogin.query('DELETE FROM "session"');
119
119
 
120
- // Destroy all sessions on the server
121
120
  req.session.destroy((err) => {
122
121
  if (err) {
123
122
  console.log("Error destroying session:", err);
124
- return res
125
- .status(500)
126
- .json({ success: false, message: "Failed to terminate sessions" });
123
+ return res.status(500).json({ success: false, message: "Failed to terminate sessions" });
127
124
  }
125
+
126
+ // Clear all cookies with proper domain
127
+ const cookieOptions = getCookieOptions();
128
+ res.clearCookie("mbkauthe.sid", cookieOptions);
129
+ res.clearCookie("sessionId", cookieOptions);
130
+ res.clearCookie("username", cookieOptions);
131
+
128
132
  console.log("All sessions terminated successfully");
129
133
  res.status(200).json({
130
134
  success: true,
@@ -133,23 +137,20 @@ router.post("/mbkauthe/api/terminateAllSessions", authenticate(mbkautheVar.Main_
133
137
  });
134
138
  } catch (err) {
135
139
  console.log("Database query error during session termination:", err);
136
- res
137
- .status(500)
138
- .json({ success: false, message: "Internal Server Error" });
140
+ res.status(500).json({ success: false, message: "Internal Server Error" });
139
141
  }
140
- }
141
- );
142
+ });
142
143
 
143
144
  router.post("/mbkauthe/api/login", async (req, res) => {
144
- console.log("Login request received"); // Log when login is initiated
145
+ console.log("Login request received");
145
146
 
146
147
  const { username, password, token, recaptcha } = req.body;
147
- console.log(`Login attempt for username: ${username}`); // Log username
148
+ console.log(`Login attempt for username: ${username}`);
148
149
 
149
150
  const secretKey = mbkautheVar.RECAPTCHA_SECRET_KEY;
150
151
  const verificationUrl = `https://www.google.com/recaptcha/api/siteverify?secret=${secretKey}&response=${recaptcha}`;
151
152
 
152
- let BypassUsers = Array.isArray(mbkautheVar.BypassUsers) ? mbkautheVar.BypassUsers : JSON.parse(mbkautheVar.BypassUsers); // Ensure it's a flat array
153
+ let BypassUsers = Array.isArray(mbkautheVar.BypassUsers) ? mbkautheVar.BypassUsers : JSON.parse(mbkautheVar.BypassUsers);
153
154
 
154
155
  if (mbkautheVar.RECAPTCHA_Enabled === "true") {
155
156
  if (!BypassUsers.includes(username)) {
@@ -160,7 +161,7 @@ router.post("/mbkauthe/api/login", async (req, res) => {
160
161
  try {
161
162
  const response = await fetch(verificationUrl, { method: 'POST' });
162
163
  const body = await response.json();
163
- console.log("reCAPTCHA verification response:", body); // Log reCAPTCHA response
164
+ console.log("reCAPTCHA verification response:", body);
164
165
 
165
166
  if (!body.success) {
166
167
  console.log("Failed reCAPTCHA verification");
@@ -182,7 +183,6 @@ router.post("/mbkauthe/api/login", async (req, res) => {
182
183
  }
183
184
 
184
185
  try {
185
- // Query to check if the username exists
186
186
  const userQuery = `SELECT * FROM "Users" WHERE "UserName" = $1`;
187
187
  const userResult = await dblogin.query(userQuery, [username]);
188
188
 
@@ -193,20 +193,16 @@ router.post("/mbkauthe/api/login", async (req, res) => {
193
193
 
194
194
  const user = userResult.rows[0];
195
195
 
196
- // Check if the password matches
197
196
  if (user.Password !== password) {
198
197
  console.log(`Incorrect password for username: ${username}`);
199
198
  return res.status(401).json({ success: false, message: "Incorrect Username Or Password" });
200
199
  }
201
200
 
202
- // Check if the account is inactive
203
201
  if (!user.Active) {
204
202
  console.log(`Inactive account for username: ${username}`);
205
203
  return res.status(403).json({ success: false, message: "Account is inactive" });
206
204
  }
207
205
 
208
-
209
- // Check if the user is authorized to use the application
210
206
  if (user.Role !== "SuperAdmin") {
211
207
  const allowedApps = user.AllowedApps;
212
208
  if (!allowedApps || !allowedApps.includes(mbkautheVar.APP_NAME)) {
@@ -219,7 +215,7 @@ router.post("/mbkauthe/api/login", async (req, res) => {
219
215
  let sharedSecret;
220
216
  const query = `SELECT "TwoFAStatus", "TwoFASecret" FROM "TwoFA" WHERE "UserName" = $1`;
221
217
  const twoFAResult = await dblogin.query(query, [username]);
222
- console.log("TwoFA query result:", twoFAResult.rows); // Log TwoFA query result
218
+ console.log("TwoFA query result:", twoFAResult.rows);
223
219
 
224
220
  sharedSecret = twoFAResult.rows[0]?.TwoFASecret;
225
221
  if (twoFAResult.rows.length > 0 && twoFAResult.rows[0].TwoFAStatus && !token) {
@@ -232,7 +228,7 @@ router.post("/mbkauthe/api/login", async (req, res) => {
232
228
  secret: sharedSecret,
233
229
  encoding: "base32",
234
230
  token: token,
235
- window: 1, // Allows a margin for clock drift, optional
231
+ window: 1,
236
232
  });
237
233
 
238
234
  if (!tokenValidates) {
@@ -242,16 +238,14 @@ router.post("/mbkauthe/api/login", async (req, res) => {
242
238
  }
243
239
  }
244
240
 
245
- // Generate session ID
246
241
  const sessionId = crypto.randomBytes(256).toString("hex");
247
- console.log(`Generated session ID for username: ${username}`); // Log session ID
242
+ console.log(`Generated session ID for username: ${username}`);
248
243
 
249
244
  await dblogin.query(`UPDATE "Users" SET "SessionId" = $1 WHERE "id" = $2`, [
250
245
  sessionId,
251
246
  user.id,
252
247
  ]);
253
248
 
254
- // Store session ID in session
255
249
  req.session.user = {
256
250
  id: user.id,
257
251
  username: user.UserName,
@@ -259,15 +253,10 @@ router.post("/mbkauthe/api/login", async (req, res) => {
259
253
  sessionId,
260
254
  };
261
255
 
262
- res.cookie("sessionId", sessionId, {
263
- maxAge: COOKIE_EXPIRE_TIME,
264
- path: '/',
265
- DOMAIN: mbkautheVar.IS_DEPLOYED === 'true' ? `.${mbkautheVar.DOMAIN}` : undefined,
266
- secure: mbkautheVar.IS_DEPLOYED === 'true',
267
- });
256
+ const cookieOptions = getCookieOptions();
257
+ res.cookie("sessionId", sessionId, cookieOptions);
268
258
  console.log(req.session.user);
269
259
 
270
-
271
260
  console.log(`User "${username}" logged in successfully`);
272
261
  res.status(200).json({
273
262
  success: true,
@@ -296,9 +285,13 @@ router.post("/mbkauthe/api/logout", async (req, res) => {
296
285
  console.log("Error destroying session:", err);
297
286
  return res.status(500).json({ success: false, message: "Logout failed" });
298
287
  }
299
- // Clear both session cookies
300
- res.clearCookie("connect.sid");
301
- res.clearCookie("sessionId"); // Clear the sessionId cookie used for restoration
288
+
289
+ // Clear all cookies with proper domain
290
+ const cookieOptions = getCookieOptions();
291
+ res.clearCookie("mbkauthe.sid", cookieOptions);
292
+ res.clearCookie("sessionId", cookieOptions);
293
+ res.clearCookie("username", cookieOptions);
294
+
302
295
  console.log(`User "${username}" logged out successfully`);
303
296
  res.status(200).json({ success: true, message: "Logout successful" });
304
297
  });
@@ -1,6 +1,15 @@
1
1
  import { dblogin } from "./pool.js";
2
2
  const mbkautheVar = JSON.parse(process.env.mbkautheVar);
3
3
 
4
+ // Get consistent cookie options
5
+ const getCookieOptions = () => ({
6
+ domain: mbkautheVar.IS_DEPLOYED === 'true' ? `.${mbkautheVar.DOMAIN}` : undefined,
7
+ secure: mbkautheVar.IS_DEPLOYED === 'true' ? 'auto' : false,
8
+ sameSite: 'lax',
9
+ path: '/',
10
+ httpOnly: true
11
+ });
12
+
4
13
  async function validateSession(req, res, next) {
5
14
  // First check if we have a session cookie
6
15
  if (!req.session.user && req.cookies.sessionId) {
@@ -25,7 +34,6 @@ async function validateSession(req, res, next) {
25
34
  }
26
35
 
27
36
  if (!req.session.user) {
28
-
29
37
  console.log("User not authenticated");
30
38
  console.log(req.session.user);
31
39
  return res.render("templates/Error/NotLoggedIn.handlebars", {
@@ -42,8 +50,10 @@ async function validateSession(req, res, next) {
42
50
  if (result.rows.length === 0 || userResult.SessionId !== sessionId) {
43
51
  console.log(`Session invalidated for user "${req.session.user.username}"`);
44
52
  req.session.destroy();
45
- res.clearCookie("mbkauthe.sid", { domain: `.${mbkautheVar.DOMAIN}` });
46
- res.clearCookie("sessionId", { domain: `.${mbkautheVar.DOMAIN}` });
53
+ const cookieOptions = getCookieOptions();
54
+ res.clearCookie("mbkauthe.sid", cookieOptions);
55
+ res.clearCookie("sessionId", cookieOptions);
56
+ res.clearCookie("username", cookieOptions);
47
57
  return res.render("templates/Error/SessionExpire.handlebars", {
48
58
  currentUrl: req.originalUrl,
49
59
  });
@@ -52,8 +62,10 @@ async function validateSession(req, res, next) {
52
62
  if (!userResult.Active) {
53
63
  console.log(`Account is inactive for user "${req.session.user.username}"`);
54
64
  req.session.destroy();
55
- res.clearCookie("mbkauthe.sid", { domain: `.${mbkautheVar.DOMAIN}` });
56
- res.clearCookie("sessionId", { domain: `.${mbkautheVar.DOMAIN}` });
65
+ const cookieOptions = getCookieOptions();
66
+ res.clearCookie("mbkauthe.sid", cookieOptions);
67
+ res.clearCookie("sessionId", cookieOptions);
68
+ res.clearCookie("username", cookieOptions);
57
69
  return res.render("templates/Error/AccountInactive.handlebars", {
58
70
  currentUrl: req.originalUrl,
59
71
  });
@@ -64,8 +76,10 @@ async function validateSession(req, res, next) {
64
76
  if (!allowedApps || !allowedApps.includes(mbkautheVar.APP_NAME)) {
65
77
  console.warn(`User \"${req.session.user.username}\" is not authorized to use the application \"${mbkautheVar.APP_NAME}\"`);
66
78
  req.session.destroy();
67
- res.clearCookie("mbkauthe.sid", { domain: `.${mbkautheVar.DOMAIN}` });
68
- res.clearCookie("sessionId", { domain: `.${mbkautheVar.DOMAIN}` });
79
+ const cookieOptions = getCookieOptions();
80
+ res.clearCookie("mbkauthe.sid", cookieOptions);
81
+ res.clearCookie("sessionId", cookieOptions);
82
+ res.clearCookie("username", cookieOptions);
69
83
  return res.render("templates/Error/Error.handlebars", {
70
84
  error: `You Are Not Authorized To Use The Application \"${mbkautheVar.APP_NAME}\"`,
71
85
  });
@@ -100,9 +114,7 @@ const checkRolePermission = (requiredRole) => {
100
114
  const result = await dblogin.query(query, [userId]);
101
115
 
102
116
  if (result.rows.length === 0) {
103
- return res
104
- .status(401)
105
- .json({ success: false, message: "User not found" });
117
+ return res.status(401).json({ success: false, message: "User not found" });
106
118
  }
107
119
 
108
120
  const userRole = result.rows[0].Role;
@@ -116,9 +128,7 @@ const checkRolePermission = (requiredRole) => {
116
128
  next();
117
129
  } catch (err) {
118
130
  console.error("Permission check error:", err);
119
- res
120
- .status(500)
121
- .json({ success: false, message: "Internal Server Error" });
131
+ res.status(500).json({ success: false, message: "Internal Server Error" });
122
132
  }
123
133
  };
124
134
  };
@@ -137,7 +147,6 @@ async function getUserData(UserName, parameters) {
137
147
  throw new Error("Parameters are required to fetch user data");
138
148
  }
139
149
 
140
- // Dynamically select fields from Users table based on `parameters`
141
150
  const userFields = [
142
151
  "Password", "UserName", "Role", "Active", "GuestRole", "HaveMailAccount", "AllowedApps",
143
152
  ];
@@ -156,7 +165,6 @@ async function getUserData(UserName, parameters) {
156
165
  profileParameters = profileFields.filter(field => parameters.includes(field));
157
166
  }
158
167
 
159
- // Prepare queries based on required fields
160
168
  let userResult = {};
161
169
  if (userParameters.length > 0) {
162
170
  const userQuery = `SELECT ${userParameters.map(field => `"${field}"`).join(", ")}
@@ -175,7 +183,6 @@ async function getUserData(UserName, parameters) {
175
183
  profileResult = profileQueryResult.rows[0];
176
184
  }
177
185
 
178
- // Combine results
179
186
  const combinedResult = { ...userResult, ...profileResult };
180
187
  return combinedResult;
181
188
  } catch (err) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mbkauthe",
3
- "version": "1.0.16",
3
+ "version": "1.0.17",
4
4
  "description": "MBKTechStudio's reusable authentication system for Node.js applications.",
5
5
  "main": "index.js",
6
6
  "type": "module",