mbkauthe 1.2.1 → 1.3.1
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/README.md +1 -14
- package/docs/db.md +124 -0
- package/index.js +26 -4
- package/lib/main.js +173 -439
- package/lib/validateSessionAndRole.js +17 -54
- package/package.json +1 -1
- package/views/info.handlebars +236 -0
- package/views/loginmbkauthe.handlebars +65 -0
package/README.md
CHANGED
|
@@ -14,9 +14,7 @@
|
|
|
14
14
|
- [Middleware Function Documentation](#middleware-function-documentation)
|
|
15
15
|
- [validateSession(session)](#validatesessionsession)
|
|
16
16
|
- [checkRolePermission(userRole, requiredRoles)](#checkrolepermissionuserrole-requiredroles)
|
|
17
|
-
- [validateSessionAndRole(session, userRole, requiredRoles)]
|
|
18
|
-
- [getUserData(session)](#getuserdatasession)
|
|
19
|
-
- [authenticate(session)](#authenticatesession)
|
|
17
|
+
- [validateSessionAndRole(session, userRole, requiredRoles)]
|
|
20
18
|
- [API Endpoints](#api-endpoints)
|
|
21
19
|
- [Login](#login)
|
|
22
20
|
- [Logout](#logout)
|
|
@@ -155,17 +153,6 @@ router.get(["/admin"], validateSessionAndRole("SuperAdmin"), (req, res) => {
|
|
|
155
153
|
```
|
|
156
154
|
---
|
|
157
155
|
|
|
158
|
-
### `getUserData(session)`
|
|
159
|
-
Retrieves user data based on the session.
|
|
160
|
-
|
|
161
|
-
- **Parameters:**
|
|
162
|
-
- `session` (Object): The session object containing user information.
|
|
163
|
-
|
|
164
|
-
- **Returns:**
|
|
165
|
-
- `Object|null`: Returns the user data object if found, otherwise `null`.
|
|
166
|
-
|
|
167
|
-
---
|
|
168
|
-
|
|
169
156
|
### `authenticate(session)`
|
|
170
157
|
Authenticates the user by validating the session and retrieving user data.
|
|
171
158
|
|
package/docs/db.md
CHANGED
|
@@ -1,3 +1,127 @@
|
|
|
1
|
+
# GitHub Login Setup Guide
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
This GitHub login feature allows users to authenticate using their GitHub account if it's already linked to their account in the system. Users must first connect their GitHub account through the regular account linking process, then they can use GitHub to log in directly.
|
|
5
|
+
|
|
6
|
+
## Setup Instructions
|
|
7
|
+
|
|
8
|
+
### 1. Environment Variables
|
|
9
|
+
Add these to your `.env` file:
|
|
10
|
+
|
|
11
|
+
```env
|
|
12
|
+
# GitHub OAuth App Configuration
|
|
13
|
+
GITHUB_CLIENT_ID=your_github_client_id
|
|
14
|
+
GITHUB_CLIENT_SECRET=your_github_client_secret
|
|
15
|
+
GITHUB_LOGIN_CALLBACK_URL=https://yourdomain.com/mbkauthe/api/github/login/callback
|
|
16
|
+
BASE_URL=https://yourdomain.com
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
### 2. GitHub OAuth App Setup
|
|
20
|
+
1. Go to GitHub Settings > Developer settings > OAuth Apps
|
|
21
|
+
2. Create a new OAuth App
|
|
22
|
+
3. Set the Authorization callback URL to: `https://yourdomain.com/mbkauthe/api/github/login/callback`
|
|
23
|
+
4. Copy the Client ID and Client Secret to your `.env` file
|
|
24
|
+
|
|
25
|
+
### 3. Database Schema
|
|
26
|
+
Ensure your `user_github` table exists with these columns:
|
|
27
|
+
|
|
28
|
+
```sql
|
|
29
|
+
CREATE TABLE user_github (
|
|
30
|
+
id SERIAL PRIMARY KEY,
|
|
31
|
+
user_name VARCHAR(255) REFERENCES "Users"("UserName"),
|
|
32
|
+
github_id VARCHAR(255) UNIQUE NOT NULL,
|
|
33
|
+
github_username VARCHAR(255),
|
|
34
|
+
access_token TEXT,
|
|
35
|
+
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
|
36
|
+
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
|
37
|
+
);
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
## How It Works
|
|
41
|
+
|
|
42
|
+
### Login Flow
|
|
43
|
+
1. User clicks "Login with GitHub" on the login page
|
|
44
|
+
2. User is redirected to GitHub for authentication
|
|
45
|
+
3. GitHub redirects back to `/mbkauthe/api/github/login/callback`
|
|
46
|
+
4. System checks if the GitHub ID exists in `user_github` table
|
|
47
|
+
5. If found and user is active/authorized:
|
|
48
|
+
- If 2FA is enabled, redirect to 2FA page
|
|
49
|
+
- If no 2FA, complete login and redirect to home
|
|
50
|
+
6. If not found, redirect to login page with error
|
|
51
|
+
|
|
52
|
+
### Account Linking
|
|
53
|
+
Users must first link their GitHub account through your existing GitHub connection system (likely in user settings) before they can use GitHub login.
|
|
54
|
+
|
|
55
|
+
## API Routes Added
|
|
56
|
+
|
|
57
|
+
### `/mbkauthe/api/github/login`
|
|
58
|
+
- **Method**: GET
|
|
59
|
+
- **Description**: Initiates GitHub OAuth flow
|
|
60
|
+
- **Redirects to**: GitHub authorization page
|
|
61
|
+
|
|
62
|
+
### `/mbkauthe/api/github/login/callback`
|
|
63
|
+
- **Method**: GET
|
|
64
|
+
- **Description**: Handles GitHub OAuth callback
|
|
65
|
+
- **Parameters**: `code` (from GitHub), `state` (optional)
|
|
66
|
+
- **Success**: Redirects to home page or configured redirect URL
|
|
67
|
+
- **Error**: Redirects to login page with error parameter
|
|
68
|
+
|
|
69
|
+
## Error Handling
|
|
70
|
+
|
|
71
|
+
The system handles various error cases:
|
|
72
|
+
- `github_auth_failed`: GitHub OAuth failed
|
|
73
|
+
- `user_not_found`: GitHub account not linked to any user
|
|
74
|
+
- `session_error`: Session save failed
|
|
75
|
+
- `internal_error`: General server error
|
|
76
|
+
|
|
77
|
+
## Testing
|
|
78
|
+
|
|
79
|
+
1. Create a test user in your `Users` table
|
|
80
|
+
2. Link a GitHub account to that user using your existing connection system
|
|
81
|
+
3. Try logging in with GitHub using the new login button
|
|
82
|
+
4. Check console logs for debugging information
|
|
83
|
+
|
|
84
|
+
## Login Page Updates
|
|
85
|
+
|
|
86
|
+
The login page now includes:
|
|
87
|
+
- A "Continue with GitHub" button
|
|
88
|
+
- A divider ("or") between regular and GitHub login
|
|
89
|
+
- Proper styling that matches your existing design
|
|
90
|
+
|
|
91
|
+
## Security Notes
|
|
92
|
+
|
|
93
|
+
- Only users with active accounts can log in
|
|
94
|
+
- App authorization is checked (same as regular login)
|
|
95
|
+
- 2FA is respected if enabled
|
|
96
|
+
- Session management is handled the same way as regular login
|
|
97
|
+
- GitHub access tokens are stored securely
|
|
98
|
+
|
|
99
|
+
## Troubleshooting
|
|
100
|
+
|
|
101
|
+
1. **GitHub OAuth errors**: Check your GitHub OAuth app configuration
|
|
102
|
+
2. **Database errors**: Ensure `user_github` table exists and has proper relationships
|
|
103
|
+
3. **Session errors**: Check your session configuration
|
|
104
|
+
4. **2FA issues**: Verify 2FA table structure and configuration
|
|
105
|
+
|
|
106
|
+
## Environment Variables Summary
|
|
107
|
+
|
|
108
|
+
```env
|
|
109
|
+
# Required for GitHub Login
|
|
110
|
+
GITHUB_CLIENT_ID=your_github_client_id
|
|
111
|
+
GITHUB_CLIENT_SECRET=your_github_client_secret
|
|
112
|
+
GITHUB_LOGIN_CALLBACK_URL=https://yourdomain.com/mbkauthe/api/github/login/callback
|
|
113
|
+
|
|
114
|
+
# Optional (used as fallback)
|
|
115
|
+
BASE_URL=https://yourdomain.com
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
The GitHub login feature is now fully integrated into your mbkauthe system and ready to use!
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
|
|
1
125
|
## Database structure
|
|
2
126
|
|
|
3
127
|
[<- Back](README.md)
|
package/index.js
CHANGED
|
@@ -44,8 +44,8 @@ if (process.env.test === "true") {
|
|
|
44
44
|
}
|
|
45
45
|
|
|
46
46
|
app.set("views", [
|
|
47
|
-
|
|
48
|
-
|
|
47
|
+
path.join(__dirname, "views"),
|
|
48
|
+
path.join(__dirname, "node_modules/mbkauthe/views")
|
|
49
49
|
]);
|
|
50
50
|
|
|
51
51
|
app.engine("handlebars", engine({
|
|
@@ -55,6 +55,28 @@ app.engine("handlebars", engine({
|
|
|
55
55
|
path.join(__dirname, "node_modules/mbkauthe/views"),
|
|
56
56
|
path.join(__dirname, "node_modules/mbkauthe/views/Error"),
|
|
57
57
|
],
|
|
58
|
+
helpers: {
|
|
59
|
+
eq: function (a, b) {
|
|
60
|
+
return a === b;
|
|
61
|
+
},
|
|
62
|
+
encodeURIComponent: function (str) {
|
|
63
|
+
return encodeURIComponent(str);
|
|
64
|
+
},
|
|
65
|
+
formatTimestamp: function (timestamp) {
|
|
66
|
+
return new Date(timestamp).toLocaleString();
|
|
67
|
+
},
|
|
68
|
+
jsonStringify: function (context) {
|
|
69
|
+
return JSON.stringify(context);
|
|
70
|
+
},
|
|
71
|
+
json: (obj) => JSON.stringify(obj, null, 2),
|
|
72
|
+
objectEntries: function (obj) {
|
|
73
|
+
if (!obj || typeof obj !== 'object') {
|
|
74
|
+
return []; // Return an empty array if obj is undefined, null, or not an object
|
|
75
|
+
}
|
|
76
|
+
return Object.entries(obj).map(([key, value]) => ({ key, value }));
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
58
80
|
}));
|
|
59
81
|
|
|
60
82
|
app.set("view engine", "handlebars");
|
|
@@ -63,10 +85,10 @@ import { createRequire } from "module";
|
|
|
63
85
|
const require = createRequire(import.meta.url);
|
|
64
86
|
const packageJson = require("./package.json");
|
|
65
87
|
const latestVersion = await getLatestVersion();
|
|
66
|
-
if(latestVersion !== packageJson.version) {
|
|
88
|
+
if (latestVersion !== packageJson.version) {
|
|
67
89
|
console.warn(`[mbkauthe] Warning: The current version (${packageJson.version}) is not the latest version (${latestVersion}). Please update mbkauthe.`);
|
|
68
90
|
}
|
|
69
91
|
|
|
70
|
-
export { validateSession, checkRolePermission, validateSessionAndRole,
|
|
92
|
+
export { validateSession, checkRolePermission, validateSessionAndRole, authenticate, authapi } from "./lib/validateSessionAndRole.js";
|
|
71
93
|
export { dblogin } from "./lib/pool.js";
|
|
72
94
|
export default router;
|
package/lib/main.js
CHANGED
|
@@ -11,6 +11,8 @@ import cookieParser from "cookie-parser";
|
|
|
11
11
|
import bcrypt from 'bcrypt';
|
|
12
12
|
import rateLimit from 'express-rate-limit';
|
|
13
13
|
import speakeasy from "speakeasy";
|
|
14
|
+
//import passport from 'passport';
|
|
15
|
+
//import GitHubStrategy from 'passport-github2';
|
|
14
16
|
|
|
15
17
|
import { createRequire } from "module";
|
|
16
18
|
import fs from "fs";
|
|
@@ -383,6 +385,7 @@ router.post("/mbkauthe/api/logout", async (req, res) => {
|
|
|
383
385
|
router.get("/mbkauthe/login", LoginLimit, csrfProtection, (req, res) => {
|
|
384
386
|
return res.render("loginmbkauthe.handlebars", {
|
|
385
387
|
layout: false,
|
|
388
|
+
githubLoginEnabled: mbkautheVar.GITHUB_LOGIN_ENABLED,
|
|
386
389
|
customURL: mbkautheVar.loginRedirectURL || '/home',
|
|
387
390
|
userLoggedIn: !!req.session?.user,
|
|
388
391
|
username: req.session?.user?.username || '',
|
|
@@ -396,7 +399,8 @@ async function getLatestVersion() {
|
|
|
396
399
|
try {
|
|
397
400
|
const response = await fetch('https://raw.githubusercontent.com/MIbnEKhalid/mbkauthe/main/package.json');
|
|
398
401
|
if (!response.ok) {
|
|
399
|
-
|
|
402
|
+
console.Error(`GitHub API responded with status ${response.status}`);
|
|
403
|
+
return "0.0.0";
|
|
400
404
|
}
|
|
401
405
|
const latestPackageJson = await response.json();
|
|
402
406
|
return latestPackageJson.version;
|
|
@@ -406,455 +410,23 @@ async function getLatestVersion() {
|
|
|
406
410
|
}
|
|
407
411
|
}
|
|
408
412
|
|
|
409
|
-
async function getPackageLock() {
|
|
410
|
-
const packageLockPath = path.resolve(process.cwd(), "package-lock.json");
|
|
411
|
-
|
|
412
|
-
return new Promise((resolve, reject) => {
|
|
413
|
-
fs.readFile(packageLockPath, "utf8", (err, data) => {
|
|
414
|
-
if (err) {
|
|
415
|
-
console.error("[mbkauthe] Error reading package-lock.json:", err);
|
|
416
|
-
return reject({ success: false, message: "Failed to read package-lock.json" });
|
|
417
|
-
}
|
|
418
|
-
try {
|
|
419
|
-
const packageLock = JSON.parse(data);
|
|
420
|
-
const mbkautheData = {
|
|
421
|
-
name: 'mbkauthe',
|
|
422
|
-
version: packageLock.packages['node_modules/mbkauthe']?.version || packageJson.version,
|
|
423
|
-
resolved: packageLock.packages['node_modules/mbkauthe']?.resolved || '',
|
|
424
|
-
integrity: packageLock.packages['node_modules/mbkauthe']?.integrity || '',
|
|
425
|
-
license: packageLock.packages['node_modules/mbkauthe']?.license || packageJson.license,
|
|
426
|
-
dependencies: packageLock.packages['node_modules/mbkauthe']?.dependencies || {}
|
|
427
|
-
};
|
|
428
|
-
const rootDependency = packageLock.dependencies?.mbkauthe || {};
|
|
429
|
-
resolve({ mbkautheData, rootDependency });
|
|
430
|
-
} catch (parseError) {
|
|
431
|
-
console.error("[mbkauthe] Error parsing package-lock.json:", parseError);
|
|
432
|
-
reject("Error parsing package-lock.json");
|
|
433
|
-
}
|
|
434
|
-
});
|
|
435
|
-
});
|
|
436
|
-
}
|
|
437
|
-
|
|
438
|
-
function formatJson(json) {
|
|
439
|
-
if (typeof json === 'string') {
|
|
440
|
-
try {
|
|
441
|
-
json = JSON.parse(json);
|
|
442
|
-
} catch (e) {
|
|
443
|
-
return json;
|
|
444
|
-
}
|
|
445
|
-
}
|
|
446
|
-
|
|
447
|
-
// First stringify with proper indentation
|
|
448
|
-
let jsonString = JSON.stringify(json, null, 2);
|
|
449
|
-
|
|
450
|
-
// Escape HTML special characters EXCEPT for our span tags
|
|
451
|
-
jsonString = jsonString
|
|
452
|
-
.replace(/&/g, '&')
|
|
453
|
-
.replace(/</g, '<')
|
|
454
|
-
.replace(/>/g, '>');
|
|
455
|
-
|
|
456
|
-
// Now apply syntax highlighting (after escaping)
|
|
457
|
-
jsonString = jsonString
|
|
458
|
-
// Highlight keys
|
|
459
|
-
.replace(/"([^"]+)":/g, '"<span style="color: #2b6cb0;">$1</span>":')
|
|
460
|
-
// Highlight string values
|
|
461
|
-
.replace(/:\s*"([^"]+)"/g, ': "<span style="color: #38a169;">$1</span>"')
|
|
462
|
-
// Highlight numbers
|
|
463
|
-
.replace(/: (\d+)/g, ': <span style="color: #dd6b20;">$1</span>')
|
|
464
|
-
// Highlight booleans and null
|
|
465
|
-
.replace(/: (true|false|null)/g, ': <span style="color: #805ad5;">$1</span>');
|
|
466
|
-
|
|
467
|
-
return jsonString;
|
|
468
|
-
}
|
|
469
|
-
|
|
470
413
|
router.get(["/mbkauthe/info", "/mbkauthe/i"], LoginLimit, async (_, res) => {
|
|
471
|
-
let pkgl = {};
|
|
472
414
|
let latestVersion;
|
|
473
415
|
|
|
474
416
|
try {
|
|
475
|
-
pkgl = await getPackageLock();
|
|
476
417
|
latestVersion = await getLatestVersion();
|
|
477
418
|
//latestVersion = "Under Development"; // Placeholder for the latest version
|
|
478
419
|
} catch (err) {
|
|
479
420
|
console.error("[mbkauthe] Error fetching package-lock.json:", err);
|
|
480
|
-
pkgl = { error: "Failed to fetch package-lock.json" };
|
|
481
421
|
}
|
|
482
422
|
|
|
483
423
|
try {
|
|
484
|
-
res.
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
<style>
|
|
491
|
-
:root {
|
|
492
|
-
--bg-color: #121212;
|
|
493
|
-
--card-bg: #1e1e1e;
|
|
494
|
-
--text-color: #e0e0e0;
|
|
495
|
-
--text-secondary: #a0a0a0;
|
|
496
|
-
--primary: #bb86fc;
|
|
497
|
-
--primary-dark: #3700b3;
|
|
498
|
-
--secondary: #03dac6;
|
|
499
|
-
--border-color: #333;
|
|
500
|
-
--success: #4caf50;
|
|
501
|
-
--warning: #ff9800;
|
|
502
|
-
--error: #f44336;
|
|
503
|
-
--key-color: #bb86fc;
|
|
504
|
-
--string-color: #03dac6;
|
|
505
|
-
--number-color: #ff7043;
|
|
506
|
-
--boolean-color: #7986cb;
|
|
507
|
-
}
|
|
508
|
-
|
|
509
|
-
body {
|
|
510
|
-
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
|
|
511
|
-
margin: 0;
|
|
512
|
-
padding: 20px;
|
|
513
|
-
background-color: var(--bg-color);
|
|
514
|
-
color: var(--text-color);
|
|
515
|
-
}
|
|
516
|
-
|
|
517
|
-
.container {
|
|
518
|
-
max-width: 1000px;
|
|
519
|
-
margin: 0 auto;
|
|
520
|
-
padding: 20px;
|
|
521
|
-
background: var(--card-bg);
|
|
522
|
-
border-radius: 8px;
|
|
523
|
-
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.3);
|
|
524
|
-
}
|
|
525
|
-
|
|
526
|
-
h1 {
|
|
527
|
-
color: var(--primary);
|
|
528
|
-
text-align: center;
|
|
529
|
-
margin-bottom: 30px;
|
|
530
|
-
padding-bottom: 10px;
|
|
531
|
-
border-bottom: 1px solid var(--border-color);
|
|
532
|
-
font-weight: bold;
|
|
533
|
-
letter-spacing: 1px;
|
|
534
|
-
}
|
|
535
|
-
|
|
536
|
-
.info-section {
|
|
537
|
-
margin-bottom: 25px;
|
|
538
|
-
padding: 20px;
|
|
539
|
-
border: 1px solid var(--border-color);
|
|
540
|
-
border-radius: 8px;
|
|
541
|
-
background-color: rgba(30, 30, 30, 0.7);
|
|
542
|
-
transition: all 0.3s ease;
|
|
543
|
-
}
|
|
544
|
-
|
|
545
|
-
.info-section:hover {
|
|
546
|
-
border-color: var(--primary);
|
|
547
|
-
box-shadow: 0 0 0 1px var(--primary);
|
|
548
|
-
}
|
|
549
|
-
|
|
550
|
-
.info-section h2 {
|
|
551
|
-
color: var(--primary);
|
|
552
|
-
border-bottom: 2px solid var(--primary-dark);
|
|
553
|
-
padding-bottom: 8px;
|
|
554
|
-
margin-top: 0;
|
|
555
|
-
margin-bottom: 15px;
|
|
556
|
-
font-size: 1.2em;
|
|
557
|
-
display: flex;
|
|
558
|
-
justify-content: space-between;
|
|
559
|
-
align-items: center;
|
|
560
|
-
}
|
|
561
|
-
|
|
562
|
-
.info-row {
|
|
563
|
-
display: flex;
|
|
564
|
-
margin-bottom: 10px;
|
|
565
|
-
padding-bottom: 10px;
|
|
566
|
-
border-bottom: 1px solid var(--border-color);
|
|
567
|
-
}
|
|
568
|
-
|
|
569
|
-
.info-label {
|
|
570
|
-
font-weight: 600;
|
|
571
|
-
color: var(--text-secondary);
|
|
572
|
-
min-width: 220px;
|
|
573
|
-
font-size: 0.95em;
|
|
574
|
-
}
|
|
575
|
-
|
|
576
|
-
.info-value {
|
|
577
|
-
flex: 1;
|
|
578
|
-
word-break: break-word;
|
|
579
|
-
color: var(--text-color);
|
|
580
|
-
}
|
|
581
|
-
|
|
582
|
-
.json-container {
|
|
583
|
-
background: #252525;
|
|
584
|
-
border: 1px solid var(--border-color);
|
|
585
|
-
border-radius: 6px;
|
|
586
|
-
padding: 12px;
|
|
587
|
-
margin-top: 10px;
|
|
588
|
-
max-height: 400px;
|
|
589
|
-
overflow: auto;
|
|
590
|
-
font-family: 'Fira Code', 'Consolas', 'Monaco', monospace;
|
|
591
|
-
font-size: 0.85em;
|
|
592
|
-
white-space: pre-wrap;
|
|
593
|
-
position: relative;
|
|
594
|
-
}
|
|
595
|
-
|
|
596
|
-
.json-container pre {
|
|
597
|
-
margin: 0;
|
|
598
|
-
font-family: inherit;
|
|
599
|
-
}
|
|
600
|
-
|
|
601
|
-
.json-container .key {
|
|
602
|
-
color: var(--key-color);
|
|
603
|
-
}
|
|
604
|
-
|
|
605
|
-
.json-container .string {
|
|
606
|
-
color: var(--string-color);
|
|
607
|
-
}
|
|
608
|
-
|
|
609
|
-
.json-container .number {
|
|
610
|
-
color: var(--number-color);
|
|
611
|
-
}
|
|
612
|
-
|
|
613
|
-
.json-container .boolean {
|
|
614
|
-
color: var(--boolean-color);
|
|
615
|
-
}
|
|
616
|
-
|
|
617
|
-
.json-container .null {
|
|
618
|
-
color: var(--boolean-color);
|
|
619
|
-
opacity: 0.7;
|
|
620
|
-
}
|
|
621
|
-
|
|
622
|
-
.version-status {
|
|
623
|
-
display: inline-block;
|
|
624
|
-
padding: 3px 10px;
|
|
625
|
-
border-radius: 12px;
|
|
626
|
-
font-size: 0.8em;
|
|
627
|
-
font-weight: 600;
|
|
628
|
-
margin-left: 10px;
|
|
629
|
-
}
|
|
630
|
-
|
|
631
|
-
.version-up-to-date {
|
|
632
|
-
background: rgba(76, 175, 80, 0.2);
|
|
633
|
-
color: var(--success);
|
|
634
|
-
border: 1px solid var(--success);
|
|
635
|
-
}
|
|
636
|
-
|
|
637
|
-
.version-outdated {
|
|
638
|
-
background: rgba(244, 67, 54, 0.2);
|
|
639
|
-
color: var(--error);
|
|
640
|
-
border: 1px solid var(--error);
|
|
641
|
-
}
|
|
642
|
-
|
|
643
|
-
.version-fetch-error {
|
|
644
|
-
background: rgba(255, 152, 0, 0.2);
|
|
645
|
-
color: var(--warning);
|
|
646
|
-
border: 1px solid var(--warning);
|
|
647
|
-
}
|
|
648
|
-
|
|
649
|
-
.copy-btn {
|
|
650
|
-
background: var(--primary-dark);
|
|
651
|
-
color: white;
|
|
652
|
-
border: none;
|
|
653
|
-
padding: 5px 12px;
|
|
654
|
-
border-radius: 4px;
|
|
655
|
-
cursor: pointer;
|
|
656
|
-
font-size: 0.8em;
|
|
657
|
-
transition: all 0.2s ease;
|
|
658
|
-
display: flex;
|
|
659
|
-
align-items: center;
|
|
660
|
-
gap: 5px;
|
|
661
|
-
}
|
|
662
|
-
|
|
663
|
-
.copy-btn:hover {
|
|
664
|
-
background: var(--primary);
|
|
665
|
-
transform: translateY(-1px);
|
|
666
|
-
}
|
|
667
|
-
|
|
668
|
-
.copy-btn:active {
|
|
669
|
-
transform: translateY(0);
|
|
670
|
-
}
|
|
671
|
-
|
|
672
|
-
/* Scrollbar styling */
|
|
673
|
-
::-webkit-scrollbar {
|
|
674
|
-
width: 8px;
|
|
675
|
-
height: 8px;
|
|
676
|
-
}
|
|
677
|
-
|
|
678
|
-
::-webkit-scrollbar-track {
|
|
679
|
-
background: #2d2d2d;
|
|
680
|
-
border-radius: 4px;
|
|
681
|
-
}
|
|
682
|
-
|
|
683
|
-
::-webkit-scrollbar-thumb {
|
|
684
|
-
background: #555;
|
|
685
|
-
border-radius: 4px;
|
|
686
|
-
}
|
|
687
|
-
|
|
688
|
-
::-webkit-scrollbar-thumb:hover {
|
|
689
|
-
background: var(--primary);
|
|
690
|
-
}
|
|
691
|
-
|
|
692
|
-
/* Tooltip for copy button */
|
|
693
|
-
.tooltip {
|
|
694
|
-
position: relative;
|
|
695
|
-
display: inline-block;
|
|
696
|
-
}
|
|
697
|
-
|
|
698
|
-
.tooltip .tooltiptext {
|
|
699
|
-
visibility: hidden;
|
|
700
|
-
width: 120px;
|
|
701
|
-
background-color: #333;
|
|
702
|
-
color: #fff;
|
|
703
|
-
text-align: center;
|
|
704
|
-
border-radius: 6px;
|
|
705
|
-
padding: 5px;
|
|
706
|
-
position: absolute;
|
|
707
|
-
z-index: 1;
|
|
708
|
-
bottom: 125%;
|
|
709
|
-
left: 50%;
|
|
710
|
-
margin-left: -60px;
|
|
711
|
-
opacity: 0;
|
|
712
|
-
transition: opacity 0.3s;
|
|
713
|
-
font-size: 0.8em;
|
|
714
|
-
}
|
|
715
|
-
|
|
716
|
-
.tooltip:hover .tooltiptext {
|
|
717
|
-
visibility: visible;
|
|
718
|
-
opacity: 1;
|
|
719
|
-
}
|
|
720
|
-
</style>
|
|
721
|
-
<link href="https://fonts.googleapis.com/css2?family=Fira+Code:wght@400;500&display=swap" rel="stylesheet">
|
|
722
|
-
</head>
|
|
723
|
-
|
|
724
|
-
<body>
|
|
725
|
-
<div class="container">
|
|
726
|
-
<h1>Version and Configuration Dashboard</h1>
|
|
727
|
-
|
|
728
|
-
<div class="info-section">
|
|
729
|
-
<h2>Version Information</h2>
|
|
730
|
-
<div class="info-row">
|
|
731
|
-
<div class="info-label">Current Version:</div>
|
|
732
|
-
<div class="info-value" id="CurrentVersion">${packageJson.version}</div>
|
|
733
|
-
</div>
|
|
734
|
-
<div class="info-row">
|
|
735
|
-
<div class="info-label">Latest Version:</div>
|
|
736
|
-
<div class="info-value">
|
|
737
|
-
${latestVersion || 'Could not fetch latest version'}
|
|
738
|
-
${latestVersion ? `
|
|
739
|
-
<span class="version-status ${packageJson.version === latestVersion ? 'version-up-to-date' : 'version-outdated'}">
|
|
740
|
-
${packageJson.version === latestVersion ? 'Up to date' : 'Update available'}
|
|
741
|
-
</span>
|
|
742
|
-
` : `
|
|
743
|
-
<span class="version-status version-fetch-error">
|
|
744
|
-
Fetch error
|
|
745
|
-
</span>
|
|
746
|
-
`}
|
|
747
|
-
</div>
|
|
748
|
-
</div>
|
|
749
|
-
</div>
|
|
750
|
-
|
|
751
|
-
<div class="info-section">
|
|
752
|
-
<h2>Configuration Information</h2>
|
|
753
|
-
<div class="info-row">
|
|
754
|
-
<div class="info-label">APP_NAME:</div>
|
|
755
|
-
<div class="info-value">${mbkautheVar.APP_NAME}</div>
|
|
756
|
-
</div>
|
|
757
|
-
<div class="info-row">
|
|
758
|
-
<div class="info-label">MBKAUTH_TWO_FA_ENABLE:</div>
|
|
759
|
-
<div class="info-value">${mbkautheVar.MBKAUTH_TWO_FA_ENABLE}</div>
|
|
760
|
-
</div>
|
|
761
|
-
<div class="info-row">
|
|
762
|
-
<div class="info-label">COOKIE_EXPIRE_TIME:</div>
|
|
763
|
-
<div class="info-value">${mbkautheVar.COOKIE_EXPIRE_TIME} Days</div>
|
|
764
|
-
</div>
|
|
765
|
-
<div class="info-row">
|
|
766
|
-
<div class="info-label">IS_DEPLOYED:</div>
|
|
767
|
-
<div class="info-value">${mbkautheVar.IS_DEPLOYED}</div>
|
|
768
|
-
</div>
|
|
769
|
-
<div class="info-row">
|
|
770
|
-
<div class="info-label">DOMAIN:</div>
|
|
771
|
-
<div class="info-value">${mbkautheVar.DOMAIN}</div>
|
|
772
|
-
</div>
|
|
773
|
-
<div class="info-row">
|
|
774
|
-
<div class="info-label">Login Redirect URL:</div>
|
|
775
|
-
<div class="info-value">${mbkautheVar.loginRedirectURL}</div>
|
|
776
|
-
</div>
|
|
777
|
-
</div>
|
|
778
|
-
|
|
779
|
-
<div class="info-section">
|
|
780
|
-
<h2>
|
|
781
|
-
Package Information
|
|
782
|
-
<button class="copy-btn tooltip" onclick="copyToClipboard('package-json')">
|
|
783
|
-
<span class="tooltiptext">Copy to clipboard</span>
|
|
784
|
-
Copy JSON
|
|
785
|
-
</button>
|
|
786
|
-
</h2>
|
|
787
|
-
<div id="package-json" class="json-container"><pre>${JSON.stringify(packageJson, null, 2)}</pre></div>
|
|
788
|
-
</div>
|
|
789
|
-
|
|
790
|
-
<div class="info-section">
|
|
791
|
-
<h2>
|
|
792
|
-
Package Lock
|
|
793
|
-
<button class="copy-btn tooltip" onclick="copyToClipboard('package-lock')">
|
|
794
|
-
<span class="tooltiptext">Copy to clipboard</span>
|
|
795
|
-
Copy JSON
|
|
796
|
-
</button>
|
|
797
|
-
</h2>
|
|
798
|
-
<div id="package-lock" class="json-container"><pre>${JSON.stringify(pkgl, null, 2)}</pre></div>
|
|
799
|
-
</div>
|
|
800
|
-
</div>
|
|
801
|
-
|
|
802
|
-
<script>
|
|
803
|
-
document.addEventListener('DOMContentLoaded', function() {
|
|
804
|
-
// Apply syntax highlighting to all JSON containers
|
|
805
|
-
const jsonContainers = document.querySelectorAll('.json-container pre');
|
|
806
|
-
jsonContainers.forEach(container => {
|
|
807
|
-
container.innerHTML = syntaxHighlight(container.textContent);
|
|
808
|
-
});
|
|
809
|
-
});
|
|
810
|
-
|
|
811
|
-
function syntaxHighlight(json) {
|
|
812
|
-
if (typeof json !== 'string') {
|
|
813
|
-
json = JSON.stringify(json, null, 2);
|
|
814
|
-
}
|
|
815
|
-
|
|
816
|
-
// Escape HTML
|
|
817
|
-
json = json.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>');
|
|
818
|
-
|
|
819
|
-
// Apply syntax highlighting
|
|
820
|
-
return json.replace(
|
|
821
|
-
/("(\\u[a-zA-Z0-9]{4}|\\[^u]|[^\\"])*"(\s*:)?|\b(true|false|null)\b|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?)/g,
|
|
822
|
-
function(match) {
|
|
823
|
-
let cls = 'number';
|
|
824
|
-
if (/^"/.test(match)) {
|
|
825
|
-
if (/:$/.test(match)) {
|
|
826
|
-
cls = 'key';
|
|
827
|
-
} else {
|
|
828
|
-
cls = 'string';
|
|
829
|
-
}
|
|
830
|
-
} else if (/true|false/.test(match)) {
|
|
831
|
-
cls = 'boolean';
|
|
832
|
-
} else if (/null/.test(match)) {
|
|
833
|
-
cls = 'null';
|
|
834
|
-
}
|
|
835
|
-
return '<span class="' + cls + '">' + match + '</span>';
|
|
836
|
-
}
|
|
837
|
-
);
|
|
838
|
-
}
|
|
839
|
-
|
|
840
|
-
function copyToClipboard(elementId) {
|
|
841
|
-
const element = document.getElementById(elementId);
|
|
842
|
-
const text = element.textContent;
|
|
843
|
-
navigator.clipboard.writeText(text).then(() => {
|
|
844
|
-
const btn = element.parentElement.querySelector('.copy-btn');
|
|
845
|
-
const originalText = btn.innerHTML;
|
|
846
|
-
btn.innerHTML = '<span class="tooltiptext">Copied!</span>✓ Copied';
|
|
847
|
-
setTimeout(() => {
|
|
848
|
-
btn.innerHTML = '<span class="tooltiptext">Copy to clipboard</span>' + originalText.replace('✓ Copied', 'Copy JSON');
|
|
849
|
-
}, 2000);
|
|
850
|
-
}).catch(err => {
|
|
851
|
-
console.error('[mbkauthe] Failed to copy text: ', err);
|
|
852
|
-
});
|
|
853
|
-
}
|
|
854
|
-
</script>
|
|
855
|
-
</body>
|
|
856
|
-
</html>
|
|
857
|
-
`);
|
|
424
|
+
res.render("info.handlebars", {
|
|
425
|
+
layout: false,
|
|
426
|
+
mbkautheVar: mbkautheVar,
|
|
427
|
+
version: packageJson.version,
|
|
428
|
+
latestVersion,
|
|
429
|
+
});
|
|
858
430
|
} catch (err) {
|
|
859
431
|
console.error("[mbkauthe] Error fetching version information:", err);
|
|
860
432
|
res.status(500).send(`
|
|
@@ -870,6 +442,168 @@ router.get(["/mbkauthe/info", "/mbkauthe/i"], LoginLimit, async (_, res) => {
|
|
|
870
442
|
`);
|
|
871
443
|
}
|
|
872
444
|
});
|
|
445
|
+
/*
|
|
446
|
+
// Configure GitHub Strategy for login
|
|
447
|
+
passport.use('github-login', new GitHubStrategy({
|
|
448
|
+
clientID: process.env.GITHUB_CLIENT_ID,
|
|
449
|
+
clientSecret: process.env.GITHUB_CLIENT_SECRET,
|
|
450
|
+
callbackURL: '/mbkauthe/api/github/login/callback',
|
|
451
|
+
scope: ['user:email']
|
|
452
|
+
},
|
|
453
|
+
async (accessToken, refreshToken, profile, done) => {
|
|
454
|
+
try {
|
|
455
|
+
// Check if this GitHub account is linked to any user
|
|
456
|
+
const githubUser = await dblogin.query(
|
|
457
|
+
'SELECT ug.*, u."UserName", u."Role", u."Active", u."AllowedApps" FROM user_github ug JOIN "Users" u ON ug.user_name = u."UserName" WHERE ug.github_id = $1',
|
|
458
|
+
[profile.id]
|
|
459
|
+
);
|
|
460
|
+
|
|
461
|
+
if (githubUser.rows.length === 0) {
|
|
462
|
+
// GitHub account is not linked to any user
|
|
463
|
+
return done(new Error('GitHub account not linked to any user'));
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
const user = githubUser.rows[0];
|
|
467
|
+
|
|
468
|
+
// Check if the user account is active
|
|
469
|
+
if (!user.Active) {
|
|
470
|
+
return done(new Error('Account is inactive'));
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
// Check if user is authorized for this app (same logic as regular login)
|
|
474
|
+
if (user.Role !== "SuperAdmin") {
|
|
475
|
+
const allowedApps = user.AllowedApps;
|
|
476
|
+
if (!allowedApps || !allowedApps.some(app => app.toLowerCase() === mbkautheVar.APP_NAME.toLowerCase())) {
|
|
477
|
+
return done(new Error(`Not authorized to use ${mbkautheVar.APP_NAME}`));
|
|
478
|
+
}
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
// Return user data for login
|
|
482
|
+
return done(null, {
|
|
483
|
+
id: user.id, // This should be the user ID from the Users table
|
|
484
|
+
username: user.UserName,
|
|
485
|
+
role: user.Role,
|
|
486
|
+
githubId: user.github_id,
|
|
487
|
+
githubUsername: user.github_username
|
|
488
|
+
});
|
|
489
|
+
} catch (err) {
|
|
490
|
+
console.error('[mbkauthe] GitHub login error:', err);
|
|
491
|
+
return done(err);
|
|
492
|
+
}
|
|
493
|
+
}
|
|
494
|
+
));
|
|
495
|
+
|
|
496
|
+
// Serialize/Deserialize user for GitHub login
|
|
497
|
+
passport.serializeUser((user, done) => {
|
|
498
|
+
done(null, user);
|
|
499
|
+
});
|
|
873
500
|
|
|
501
|
+
passport.deserializeUser((user, done) => {
|
|
502
|
+
done(null, user);
|
|
503
|
+
});
|
|
504
|
+
|
|
505
|
+
// Initialize passport
|
|
506
|
+
router.use(passport.initialize());
|
|
507
|
+
router.use(passport.session());
|
|
508
|
+
|
|
509
|
+
// GitHub login initiation
|
|
510
|
+
router.get('/mbkauthe/api/github/login', passport.authenticate('github-login'));
|
|
511
|
+
|
|
512
|
+
// GitHub login callback
|
|
513
|
+
router.get('/mbkauthe/api/github/login/callback',
|
|
514
|
+
passport.authenticate('github-login', {
|
|
515
|
+
failureRedirect: '/mbkauthe/login?error=github_auth_failed',
|
|
516
|
+
session: false // We'll handle session manually
|
|
517
|
+
}),
|
|
518
|
+
async (req, res) => {
|
|
519
|
+
try {
|
|
520
|
+
const githubUser = req.user;
|
|
521
|
+
|
|
522
|
+
// Find the actual user record
|
|
523
|
+
const userQuery = `SELECT * FROM "Users" WHERE "UserName" = $1`;
|
|
524
|
+
const userResult = await dblogin.query(userQuery, [githubUser.username]);
|
|
525
|
+
|
|
526
|
+
if (userResult.rows.length === 0) {
|
|
527
|
+
console.log(`[mbkauthe] GitHub login: User not found: ${githubUser.username}`);
|
|
528
|
+
return res.redirect('/mbkauthe/login?error=user_not_found');
|
|
529
|
+
}
|
|
530
|
+
|
|
531
|
+
const user = userResult.rows[0];
|
|
532
|
+
|
|
533
|
+
// Check 2FA if enabled
|
|
534
|
+
if ((mbkautheVar.MBKAUTH_TWO_FA_ENABLE || "").toLowerCase() === "true") {
|
|
535
|
+
const twoFAQuery = `SELECT "TwoFAStatus" FROM "TwoFA" WHERE "UserName" = $1`;
|
|
536
|
+
const twoFAResult = await dblogin.query(twoFAQuery, [githubUser.username]);
|
|
537
|
+
|
|
538
|
+
if (twoFAResult.rows.length > 0 && twoFAResult.rows[0].TwoFAStatus) {
|
|
539
|
+
// 2FA is enabled, store pre-auth user and redirect to 2FA
|
|
540
|
+
req.session.preAuthUser = {
|
|
541
|
+
id: user.id,
|
|
542
|
+
username: user.UserName,
|
|
543
|
+
role: user.Role,
|
|
544
|
+
loginMethod: 'github'
|
|
545
|
+
};
|
|
546
|
+
console.log(`[mbkauthe] GitHub login: 2FA required for user: ${githubUser.username}`);
|
|
547
|
+
return res.redirect('/mbkauthe/2fa');
|
|
548
|
+
}
|
|
549
|
+
}
|
|
550
|
+
|
|
551
|
+
// Complete login process
|
|
552
|
+
const userForSession = {
|
|
553
|
+
id: user.id,
|
|
554
|
+
username: user.UserName,
|
|
555
|
+
role: user.Role,
|
|
556
|
+
};
|
|
557
|
+
|
|
558
|
+
// Generate session and complete login
|
|
559
|
+
const sessionId = crypto.randomBytes(256).toString("hex");
|
|
560
|
+
console.log(`[mbkauthe] GitHub login: Generated session ID for username: ${user.UserName}`);
|
|
561
|
+
|
|
562
|
+
// Delete old session record for this user
|
|
563
|
+
await dblogin.query('DELETE FROM "session" WHERE username = $1', [user.UserName]);
|
|
564
|
+
|
|
565
|
+
await dblogin.query(`UPDATE "Users" SET "SessionId" = $1 WHERE "id" = $2`, [
|
|
566
|
+
sessionId,
|
|
567
|
+
user.id,
|
|
568
|
+
]);
|
|
569
|
+
|
|
570
|
+
req.session.user = {
|
|
571
|
+
id: user.id,
|
|
572
|
+
username: user.UserName,
|
|
573
|
+
role: user.Role,
|
|
574
|
+
sessionId,
|
|
575
|
+
};
|
|
576
|
+
|
|
577
|
+
req.session.save(async (err) => {
|
|
578
|
+
if (err) {
|
|
579
|
+
console.log("[mbkauthe] GitHub login session save error:", err);
|
|
580
|
+
return res.redirect('/mbkauthe/login?error=session_error');
|
|
581
|
+
}
|
|
582
|
+
|
|
583
|
+
try {
|
|
584
|
+
await dblogin.query(
|
|
585
|
+
'UPDATE "session" SET username = $1 WHERE sid = $2',
|
|
586
|
+
[user.UserName, req.sessionID]
|
|
587
|
+
);
|
|
588
|
+
} catch (e) {
|
|
589
|
+
console.log("[mbkauthe] GitHub login: Failed to update username in session table:", e);
|
|
590
|
+
}
|
|
591
|
+
|
|
592
|
+
const cookieOptions = getCookieOptions();
|
|
593
|
+
res.cookie("sessionId", sessionId, cookieOptions);
|
|
594
|
+
console.log(`[mbkauthe] GitHub login: User "${user.UserName}" logged in successfully`);
|
|
595
|
+
|
|
596
|
+
// Redirect to the configured URL or home
|
|
597
|
+
const redirectUrl = mbkautheVar.loginRedirectURL || '/home';
|
|
598
|
+
res.redirect(redirectUrl);
|
|
599
|
+
});
|
|
600
|
+
|
|
601
|
+
} catch (err) {
|
|
602
|
+
console.error('[mbkauthe] GitHub login callback error:', err);
|
|
603
|
+
res.redirect('/mbkauthe/login?error=internal_error');
|
|
604
|
+
}
|
|
605
|
+
}
|
|
606
|
+
);
|
|
607
|
+
*/
|
|
874
608
|
export { getLatestVersion };
|
|
875
609
|
export default router;
|
|
@@ -113,7 +113,7 @@ async function validateSession(req, res, next) {
|
|
|
113
113
|
}
|
|
114
114
|
}
|
|
115
115
|
|
|
116
|
-
const checkRolePermission = (requiredRole) => {
|
|
116
|
+
const checkRolePermission = (requiredRole, notAllowed) => {
|
|
117
117
|
return async (req, res, next) => {
|
|
118
118
|
try {
|
|
119
119
|
if (!req.session || !req.session.user || !req.session.user.id) {
|
|
@@ -143,6 +143,19 @@ const checkRolePermission = (requiredRole) => {
|
|
|
143
143
|
}
|
|
144
144
|
|
|
145
145
|
const userRole = result.rows[0].Role;
|
|
146
|
+
|
|
147
|
+
// Check notAllowed role
|
|
148
|
+
if (notAllowed && userRole === notAllowed) {
|
|
149
|
+
return res.render("Error/dError.handlebars", {
|
|
150
|
+
layout: false,
|
|
151
|
+
code: 403,
|
|
152
|
+
error: "Access Denied",
|
|
153
|
+
message: `You are not allowed to access this resource with role: ${notAllowed}`,
|
|
154
|
+
pagename: "Home",
|
|
155
|
+
page: `/${mbkautheVar.loginRedirectURL}`
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
|
|
146
159
|
if (userRole !== requiredRole) {
|
|
147
160
|
return res.render("Error/dError.handlebars", {
|
|
148
161
|
layout: false,
|
|
@@ -162,64 +175,14 @@ const checkRolePermission = (requiredRole) => {
|
|
|
162
175
|
};
|
|
163
176
|
};
|
|
164
177
|
|
|
165
|
-
const validateSessionAndRole = (requiredRole) => {
|
|
178
|
+
const validateSessionAndRole = (requiredRole, notAllowed) => {
|
|
166
179
|
return async (req, res, next) => {
|
|
167
180
|
await validateSession(req, res, async () => {
|
|
168
|
-
await checkRolePermission(requiredRole)(req, res, next);
|
|
181
|
+
await checkRolePermission(requiredRole, notAllowed)(req, res, next);
|
|
169
182
|
});
|
|
170
183
|
};
|
|
171
184
|
};
|
|
172
185
|
|
|
173
|
-
async function getUserData(UserName, parameters) {
|
|
174
|
-
try {
|
|
175
|
-
if (!parameters || parameters.length === 0) {
|
|
176
|
-
throw new Error("Parameters are required to fetch user data");
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
const userFields = [
|
|
180
|
-
"Password", "UserName", "Role", "Active", "GuestRole", "HaveMailAccount", "AllowedApps",
|
|
181
|
-
];
|
|
182
|
-
const profileFields = [
|
|
183
|
-
"FullName", "email", "Image", "ProjectLinks", "SocialAccounts", "Bio", "Positions",
|
|
184
|
-
];
|
|
185
|
-
|
|
186
|
-
let userParameters = [];
|
|
187
|
-
let profileParameters = [];
|
|
188
|
-
|
|
189
|
-
if (parameters === "profiledata") {
|
|
190
|
-
userParameters = userFields.filter(field => field !== "Password");
|
|
191
|
-
profileParameters = profileFields;
|
|
192
|
-
} else {
|
|
193
|
-
userParameters = userFields.filter(field => parameters.includes(field));
|
|
194
|
-
profileParameters = profileFields.filter(field => parameters.includes(field));
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
let userResult = {};
|
|
198
|
-
if (userParameters.length > 0) {
|
|
199
|
-
const userQuery = `SELECT ${userParameters.map(field => `"${field}"`).join(", ")}
|
|
200
|
-
FROM "Users" WHERE "UserName" = $1`;
|
|
201
|
-
const userQueryResult = await dblogin.query(userQuery, [UserName]);
|
|
202
|
-
if (userQueryResult.rows.length === 0) return { error: "User not found" };
|
|
203
|
-
userResult = userQueryResult.rows[0];
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
let profileResult = {};
|
|
207
|
-
if (profileParameters.length > 0) {
|
|
208
|
-
const profileQuery = `SELECT ${profileParameters.map(field => `"${field}"`).join(", ")}
|
|
209
|
-
FROM profiledata WHERE "UserName" = $1`;
|
|
210
|
-
const profileQueryResult = await dblogin.query(profileQuery, [UserName]);
|
|
211
|
-
if (profileQueryResult.rows.length === 0) return { error: "Profile data not found" };
|
|
212
|
-
profileResult = profileQueryResult.rows[0];
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
const combinedResult = { ...userResult, ...profileResult };
|
|
216
|
-
return combinedResult;
|
|
217
|
-
} catch (err) {
|
|
218
|
-
console.error("[mbkauthe] Error fetching user data:", err.message);
|
|
219
|
-
throw err;
|
|
220
|
-
}
|
|
221
|
-
}
|
|
222
|
-
|
|
223
186
|
const authenticate = (authentication) => {
|
|
224
187
|
return (req, res, next) => {
|
|
225
188
|
const token = req.headers["authorization"];
|
|
@@ -331,4 +294,4 @@ const authapi = (requiredRole = []) => {
|
|
|
331
294
|
};
|
|
332
295
|
};
|
|
333
296
|
|
|
334
|
-
export { validateSession, checkRolePermission, validateSessionAndRole,
|
|
297
|
+
export { validateSession, checkRolePermission, validateSessionAndRole, authenticate, authapi };
|
package/package.json
CHANGED
|
@@ -0,0 +1,236 @@
|
|
|
1
|
+
<html>
|
|
2
|
+
|
|
3
|
+
<head>
|
|
4
|
+
<title>Version and Configuration Information</title>
|
|
5
|
+
<link rel="icon" type="image/x-icon" href="https://mbktechstudio.com/Assets/Images/Icon/dgicon.svg">
|
|
6
|
+
|
|
7
|
+
<style>
|
|
8
|
+
:root {
|
|
9
|
+
--bg-color: #121212;
|
|
10
|
+
--card-bg: #1e1e1e;
|
|
11
|
+
--text-color: #e0e0e0;
|
|
12
|
+
--text-secondary: #a0a0a0;
|
|
13
|
+
--primary: #bb86fc;
|
|
14
|
+
--primary-dark: #3700b3;
|
|
15
|
+
--secondary: #03dac6;
|
|
16
|
+
--border-color: #333;
|
|
17
|
+
--success: #4caf50;
|
|
18
|
+
--warning: #ff9800;
|
|
19
|
+
--error: #f44336;
|
|
20
|
+
--key-color: #bb86fc;
|
|
21
|
+
--string-color: #03dac6;
|
|
22
|
+
--number-color: #ff7043;
|
|
23
|
+
--boolean-color: #7986cb;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
body {
|
|
27
|
+
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
|
|
28
|
+
margin: 0;
|
|
29
|
+
padding: 20px;
|
|
30
|
+
background-color: var(--bg-color);
|
|
31
|
+
color: var(--text-color);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
.container {
|
|
35
|
+
max-width: 1000px;
|
|
36
|
+
margin: 0 auto;
|
|
37
|
+
padding: 20px;
|
|
38
|
+
background: var(--card-bg);
|
|
39
|
+
border-radius: 8px;
|
|
40
|
+
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.3);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
h1 {
|
|
44
|
+
color: var(--primary);
|
|
45
|
+
text-align: center;
|
|
46
|
+
margin-bottom: 30px;
|
|
47
|
+
padding-bottom: 10px;
|
|
48
|
+
border-bottom: 1px solid var(--border-color);
|
|
49
|
+
font-weight: bold;
|
|
50
|
+
letter-spacing: 1px;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
.info-section {
|
|
54
|
+
margin-bottom: 25px;
|
|
55
|
+
padding: 20px;
|
|
56
|
+
border: 1px solid var(--border-color);
|
|
57
|
+
border-radius: 8px;
|
|
58
|
+
background-color: rgba(30, 30, 30, 0.7);
|
|
59
|
+
transition: all 0.3s ease;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
.info-section:hover {
|
|
63
|
+
border-color: var(--primary);
|
|
64
|
+
box-shadow: 0 0 0 1px var(--primary);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
.info-section h2 {
|
|
68
|
+
color: var(--primary);
|
|
69
|
+
border-bottom: 2px solid var(--primary-dark);
|
|
70
|
+
padding-bottom: 8px;
|
|
71
|
+
margin-top: 0;
|
|
72
|
+
margin-bottom: 15px;
|
|
73
|
+
font-size: 1.2em;
|
|
74
|
+
display: flex;
|
|
75
|
+
justify-content: space-between;
|
|
76
|
+
align-items: center;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
.info-row {
|
|
80
|
+
display: flex;
|
|
81
|
+
margin-bottom: 10px;
|
|
82
|
+
padding-bottom: 10px;
|
|
83
|
+
border-bottom: 1px solid var(--border-color);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
.info-label {
|
|
87
|
+
font-weight: 600;
|
|
88
|
+
color: var(--text-secondary);
|
|
89
|
+
min-width: 220px;
|
|
90
|
+
font-size: 0.95em;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
.info-value {
|
|
94
|
+
flex: 1;
|
|
95
|
+
word-break: break-word;
|
|
96
|
+
color: var(--text-color);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
.version-status {
|
|
100
|
+
display: inline-block;
|
|
101
|
+
padding: 3px 10px;
|
|
102
|
+
border-radius: 12px;
|
|
103
|
+
font-size: 0.8em;
|
|
104
|
+
font-weight: 600;
|
|
105
|
+
margin-left: 10px;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
.version-up-to-date {
|
|
109
|
+
background: rgba(76, 175, 80, 0.2);
|
|
110
|
+
color: var(--success);
|
|
111
|
+
border: 1px solid var(--success);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
.version-outdated {
|
|
115
|
+
background: rgba(244, 67, 54, 0.2);
|
|
116
|
+
color: var(--error);
|
|
117
|
+
border: 1px solid var(--error);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
.version-fetch-error {
|
|
121
|
+
background: rgba(255, 152, 0, 0.2);
|
|
122
|
+
color: var(--warning);
|
|
123
|
+
border: 1px solid var(--warning);
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
::-webkit-scrollbar {
|
|
127
|
+
width: 8px;
|
|
128
|
+
height: 8px;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
::-webkit-scrollbar-track {
|
|
132
|
+
background: #2d2d2d;
|
|
133
|
+
border-radius: 4px;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
::-webkit-scrollbar-thumb {
|
|
137
|
+
background: #555;
|
|
138
|
+
border-radius: 4px;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
::-webkit-scrollbar-thumb:hover {
|
|
142
|
+
background: var(--primary);
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
/* Tooltip for copy button */
|
|
146
|
+
.tooltip {
|
|
147
|
+
position: relative;
|
|
148
|
+
display: inline-block;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
.tooltip .tooltiptext {
|
|
152
|
+
visibility: hidden;
|
|
153
|
+
width: 120px;
|
|
154
|
+
background-color: #333;
|
|
155
|
+
color: #fff;
|
|
156
|
+
text-align: center;
|
|
157
|
+
border-radius: 6px;
|
|
158
|
+
padding: 5px;
|
|
159
|
+
position: absolute;
|
|
160
|
+
z-index: 1;
|
|
161
|
+
bottom: 125%;
|
|
162
|
+
left: 50%;
|
|
163
|
+
margin-left: -60px;
|
|
164
|
+
opacity: 0;
|
|
165
|
+
transition: opacity 0.3s;
|
|
166
|
+
font-size: 0.8em;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
.tooltip:hover .tooltiptext {
|
|
170
|
+
visibility: visible;
|
|
171
|
+
opacity: 1;
|
|
172
|
+
}
|
|
173
|
+
</style>
|
|
174
|
+
<link href="https://fonts.googleapis.com/css2?family=Fira+Code:wght@400;500&display=swap" rel="stylesheet">
|
|
175
|
+
</head>
|
|
176
|
+
|
|
177
|
+
<body>
|
|
178
|
+
<div class="container">
|
|
179
|
+
<h1>Version and Configuration Dashboard</h1>
|
|
180
|
+
|
|
181
|
+
<div class="info-section">
|
|
182
|
+
<h2>Version Information</h2>
|
|
183
|
+
<div class="info-row">
|
|
184
|
+
<div class="info-label">Current Version:</div>
|
|
185
|
+
<div class="info-value" id="CurrentVersion">{{version}}</div>
|
|
186
|
+
</div>
|
|
187
|
+
<div class="info-row">
|
|
188
|
+
<div class="info-label">Latest Version:</div>
|
|
189
|
+
<div class="info-value">
|
|
190
|
+
{{latestVersion}}
|
|
191
|
+
|
|
192
|
+
{{#if (eq latestVersion version)}}
|
|
193
|
+
<span class="version-status version-up-to-date">Up to date</span>
|
|
194
|
+
{{/if}}
|
|
195
|
+
|
|
196
|
+
</div>
|
|
197
|
+
</div>
|
|
198
|
+
</div>
|
|
199
|
+
|
|
200
|
+
<div class="info-section">
|
|
201
|
+
<h2>Configuration Information</h2>
|
|
202
|
+
<div class="info-row">
|
|
203
|
+
<div class="info-label">APP_NAME:</div>
|
|
204
|
+
<div class="info-value">{{mbkautheVar.APP_NAME}}</div>
|
|
205
|
+
</div>
|
|
206
|
+
<div class="info-row">
|
|
207
|
+
<div class="info-label">MBKAUTH_TWO_FA_ENABLE:</div>
|
|
208
|
+
<div class="info-value">{{mbkautheVar.MBKAUTH_TWO_FA_ENABLE}}</div>
|
|
209
|
+
</div>
|
|
210
|
+
<div class="info-row">
|
|
211
|
+
<div class="info-label">COOKIE_EXPIRE_TIME:</div>
|
|
212
|
+
<div class="info-value">{{mbkautheVar.COOKIE_EXPIRE_TIME}} Days</div>
|
|
213
|
+
</div>
|
|
214
|
+
<div class="info-row">
|
|
215
|
+
<div class="info-label">IS_DEPLOYED:</div>
|
|
216
|
+
<div class="info-value">{{mbkautheVar.IS_DEPLOYED}}</div>
|
|
217
|
+
</div>
|
|
218
|
+
<div class="info-row">
|
|
219
|
+
<div class="info-label">DOMAIN:</div>
|
|
220
|
+
<div class="info-value">{{mbkautheVar.DOMAIN}}</div>
|
|
221
|
+
</div>
|
|
222
|
+
<div class="info-row">
|
|
223
|
+
<div class="info-label">Login Redirect URL:</div>
|
|
224
|
+
<div class="info-value">{{mbkautheVar.loginRedirectURL}}</div>
|
|
225
|
+
</div>
|
|
226
|
+
<div class="info-row">
|
|
227
|
+
<div class="info-label">GitHub Login Enabled:</div>
|
|
228
|
+
<div class="info-value">{{mbkautheVar.GITHUB_LOGIN_ENABLED}}</div>
|
|
229
|
+
</div>
|
|
230
|
+
</div>
|
|
231
|
+
|
|
232
|
+
</div>
|
|
233
|
+
|
|
234
|
+
</body>
|
|
235
|
+
|
|
236
|
+
</html>
|
|
@@ -242,6 +242,60 @@
|
|
|
242
242
|
box-shadow: none;
|
|
243
243
|
}
|
|
244
244
|
|
|
245
|
+
.social-login {
|
|
246
|
+
margin-top: 1.5rem;
|
|
247
|
+
text-align: center;
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
.divider {
|
|
251
|
+
display: flex;
|
|
252
|
+
align-items: center;
|
|
253
|
+
justify-content: center;
|
|
254
|
+
margin: 1rem 0;
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
.divider::before,
|
|
258
|
+
.divider::after {
|
|
259
|
+
content: '';
|
|
260
|
+
flex: 1;
|
|
261
|
+
height: 1px;
|
|
262
|
+
background: var(--gray-dark);
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
.divider span {
|
|
266
|
+
background: var(--dark);
|
|
267
|
+
padding: 0 15px;
|
|
268
|
+
color: var(--gray);
|
|
269
|
+
font-size: 0.9rem;
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
.btn-github {
|
|
273
|
+
display: inline-flex;
|
|
274
|
+
align-items: center;
|
|
275
|
+
justify-content: center;
|
|
276
|
+
gap: 8px;
|
|
277
|
+
width: 100%;
|
|
278
|
+
padding: 12px 20px;
|
|
279
|
+
border-radius: var(--radius-sm);
|
|
280
|
+
background: #24292e;
|
|
281
|
+
color: white;
|
|
282
|
+
font-weight: 500;
|
|
283
|
+
font-size: 0.95rem;
|
|
284
|
+
text-decoration: none;
|
|
285
|
+
transition: var(--transition);
|
|
286
|
+
box-shadow: var(--shadow-sm);
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
.btn-github:hover {
|
|
290
|
+
background: #3b4045;
|
|
291
|
+
box-shadow: var(--shadow-md);
|
|
292
|
+
transform: translateY(-2px);
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
.btn-github i {
|
|
296
|
+
font-size: 1.1rem;
|
|
297
|
+
}
|
|
298
|
+
|
|
245
299
|
.login-links {
|
|
246
300
|
display: flex;
|
|
247
301
|
justify-content: space-between;
|
|
@@ -511,6 +565,17 @@
|
|
|
511
565
|
<button type="submit" class="btn-login" id="loginButton">
|
|
512
566
|
<span id="loginButtonText">Login</span>
|
|
513
567
|
</button>
|
|
568
|
+
{{#if githubLoginEnabled }}
|
|
569
|
+
<div class="social-login">
|
|
570
|
+
<div class="divider">
|
|
571
|
+
<span>or</span>
|
|
572
|
+
</div>
|
|
573
|
+
<a href="/mbkauthe/api/github/login" class="btn-github">
|
|
574
|
+
<i class="fab fa-github"></i>
|
|
575
|
+
<span>Continue with GitHub</span>
|
|
576
|
+
</a>
|
|
577
|
+
</div>
|
|
578
|
+
{{/if }}
|
|
514
579
|
|
|
515
580
|
{{#if userLoggedIn }}
|
|
516
581
|
<div class="WarningboxInfo">
|