mbkauthe 2.1.0 → 2.3.0
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 +2 -2
- package/README.md +128 -7
- package/docs/api.md +48 -1
- package/docs/db.md +53 -15
- package/{env.md → docs/env.md} +76 -2
- package/index.js +10 -30
- package/lib/config.js +200 -0
- package/lib/main.js +226 -153
- package/lib/pool.js +1 -25
- package/lib/validateSessionAndRole.js +19 -131
- package/package.json +2 -2
- package/public/bg.webp +0 -0
- package/public/icon.ico +0 -0
- package/public/icon.svg +5 -0
- package/views/2fa.handlebars +21 -41
- package/views/Error/dError.handlebars +7 -35
- package/views/backgroundElements.handlebars +6 -0
- package/views/head.handlebars +14 -0
- package/views/header.handlebars +15 -0
- package/views/info.handlebars +8 -29
- package/views/loginmbkauthe.handlebars +5 -40
- package/views/sharedStyles.handlebars +112 -1
- package/views/versionInfo.handlebars +6 -0
- package/public/bg.avif +0 -0
package/lib/pool.js
CHANGED
|
@@ -1,30 +1,6 @@
|
|
|
1
1
|
import pkg from "pg";
|
|
2
2
|
const { Pool } = pkg;
|
|
3
|
-
|
|
4
|
-
import dotenv from "dotenv";
|
|
5
|
-
dotenv.config();
|
|
6
|
-
|
|
7
|
-
let mbkautheVar;
|
|
8
|
-
try {
|
|
9
|
-
mbkautheVar = JSON.parse(process.env.mbkautheVar);
|
|
10
|
-
} catch (error) {
|
|
11
|
-
throw new Error("Invalid JSON in process.env.mbkautheVar");
|
|
12
|
-
}
|
|
13
|
-
if (!mbkautheVar) {
|
|
14
|
-
throw new Error("mbkautheVar is not defined");
|
|
15
|
-
}
|
|
16
|
-
const requiredKeys = ["APP_NAME", "SESSION_SECRET_KEY", "IS_DEPLOYED", "LOGIN_DB", "MBKAUTH_TWO_FA_ENABLE", "DOMAIN"];
|
|
17
|
-
requiredKeys.forEach(key => {
|
|
18
|
-
if (!mbkautheVar[key]) {
|
|
19
|
-
throw new Error(`mbkautheVar.${key} is required`);
|
|
20
|
-
}
|
|
21
|
-
});
|
|
22
|
-
if (mbkautheVar.COOKIE_EXPIRE_TIME !== undefined) {
|
|
23
|
-
const expireTime = parseFloat(mbkautheVar.COOKIE_EXPIRE_TIME);
|
|
24
|
-
if (isNaN(expireTime) || expireTime <= 0) {
|
|
25
|
-
throw new Error("mbkautheVar.COOKIE_EXPIRE_TIME must be a valid positive number");
|
|
26
|
-
}
|
|
27
|
-
}
|
|
3
|
+
import { mbkautheVar } from "./config.js";
|
|
28
4
|
|
|
29
5
|
const poolConfig = {
|
|
30
6
|
connectionString: mbkautheVar.LOGIN_DB,
|
|
@@ -1,29 +1,11 @@
|
|
|
1
1
|
import { dblogin } from "./pool.js";
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
const getCookieOptions = () => ({
|
|
5
|
-
maxAge: mbkautheVar.COOKIE_EXPIRE_TIME * 24 * 60 * 60 * 1000,
|
|
6
|
-
domain: mbkautheVar.IS_DEPLOYED === 'true' ? `.${mbkautheVar.DOMAIN}` : undefined,
|
|
7
|
-
secure: mbkautheVar.IS_DEPLOYED === 'true',
|
|
8
|
-
sameSite: 'lax',
|
|
9
|
-
path: '/',
|
|
10
|
-
httpOnly: true
|
|
11
|
-
});
|
|
12
|
-
|
|
13
|
-
const getClearCookieOptions = () => ({
|
|
14
|
-
domain: mbkautheVar.IS_DEPLOYED === 'true' ? `.${mbkautheVar.DOMAIN}` : undefined,
|
|
15
|
-
secure: mbkautheVar.IS_DEPLOYED === 'true',
|
|
16
|
-
sameSite: 'lax',
|
|
17
|
-
path: '/',
|
|
18
|
-
httpOnly: true
|
|
19
|
-
});
|
|
2
|
+
import { mbkautheVar, renderError, clearSessionCookies } from "./config.js";
|
|
20
3
|
|
|
21
4
|
async function validateSession(req, res, next) {
|
|
22
5
|
if (!req.session.user) {
|
|
23
6
|
console.log("[mbkauthe] User not authenticated");
|
|
24
7
|
console.log("[mbkauthe]: ", req.session.user);
|
|
25
|
-
return res
|
|
26
|
-
layout: false,
|
|
8
|
+
return renderError(res, {
|
|
27
9
|
code: 401,
|
|
28
10
|
error: "Not Logged In",
|
|
29
11
|
message: "You Are Not Logged In. Please Log In To Continue.",
|
|
@@ -38,19 +20,15 @@ async function validateSession(req, res, next) {
|
|
|
38
20
|
// Normalize sessionId to lowercase for consistent comparison
|
|
39
21
|
const normalizedSessionId = sessionId.toLowerCase();
|
|
40
22
|
|
|
41
|
-
// Single optimized query to validate session
|
|
42
|
-
const query = `SELECT "SessionId", "Active" FROM "Users" WHERE "id" = $1`;
|
|
23
|
+
// Single optimized query to validate session and get role
|
|
24
|
+
const query = `SELECT "SessionId", "Active", "Role" FROM "Users" WHERE "id" = $1`;
|
|
43
25
|
const result = await dblogin.query({ name: 'validate-user-session', text: query, values: [id] });
|
|
44
26
|
|
|
45
27
|
if (result.rows.length === 0 || result.rows[0].SessionId.toLowerCase() !== normalizedSessionId) {
|
|
46
28
|
console.log(`[mbkauthe] Session invalidated for user "${req.session.user.username}"`);
|
|
47
29
|
req.session.destroy();
|
|
48
|
-
|
|
49
|
-
res
|
|
50
|
-
res.clearCookie("sessionId", cookieOptions);
|
|
51
|
-
res.clearCookie("username", cookieOptions);
|
|
52
|
-
return res.render("Error/dError.handlebars", {
|
|
53
|
-
layout: false,
|
|
30
|
+
clearSessionCookies(res);
|
|
31
|
+
return renderError(res, {
|
|
54
32
|
code: 401,
|
|
55
33
|
error: "Session Expired",
|
|
56
34
|
message: "Your Session Has Expired. Please Log In Again.",
|
|
@@ -62,12 +40,8 @@ async function validateSession(req, res, next) {
|
|
|
62
40
|
if (!result.rows[0].Active) {
|
|
63
41
|
console.log(`[mbkauthe] Account is inactive for user "${req.session.user.username}"`);
|
|
64
42
|
req.session.destroy();
|
|
65
|
-
|
|
66
|
-
res
|
|
67
|
-
res.clearCookie("sessionId", cookieOptions);
|
|
68
|
-
res.clearCookie("username", cookieOptions);
|
|
69
|
-
return res.render("Error/dError.handlebars", {
|
|
70
|
-
layout: false,
|
|
43
|
+
clearSessionCookies(res);
|
|
44
|
+
return renderError(res, {
|
|
71
45
|
code: 401,
|
|
72
46
|
error: "Account Inactive",
|
|
73
47
|
message: "Your Account Is Inactive. Please Contact Support.",
|
|
@@ -80,12 +54,8 @@ async function validateSession(req, res, next) {
|
|
|
80
54
|
if (!allowedApps || !allowedApps.some(app => app.toLowerCase() === mbkautheVar.APP_NAME.toLowerCase())) {
|
|
81
55
|
console.warn(`[mbkauthe] User \"${req.session.user.username}\" is not authorized to use the application \"${mbkautheVar.APP_NAME}\"`);
|
|
82
56
|
req.session.destroy();
|
|
83
|
-
|
|
84
|
-
res
|
|
85
|
-
res.clearCookie("sessionId", cookieOptions);
|
|
86
|
-
res.clearCookie("username", cookieOptions);
|
|
87
|
-
return res.render("Error/dError.handlebars", {
|
|
88
|
-
layout: false,
|
|
57
|
+
clearSessionCookies(res);
|
|
58
|
+
return renderError(res, {
|
|
89
59
|
code: 401,
|
|
90
60
|
error: "Unauthorized",
|
|
91
61
|
message: `You Are Not Authorized To Use The Application \"${mbkautheVar.APP_NAME}\"`,
|
|
@@ -95,6 +65,9 @@ async function validateSession(req, res, next) {
|
|
|
95
65
|
}
|
|
96
66
|
}
|
|
97
67
|
|
|
68
|
+
// Store user role in request for checkRolePermission to use
|
|
69
|
+
req.userRole = result.rows[0].Role;
|
|
70
|
+
|
|
98
71
|
next();
|
|
99
72
|
} catch (err) {
|
|
100
73
|
console.error("[mbkauthe] Session validation error:", err);
|
|
@@ -107,8 +80,7 @@ const checkRolePermission = (requiredRoles, notAllowed) => {
|
|
|
107
80
|
try {
|
|
108
81
|
if (!req.session || !req.session.user || !req.session.user.id) {
|
|
109
82
|
console.log("[mbkauthe] User not authenticated");
|
|
110
|
-
return res
|
|
111
|
-
layout: false,
|
|
83
|
+
return renderError(res, {
|
|
112
84
|
code: 401,
|
|
113
85
|
error: "Not Logged In",
|
|
114
86
|
message: "You Are Not Logged In. Please Log In To Continue.",
|
|
@@ -117,21 +89,12 @@ const checkRolePermission = (requiredRoles, notAllowed) => {
|
|
|
117
89
|
});
|
|
118
90
|
}
|
|
119
91
|
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
const query = `SELECT "Role" FROM "Users" WHERE "id" = $1`;
|
|
123
|
-
const result = await dblogin.query({ name: 'check-role-permission', text: query, values: [userId] });
|
|
124
|
-
|
|
125
|
-
if (result.rows.length === 0) {
|
|
126
|
-
return res.status(401).json({ success: false, message: "Authentication failed" });
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
const userRole = result.rows[0].Role;
|
|
92
|
+
// Use role from validateSession to avoid additional DB query
|
|
93
|
+
const userRole = req.userRole;
|
|
130
94
|
|
|
131
95
|
// Check notAllowed role
|
|
132
96
|
if (notAllowed && userRole === notAllowed) {
|
|
133
|
-
return res
|
|
134
|
-
layout: false,
|
|
97
|
+
return renderError(res, {
|
|
135
98
|
code: 403,
|
|
136
99
|
error: "Access Denied",
|
|
137
100
|
message: "You are not allowed to access this resource",
|
|
@@ -150,8 +113,7 @@ const checkRolePermission = (requiredRoles, notAllowed) => {
|
|
|
150
113
|
|
|
151
114
|
// Check if user role is in allowed roles
|
|
152
115
|
if (!rolesArray.includes(userRole)) {
|
|
153
|
-
return res
|
|
154
|
-
layout: false,
|
|
116
|
+
return renderError(res, {
|
|
155
117
|
code: 403,
|
|
156
118
|
error: "Access Denied",
|
|
157
119
|
message: "You do not have permission to access this resource",
|
|
@@ -179,7 +141,6 @@ const validateSessionAndRole = (requiredRole, notAllowed) => {
|
|
|
179
141
|
const authenticate = (authentication) => {
|
|
180
142
|
return (req, res, next) => {
|
|
181
143
|
const token = req.headers["authorization"];
|
|
182
|
-
console.log(`[mbkauthe] Received token: ${token}`);
|
|
183
144
|
if (token === authentication) {
|
|
184
145
|
console.log("[mbkauthe] Authentication successful");
|
|
185
146
|
next();
|
|
@@ -190,78 +151,5 @@ const authenticate = (authentication) => {
|
|
|
190
151
|
};
|
|
191
152
|
};
|
|
192
153
|
|
|
193
|
-
const authapi = (requiredRole = []) => {
|
|
194
|
-
return (req, res, next) => {
|
|
195
|
-
const token = req.headers["authorization"];
|
|
196
|
-
|
|
197
|
-
// Validate token
|
|
198
|
-
if (!token) {
|
|
199
|
-
console.warn("[mbkauthe] [authapi] No token provided in the request headers");
|
|
200
|
-
return res.status(401).json({
|
|
201
|
-
success: false,
|
|
202
|
-
message: "Authorization token is required"
|
|
203
|
-
});
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
if (typeof token !== 'string' || token.length === 0 || token.length > 512) {
|
|
207
|
-
console.warn("[mbkauthe] [authapi] Invalid token format");
|
|
208
|
-
return res.status(401).json({
|
|
209
|
-
success: false,
|
|
210
|
-
message: "Invalid authorization token format"
|
|
211
|
-
});
|
|
212
|
-
}
|
|
213
|
-
|
|
214
|
-
if (typeof token === 'string' && token.length >= 64) {
|
|
215
|
-
console.log("[mbkauthe] [authapi] Received request with token:", token.substring(0, 3) + ".....", token.charAt(63));
|
|
216
|
-
} else {
|
|
217
|
-
console.log("[mbkauthe] [authapi] Received request with short token");
|
|
218
|
-
}
|
|
219
|
-
|
|
220
|
-
// Single query to validate API key and fetch user in one DB round trip.
|
|
221
|
-
(async () => {
|
|
222
|
-
try {
|
|
223
|
-
const jointQuery = `
|
|
224
|
-
SELECT u.id, u."UserName", u."Active", u."Role", k."key" as apikey
|
|
225
|
-
FROM "UserAuthApiKey" k
|
|
226
|
-
JOIN "Users" u ON u."UserName" = k.username
|
|
227
|
-
WHERE k."key" = $1 AND u."Active" = true
|
|
228
|
-
LIMIT 1
|
|
229
|
-
`;
|
|
230
|
-
|
|
231
|
-
const result = await dblogin.query({ name: 'validate-api-key', text: jointQuery, values: [token] });
|
|
232
|
-
|
|
233
|
-
if (result.rows.length === 0) {
|
|
234
|
-
console.warn("[mbkauthe] [authapi] Invalid token or associated user inactive");
|
|
235
|
-
return res.status(401).json({ success: false, message: "The AuthApiToken Is Invalid or user inactive" });
|
|
236
|
-
}
|
|
237
|
-
|
|
238
|
-
const user = result.rows[0];
|
|
239
|
-
|
|
240
|
-
if (user.UserName === "demo") {
|
|
241
|
-
console.warn("[mbkauthe] [authapi] Demo user attempted to access an endpoint. Access denied.");
|
|
242
|
-
return res.status(401).json({ success: false, message: "Demo user is not allowed to access endpoints" });
|
|
243
|
-
}
|
|
244
|
-
|
|
245
|
-
// role check
|
|
246
|
-
if ((requiredRole && user.Role !== requiredRole) && user.Role !== "SuperAdmin") {
|
|
247
|
-
console.warn(`[mbkauthe] [authapi] User does not have the required role. Required: ${requiredRole}, User's role: ${user.Role}`);
|
|
248
|
-
return res.status(403).json({ success: false, message: `Access denied. Required role: ${requiredRole}` });
|
|
249
|
-
}
|
|
250
|
-
|
|
251
|
-
req.user = {
|
|
252
|
-
username: user.UserName,
|
|
253
|
-
UserName: user.UserName,
|
|
254
|
-
role: user.Role,
|
|
255
|
-
Role: user.Role,
|
|
256
|
-
};
|
|
257
|
-
|
|
258
|
-
next();
|
|
259
|
-
} catch (err) {
|
|
260
|
-
console.error("[mbkauthe] [authapi] Database error while validating token/user:", err);
|
|
261
|
-
return res.status(500).json({ success: false, message: "Internal Server Error" });
|
|
262
|
-
}
|
|
263
|
-
})();
|
|
264
|
-
};
|
|
265
|
-
};
|
|
266
154
|
|
|
267
|
-
export { validateSession, checkRolePermission, validateSessionAndRole, authenticate
|
|
155
|
+
export { validateSession, checkRolePermission, validateSessionAndRole, authenticate };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mbkauthe",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.3.0",
|
|
4
4
|
"description": "MBKTech's reusable authentication system for Node.js applications.",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"type": "module",
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
"session",
|
|
20
20
|
"security"
|
|
21
21
|
],
|
|
22
|
-
"author": "Muhammad Bin Khalid <support@
|
|
22
|
+
"author": "Muhammad Bin Khalid <support@mbktech.org>",
|
|
23
23
|
"license": "MPL-2.0",
|
|
24
24
|
"bugs": {
|
|
25
25
|
"url": "https://github.com/MIbnEKhalid/mbkauthe/issues"
|
package/public/bg.webp
ADDED
|
Binary file
|
package/public/icon.ico
ADDED
|
Binary file
|
package/public/icon.svg
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
<svg data-v-423bf9ae="" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 90 90" class="iconAboveSlogan">
|
|
2
|
+
<g data-v-423bf9ae="" id="8db2a7f9-6efc-4f7e-ae5b-8ba33875da43" transform="matrix(2.8125,0,0,2.8125,0,0)" stroke="none" fill="#88df95">
|
|
3
|
+
<path d="M0 32h32V0H0v32zm19.377-19.492l6.936-6.936v20.855h-6.936V12.508zM5.688 5.572l6.936 6.936v13.919H5.688V5.572z"></path>
|
|
4
|
+
</g>
|
|
5
|
+
</svg>
|
package/views/2fa.handlebars
CHANGED
|
@@ -1,61 +1,38 @@
|
|
|
1
1
|
<!DOCTYPE html>
|
|
2
2
|
<html lang="en">
|
|
3
3
|
|
|
4
|
-
|
|
5
|
-
<meta charset="UTF-8">
|
|
6
|
-
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
7
|
-
<meta name="description"
|
|
8
|
-
content="Log in to portal.mbktech.org to access your resources and manage projects securely.">
|
|
9
|
-
<meta name="keywords" content="MBK Tech Studio, Web-Portal, Web, Portal, Admin-Panel, Admin, login">
|
|
10
|
-
<meta property="og:title" content="Login | MBK Tech Studio" />
|
|
11
|
-
<meta property="og:image" content="https://mbktech.org/Assets/Images/Icon/logo.png" />
|
|
12
|
-
<meta property="og:url" content="/mbkauthe/2fa">
|
|
13
|
-
<title>2FA | MBK Tech Studio Portal</title>
|
|
14
|
-
<link rel="icon" type="image/x-icon" href="https://mbktech.org/Assets/Images/Icon/dgicon.svg">
|
|
15
|
-
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
|
|
16
|
-
{{> sharedStyles}}
|
|
17
|
-
</head>
|
|
4
|
+
{{> head pageTitle="2FA" ogUrl="/mbkauthe/2fa"}}
|
|
18
5
|
|
|
19
6
|
<body>
|
|
20
|
-
|
|
21
|
-
<div class="header-container">
|
|
22
|
-
<a class="logo">
|
|
23
|
-
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 90 90" class="iconAboveSlogan">
|
|
24
|
-
<g id="8db2a7f9-6efc-4f7e-ae5b-8ba33875da43" transform="matrix(2.8125,0,0,2.8125,0,0)" stroke="none"
|
|
25
|
-
fill="#00b894">
|
|
26
|
-
<path
|
|
27
|
-
d="M0 32h32V0H0v32zm19.377-19.492l6.936-6.936v20.855h-6.936V12.508zM5.688 5.572l6.936 6.936v13.919H5.688V5.572z">
|
|
28
|
-
</path>
|
|
29
|
-
</g>
|
|
30
|
-
</svg>
|
|
31
|
-
<span class="logo-text">{{appName}} <span class="logo-comp">mbktech</span></span>
|
|
32
|
-
</a>
|
|
33
|
-
</div>
|
|
34
|
-
</header>
|
|
7
|
+
{{> header}}
|
|
35
8
|
|
|
36
9
|
{{> showmessage}}
|
|
37
10
|
|
|
38
11
|
<section class="login-container">
|
|
39
12
|
|
|
40
|
-
|
|
41
|
-
<i class="fas fa-microchip ai-element"></i>
|
|
42
|
-
<i class="fas fa-user-astronaut ai-element"></i>
|
|
43
|
-
<i class="fas fa-satellite-dish ai-element"></i>
|
|
44
|
-
<i class="fas fa-cloud ai-element"></i>
|
|
45
|
-
<i class="fas fa-shield-alt ai-element"></i>
|
|
13
|
+
{{> backgroundElements}}
|
|
46
14
|
|
|
47
15
|
<div class="login-box">
|
|
48
|
-
<h1 class="login-title">Two
|
|
16
|
+
<h1 class="login-title">Two-Factor Authentication</h1>
|
|
17
|
+
<p class="login-subtitle">Enter the 6-digit code from your authenticator app</p>
|
|
49
18
|
|
|
50
19
|
<form id="loginForm" method="POST">
|
|
51
20
|
<input type="hidden" name="_csrf" value="{{csrfToken}}">
|
|
52
21
|
<div class="form-group token-container" id="tokenCon">
|
|
53
22
|
<input id="token" class="form-input" type="text" name="token" placeholder=" " pattern="\d{6}"
|
|
54
|
-
title="Token must be exactly 6 digits" maxlength="6" minlength="6" />
|
|
23
|
+
title="Token must be exactly 6 digits" maxlength="6" minlength="6" autocomplete="off" required />
|
|
55
24
|
<label class="form-label">2FA Token</label>
|
|
56
25
|
<i class="fas fa-info-circle input-icon" onclick="tokeninfo()"></i>
|
|
57
26
|
</div>
|
|
58
27
|
|
|
28
|
+
<div class="trust-device-container">
|
|
29
|
+
<label class="trust-device-label">
|
|
30
|
+
<input type="checkbox" id="trustDevice" name="trustDevice" class="trust-device-checkbox" />
|
|
31
|
+
<span class="checkbox-custom"></span>
|
|
32
|
+
<span class="checkbox-text">Trust this device for {{DEVICE_TRUST_DURATION_DAYS}} days</span>
|
|
33
|
+
</label>
|
|
34
|
+
<i class="fas fa-info-circle trust-device-info" onclick="trustDeviceInfo()" title="Learn more about trusted devices"></i>
|
|
35
|
+
</div>
|
|
59
36
|
|
|
60
37
|
<button type="submit" class="btn-login" id="loginButton">
|
|
61
38
|
<span id="loginButtonText">Verify</span>
|
|
@@ -73,19 +50,21 @@
|
|
|
73
50
|
</div>
|
|
74
51
|
</section>
|
|
75
52
|
|
|
76
|
-
|
|
77
|
-
<div class="version-info">
|
|
78
|
-
v{{version}}
|
|
79
|
-
</div>
|
|
53
|
+
{{> versionInfo}}
|
|
80
54
|
|
|
81
55
|
<script>
|
|
82
56
|
function tokeninfo() {
|
|
83
57
|
showMessage(`The 2FA token is a 6-digit code generated by your authenticator app (such as Google Authenticator, Microsoft Authenticator, or Authy). Enter the code shown in your app to complete login. If you have not set up 2FA or are having trouble, please contact support.`, `What is the 2FA token?`);
|
|
84
58
|
}
|
|
85
59
|
|
|
60
|
+
function trustDeviceInfo() {
|
|
61
|
+
showMessage(`When you trust this device, you won't need to enter a 2FA code for {{DEVICE_TRUST_DURATION_DAYS}} days when logging in from this browser. This makes logging in faster while keeping your account secure. You can revoke trusted devices at any time from your account settings.`, `Trust This Device`);
|
|
62
|
+
}
|
|
63
|
+
|
|
86
64
|
document.getElementById('loginForm').addEventListener('submit', async (e) => {
|
|
87
65
|
e.preventDefault();
|
|
88
66
|
const token = document.getElementById('token').value;
|
|
67
|
+
const trustDevice = document.getElementById('trustDevice').checked;
|
|
89
68
|
const csrfToken = document.querySelector('input[name="_csrf"]').value;
|
|
90
69
|
const loginButton = document.getElementById('loginButton');
|
|
91
70
|
const loginButtonText = document.getElementById('loginButtonText');
|
|
@@ -101,6 +80,7 @@
|
|
|
101
80
|
},
|
|
102
81
|
body: JSON.stringify({
|
|
103
82
|
token,
|
|
83
|
+
trustDevice,
|
|
104
84
|
_csrf: csrfToken
|
|
105
85
|
})
|
|
106
86
|
});
|
|
@@ -1,14 +1,7 @@
|
|
|
1
1
|
<!DOCTYPE html>
|
|
2
2
|
<html lang="en">
|
|
3
3
|
|
|
4
|
-
<
|
|
5
|
-
<meta charset="UTF-8">
|
|
6
|
-
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
7
|
-
<title>{{code}} - {{error}}</title>
|
|
8
|
-
<link rel="icon" type="image/x-icon" href="https://mbktech.org/Assets/Images/Icon/dgicon.svg">
|
|
9
|
-
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
|
|
10
|
-
{{> sharedStyles}}
|
|
11
|
-
<style>
|
|
4
|
+
{{> head pageCode=code pageError=error ogUrl="/error" extraStyles="<style>
|
|
12
5
|
.login-box {
|
|
13
6
|
max-width: 600px;
|
|
14
7
|
}
|
|
@@ -171,34 +164,14 @@
|
|
|
171
164
|
gap: 0.5rem;
|
|
172
165
|
}
|
|
173
166
|
}
|
|
174
|
-
</style>
|
|
175
|
-
</head>
|
|
167
|
+
</style>"}}
|
|
176
168
|
|
|
177
169
|
<body>
|
|
178
|
-
|
|
179
|
-
<div class="header-container">
|
|
180
|
-
<a class="logo">
|
|
181
|
-
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 90 90" class="iconAboveSlogan">
|
|
182
|
-
<g id="8db2a7f9-6efc-4f7e-ae5b-8ba33875da43" transform="matrix(2.8125,0,0,2.8125,0,0)" stroke="none"
|
|
183
|
-
fill="#00b894">
|
|
184
|
-
<path
|
|
185
|
-
d="M0 32h32V0H0v32zm19.377-19.492l6.936-6.936v20.855h-6.936V12.508zM5.688 5.572l6.936 6.936v13.919H5.688V5.572z">
|
|
186
|
-
</path>
|
|
187
|
-
</g>
|
|
188
|
-
</svg>
|
|
189
|
-
<span class="logo-text">{{#if app}}{{app}}{{else}}mbkauthe{{/if}} <span
|
|
190
|
-
class="logo-comp">mbktech</span></span>
|
|
191
|
-
</a>
|
|
192
|
-
</div>
|
|
193
|
-
</header>
|
|
194
|
-
|
|
170
|
+
{{> header}}
|
|
195
171
|
|
|
196
172
|
<section class="login-container">
|
|
197
173
|
|
|
198
|
-
|
|
199
|
-
<i class="fas fa-database ai-element"></i>
|
|
200
|
-
<i class="fas fa-network-wired ai-element"></i>
|
|
201
|
-
<i class="fas fa-code ai-element"></i>
|
|
174
|
+
{{> backgroundElements}}
|
|
202
175
|
|
|
203
176
|
<div class="login-box">
|
|
204
177
|
<h1 class="status-code">{{code}}</h1>
|
|
@@ -230,10 +203,9 @@
|
|
|
230
203
|
|
|
231
204
|
</div>
|
|
232
205
|
</section>
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
</div>
|
|
206
|
+
|
|
207
|
+
{{> versionInfo}}
|
|
208
|
+
|
|
237
209
|
<script>
|
|
238
210
|
function toggleDetailsDropdown(element) {
|
|
239
211
|
const errorDetailsWrapper = element.querySelector('.error-details-wrapper');
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
<i class="fas fa-robot ai-element"></i>
|
|
2
|
+
<i class="fas fa-microchip ai-element"></i>
|
|
3
|
+
<i class="fas fa-user-astronaut ai-element"></i>
|
|
4
|
+
<i class="fas fa-satellite-dish ai-element"></i>
|
|
5
|
+
<i class="fas fa-cloud ai-element"></i>
|
|
6
|
+
<i class="fas fa-shield-alt ai-element"></i>
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
<head>
|
|
2
|
+
<meta charset="UTF-8">
|
|
3
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
4
|
+
<meta name="description" content="{{#if description}}{{description}}{{else}}Log in to portal.mbktech.org to access your resources and manage projects securely.{{/if}}">
|
|
5
|
+
<meta name="keywords" content="MBK Tech, Web-Portal, Web, Portal, Admin-Panel, Admin, login">
|
|
6
|
+
<meta property="og:title" content="{{#if pageTitle}}{{pageTitle}}{{else}}{{#if pageCode}}{{pageCode}}{{/if}}{{#if pageError}} - {{pageError}}{{/if}}{{/if}} | MBK Tech" />
|
|
7
|
+
<meta property="og:image" content="https://mbktech.org/Assets/Images/Icon/logo.png" />
|
|
8
|
+
<meta property="og:url" content="{{ogUrl}}">
|
|
9
|
+
<title>{{#if pageTitle}}{{pageTitle}}{{else}}{{#if pageCode}}{{pageCode}}{{/if}}{{#if pageError}} - {{pageError}}{{/if}}{{/if}} | MBK Tech Portal</title>
|
|
10
|
+
<link rel="icon" type="image/x-icon" href="/favicon.ico">
|
|
11
|
+
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
|
|
12
|
+
{{> sharedStyles}}
|
|
13
|
+
{{#if extraStyles}}{{{extraStyles}}}{{/if}}
|
|
14
|
+
</head>
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
<header>
|
|
2
|
+
<div class="header-container">
|
|
3
|
+
<a class="logo">
|
|
4
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 90 90" class="iconAboveSlogan">
|
|
5
|
+
<g id="8db2a7f9-6efc-4f7e-ae5b-8ba33875da43" transform="matrix(2.8125,0,0,2.8125,0,0)" stroke="none"
|
|
6
|
+
fill="#00b894">
|
|
7
|
+
<path
|
|
8
|
+
d="M0 32h32V0H0v32zm19.377-19.492l6.936-6.936v20.855h-6.936V12.508zM5.688 5.572l6.936 6.936v13.919H5.688V5.572z">
|
|
9
|
+
</path>
|
|
10
|
+
</g>
|
|
11
|
+
</svg>
|
|
12
|
+
<span class="logo-text">{{#if appName}}{{appName}}{{else}}{{#if app}}{{app}}{{else}}mbkauthe{{/if}}{{/if}} <span class="logo-comp">mbktech</span></span>
|
|
13
|
+
</a>
|
|
14
|
+
</div>
|
|
15
|
+
</header>
|
package/views/info.handlebars
CHANGED
|
@@ -1,14 +1,7 @@
|
|
|
1
1
|
<!DOCTYPE html>
|
|
2
2
|
<html lang="en">
|
|
3
3
|
|
|
4
|
-
<
|
|
5
|
-
<meta charset="UTF-8">
|
|
6
|
-
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
7
|
-
<title>Version and Configuration Information</title>
|
|
8
|
-
<link rel="icon" type="image/x-icon" href="https://mbktech.org/Assets/Images/Icon/dgicon.svg">
|
|
9
|
-
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
|
|
10
|
-
{{> sharedStyles}}
|
|
11
|
-
<style>
|
|
4
|
+
{{> head pageTitle="Version and Configuration Information" ogUrl="/mbkauthe/info" extraStyles="<style>
|
|
12
5
|
.info-box {
|
|
13
6
|
background: rgba(10, 20, 20, 0.95);
|
|
14
7
|
backdrop-filter: blur(10px);
|
|
@@ -169,25 +162,10 @@
|
|
|
169
162
|
padding: 1rem;
|
|
170
163
|
}
|
|
171
164
|
}
|
|
172
|
-
</style>
|
|
173
|
-
</head>
|
|
165
|
+
</style>"}}
|
|
174
166
|
|
|
175
167
|
<body>
|
|
176
|
-
|
|
177
|
-
<div class="header-container">
|
|
178
|
-
<a class="logo">
|
|
179
|
-
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 90 90" class="iconAboveSlogan">
|
|
180
|
-
<g id="8db2a7f9-6efc-4f7e-ae5b-8ba33875da43" transform="matrix(2.8125,0,0,2.8125,0,0)" stroke="none"
|
|
181
|
-
fill="#00b894">
|
|
182
|
-
<path
|
|
183
|
-
d="M0 32h32V0H0v32zm19.377-19.492l6.936-6.936v20.855h-6.936V12.508zM5.688 5.572l6.936 6.936v13.919H5.688V5.572z">
|
|
184
|
-
</path>
|
|
185
|
-
</g>
|
|
186
|
-
</svg>
|
|
187
|
-
<span class="logo-text">{{mbkautheVar.APP_NAME}} <span class="logo-comp">mbktech</span></span>
|
|
188
|
-
</a>
|
|
189
|
-
</div>
|
|
190
|
-
</header>
|
|
168
|
+
{{> header appName=mbkautheVar.APP_NAME}}
|
|
191
169
|
|
|
192
170
|
<section class="login-container">
|
|
193
171
|
<i class="fas fa-info-circle ai-element"></i>
|
|
@@ -227,6 +205,10 @@
|
|
|
227
205
|
<div class="info-label">Domain:</div>
|
|
228
206
|
<div class="info-value">{{mbkautheVar.DOMAIN}}</div>
|
|
229
207
|
</div>
|
|
208
|
+
<div class="info-row">
|
|
209
|
+
<div class="info-label">IS_DEPLOYED:</div>
|
|
210
|
+
<div class="info-value">{{mbkautheVar.IS_DEPLOYED}}</div>
|
|
211
|
+
</div>
|
|
230
212
|
<div class="info-row">
|
|
231
213
|
<div class="info-label">Login Redirect URL:</div>
|
|
232
214
|
<div class="info-value">{{mbkautheVar.loginRedirectURL}}</div>
|
|
@@ -250,10 +232,7 @@
|
|
|
250
232
|
</div>
|
|
251
233
|
</section>
|
|
252
234
|
|
|
253
|
-
|
|
254
|
-
<div class="version-info">
|
|
255
|
-
v{{version}}
|
|
256
|
-
</div>
|
|
235
|
+
{{> versionInfo}}
|
|
257
236
|
</body>
|
|
258
237
|
|
|
259
238
|
</html>
|
|
@@ -1,48 +1,16 @@
|
|
|
1
1
|
<!DOCTYPE html>
|
|
2
2
|
<html lang="en">
|
|
3
3
|
|
|
4
|
-
|
|
5
|
-
<meta charset="UTF-8">
|
|
6
|
-
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
7
|
-
<meta name="description"
|
|
8
|
-
content="Log in to portal.mbktech.org to access your resources and manage projects securely.">
|
|
9
|
-
<meta name="keywords" content="MBK Tech Studio, Web-Portal, Web, Portal, Admin-Panel, Admin, login">
|
|
10
|
-
<meta property="og:title" content="Login | MBK Tech Studio" />
|
|
11
|
-
<meta property="og:image" content="https://mbktech.org/Assets/Images/Icon/logo.png" />
|
|
12
|
-
<meta property="og:url" content="/mbkauthe/login">
|
|
13
|
-
<title>Login | MBK Tech Studio Portal</title>
|
|
14
|
-
<link rel="icon" type="image/x-icon" href="https://mbktech.org/Assets/Images/Icon/dgicon.svg">
|
|
15
|
-
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
|
|
16
|
-
{{> sharedStyles}}
|
|
17
|
-
</head>
|
|
4
|
+
{{> head pageTitle="Login" ogUrl="/mbkauthe/login"}}
|
|
18
5
|
|
|
19
6
|
<body>
|
|
20
|
-
|
|
21
|
-
<div class="header-container">
|
|
22
|
-
<a class="logo">
|
|
23
|
-
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 90 90" class="iconAboveSlogan">
|
|
24
|
-
<g id="8db2a7f9-6efc-4f7e-ae5b-8ba33875da43" transform="matrix(2.8125,0,0,2.8125,0,0)" stroke="none"
|
|
25
|
-
fill="#00b894">
|
|
26
|
-
<path
|
|
27
|
-
d="M0 32h32V0H0v32zm19.377-19.492l6.936-6.936v20.855h-6.936V12.508zM5.688 5.572l6.936 6.936v13.919H5.688V5.572z">
|
|
28
|
-
</path>
|
|
29
|
-
</g>
|
|
30
|
-
</svg>
|
|
31
|
-
<span class="logo-text">{{appName}} <span class="logo-comp">mbktech</span></span>
|
|
32
|
-
</a>
|
|
33
|
-
</div>
|
|
34
|
-
</header>
|
|
7
|
+
{{> header}}
|
|
35
8
|
|
|
36
9
|
{{> showmessage}}
|
|
37
10
|
|
|
38
11
|
<section class="login-container">
|
|
39
12
|
|
|
40
|
-
|
|
41
|
-
<i class="fas fa-microchip ai-element"></i>
|
|
42
|
-
<i class="fas fa-user-astronaut ai-element"></i>
|
|
43
|
-
<i class="fas fa-satellite-dish ai-element"></i>
|
|
44
|
-
<i class="fas fa-cloud ai-element"></i>
|
|
45
|
-
<i class="fas fa-shield-alt ai-element"></i>
|
|
13
|
+
{{> backgroundElements}}
|
|
46
14
|
|
|
47
15
|
<div class="login-box">
|
|
48
16
|
<h1 class="login-title">Login</h1>
|
|
@@ -110,10 +78,7 @@
|
|
|
110
78
|
</div>
|
|
111
79
|
</section>
|
|
112
80
|
|
|
113
|
-
|
|
114
|
-
<div class="version-info">
|
|
115
|
-
v{{version}}
|
|
116
|
-
</div>
|
|
81
|
+
{{> versionInfo}}
|
|
117
82
|
|
|
118
83
|
<script>
|
|
119
84
|
// Toggle password visibility
|
|
@@ -133,7 +98,7 @@
|
|
|
133
98
|
|
|
134
99
|
// Info dialogs
|
|
135
100
|
function usernameinfo() {
|
|
136
|
-
showMessage(`Your username is the part of your
|
|
101
|
+
showMessage(`Your username is the part of your MBKTech.org email before the @ (e.g., abc.xyz@mbktech.org
|
|
137
102
|
→ abc.xyz). For guests or if you’ve forgotten your credentials, contact <a href="https://mbktech.org/Support">Support</a>.`, `What is my username?`);
|
|
138
103
|
}
|
|
139
104
|
|