mbkauthe 1.1.6 → 1.1.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/index.js +29 -2
- package/lib/info.js +12 -457
- package/lib/main.js +1 -0
- package/package.json +6 -2
- package/views/loginmbkauthe.handlebars +570 -0
package/index.js
CHANGED
|
@@ -1,9 +1,17 @@
|
|
|
1
1
|
import express from "express"; // Add this line
|
|
2
2
|
import router from "./lib/main.js";
|
|
3
|
-
|
|
3
|
+
import { getLatestVersion } from "./lib/info.js";
|
|
4
|
+
import { engine } from "express-handlebars";
|
|
4
5
|
import dotenv from "dotenv";
|
|
6
|
+
import path from "path";
|
|
7
|
+
import { fileURLToPath } from "url";
|
|
8
|
+
|
|
5
9
|
dotenv.config();
|
|
10
|
+
|
|
11
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
12
|
+
const __dirname = path.dirname(__filename);
|
|
6
13
|
let mbkautheVar;
|
|
14
|
+
|
|
7
15
|
try {
|
|
8
16
|
mbkautheVar = JSON.parse(process.env.mbkautheVar);
|
|
9
17
|
} catch (error) {
|
|
@@ -35,9 +43,9 @@ if (mbkautheVar.BypassUsers !== undefined) {
|
|
|
35
43
|
}
|
|
36
44
|
}
|
|
37
45
|
|
|
46
|
+
const app = express();
|
|
38
47
|
if (process.env.test === "true") {
|
|
39
48
|
console.log("Test mode is enabled. Starting server in test mode.");
|
|
40
|
-
const app = express();
|
|
41
49
|
const port = 3000;
|
|
42
50
|
app.use(router);
|
|
43
51
|
app.listen(port, () => {
|
|
@@ -45,6 +53,25 @@ if (process.env.test === "true") {
|
|
|
45
53
|
});
|
|
46
54
|
}
|
|
47
55
|
|
|
56
|
+
app.set("views", path.join(__dirname, "node_modules/mbkauthe/views"));
|
|
57
|
+
|
|
58
|
+
app.engine("handlebars", engine({
|
|
59
|
+
defaultLayout: false,
|
|
60
|
+
partialsDir: [
|
|
61
|
+
path.join(__dirname, "node_modules/mbkauthe/views"),
|
|
62
|
+
],
|
|
63
|
+
}));
|
|
64
|
+
|
|
65
|
+
app.set("view engine", "handlebars");
|
|
66
|
+
|
|
67
|
+
import { createRequire } from "module";
|
|
68
|
+
const require = createRequire(import.meta.url);
|
|
69
|
+
const packageJson = require("./package.json");
|
|
70
|
+
const latestVersion = await getLatestVersion();
|
|
71
|
+
if(latestVersion !== packageJson.version) {
|
|
72
|
+
console.warn(`Warning: The current version (${packageJson.version}) is not the latest version (${latestVersion}). Please update mbkauthe.`);
|
|
73
|
+
}
|
|
74
|
+
|
|
48
75
|
export { validateSession, checkRolePermission, validateSessionAndRole, getUserData, authenticate, authapi } from "./lib/validateSessionAndRole.js";
|
|
49
76
|
export { dblogin } from "./lib/pool.js";
|
|
50
77
|
export default router;
|
package/lib/info.js
CHANGED
|
@@ -15,6 +15,15 @@ const mbkautheVar = JSON.parse(process.env.mbkautheVar);
|
|
|
15
15
|
|
|
16
16
|
const router = express.Router();
|
|
17
17
|
|
|
18
|
+
router.get(["/mbkauthe/login"], (req, res) => {
|
|
19
|
+
return res.render("loginmbkauthe", {
|
|
20
|
+
layout: false,
|
|
21
|
+
customURL: mbkautheVar.loginRedirectURL || '/home',
|
|
22
|
+
userLoggedIn: !!req.session?.user,
|
|
23
|
+
UserName: req.session?.user?.username || ''
|
|
24
|
+
});
|
|
25
|
+
});
|
|
26
|
+
|
|
18
27
|
async function getLatestVersion() {
|
|
19
28
|
try {
|
|
20
29
|
const response = await fetch('https://raw.githubusercontent.com/MIbnEKhalid/mbkauthe/main/package.json');
|
|
@@ -96,8 +105,8 @@ router.get(["/mbkauthe/info", "/mbkauthe/i"], async (_, res) => {
|
|
|
96
105
|
|
|
97
106
|
try {
|
|
98
107
|
pkgl = await getPackageLock();
|
|
99
|
-
|
|
100
|
-
latestVersion = "Under Development"; // Placeholder for the latest version
|
|
108
|
+
latestVersion = await getLatestVersion();
|
|
109
|
+
//latestVersion = "Under Development"; // Placeholder for the latest version
|
|
101
110
|
} catch (err) {
|
|
102
111
|
console.error("Error fetching package-lock.json:", err);
|
|
103
112
|
pkgl = { error: "Failed to fetch package-lock.json" };
|
|
@@ -491,460 +500,6 @@ router.get(["/mbkauthe/info", "/mbkauthe/i"], async (_, res) => {
|
|
|
491
500
|
`);
|
|
492
501
|
}
|
|
493
502
|
});
|
|
494
|
-
const DOCUMENTATION_TITLE = "Project Documentation";
|
|
495
|
-
const CACHE_TTL = 3600000; // 1 hour in milliseconds
|
|
496
|
-
|
|
497
|
-
// Cache for the rendered HTML
|
|
498
|
-
let cachedHtml = null;
|
|
499
|
-
let cacheTimestamp = 0;
|
|
500
|
-
|
|
501
|
-
router.get(["/mbkauthe/"], async (_, res) => {
|
|
502
|
-
try {
|
|
503
|
-
// Check cache first
|
|
504
|
-
const now = Date.now();
|
|
505
|
-
if (cachedHtml && (now - cacheTimestamp) < CACHE_TTL) {
|
|
506
|
-
return res.send(cachedHtml);
|
|
507
|
-
}
|
|
508
|
-
|
|
509
|
-
// Read and process file
|
|
510
|
-
let readmePath;
|
|
511
|
-
if (process.env.test === "true") {
|
|
512
|
-
readmePath = path.join(process.cwd(), "README.md");
|
|
513
|
-
}
|
|
514
|
-
else {
|
|
515
|
-
readmePath = path.join(process.cwd(), "./node_modules/mbkauthe/README.md");
|
|
516
|
-
}
|
|
517
|
-
const data = await fs.promises.readFile(readmePath, "utf8");
|
|
518
|
-
|
|
519
|
-
// Convert markdown to HTML
|
|
520
|
-
let html = marked(data, {
|
|
521
|
-
breaks: true,
|
|
522
|
-
gfm: true,
|
|
523
|
-
smartypants: true
|
|
524
|
-
});
|
|
525
|
-
|
|
526
|
-
// Process HTML with cheerio
|
|
527
|
-
const $ = cheerio.load(html);
|
|
528
|
-
|
|
529
|
-
// Add IDs to headers for anchor links
|
|
530
|
-
$('h1, h2, h3, h4, h5, h6').each(function () {
|
|
531
|
-
const id = $(this).text()
|
|
532
|
-
.toLowerCase()
|
|
533
|
-
.replace(/\s+/g, '-')
|
|
534
|
-
.replace(/[^\w-]+/g, '');
|
|
535
|
-
$(this).attr('id', id);
|
|
536
|
-
$(this).addClass('header-anchor');
|
|
537
|
-
});
|
|
538
|
-
|
|
539
|
-
// Fix table of contents links and add icons
|
|
540
|
-
$('a[href^="#"]').each(function () {
|
|
541
|
-
const href = $(this).attr('href');
|
|
542
|
-
const id = href.substring(1)
|
|
543
|
-
.toLowerCase()
|
|
544
|
-
.replace(/\s+/g, '-')
|
|
545
|
-
.replace(/[^\w-]+/g, '');
|
|
546
|
-
$(this).attr('href', `#${id}`);
|
|
547
|
-
$(this).addClass('toc-link');
|
|
548
|
-
});
|
|
549
|
-
|
|
550
|
-
// Add copy buttons to code blocks
|
|
551
|
-
$('pre').each(function () {
|
|
552
|
-
const $pre = $(this);
|
|
553
|
-
const $button = $(`<button class="copy-button" aria-label="Copy code">📋</button>`);
|
|
554
|
-
$pre.prepend($button);
|
|
555
|
-
});
|
|
556
|
-
|
|
557
|
-
// Create the full HTML response
|
|
558
|
-
const htmlContent = generateFullHtml($.html());
|
|
559
|
-
|
|
560
|
-
// Update cache
|
|
561
|
-
cachedHtml = htmlContent;
|
|
562
|
-
cacheTimestamp = now;
|
|
563
|
-
|
|
564
|
-
res.send(htmlContent);
|
|
565
|
-
} catch (err) {
|
|
566
|
-
console.error("Error processing documentation:", err);
|
|
567
|
-
res.status(500).send(generateErrorHtml());
|
|
568
|
-
}
|
|
569
|
-
});
|
|
570
|
-
|
|
571
|
-
function generateFullHtml(contentHtml) {
|
|
572
|
-
return `<!DOCTYPE html>
|
|
573
|
-
<html lang="en">
|
|
574
|
-
<head>
|
|
575
|
-
<meta charset="UTF-8">
|
|
576
|
-
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
577
|
-
<meta name="description" content="Project documentation generated from README.md">
|
|
578
|
-
<title>${DOCUMENTATION_TITLE}</title>
|
|
579
|
-
<style>
|
|
580
|
-
:root {
|
|
581
|
-
--primary-color: #bb86fc;
|
|
582
|
-
--primary-dark: #9a67ea;
|
|
583
|
-
--secondary-color: #03dac6;
|
|
584
|
-
--secondary-dark: #018786;
|
|
585
|
-
--background-dark: #121212;
|
|
586
|
-
--background-darker: #1e1e1e;
|
|
587
|
-
--background-light: #2d2d2d;
|
|
588
|
-
--text-primary: #e0e0e0;
|
|
589
|
-
--text-secondary: #a0a0a0;
|
|
590
|
-
--error-color: #cf6679;
|
|
591
|
-
--success-color: #4caf50;
|
|
592
|
-
}
|
|
593
|
-
|
|
594
|
-
body {
|
|
595
|
-
font-family: 'Inter', 'Segoe UI', system-ui, sans-serif;
|
|
596
|
-
line-height: 1.6;
|
|
597
|
-
margin: 0;
|
|
598
|
-
padding: 0;
|
|
599
|
-
background-color: var(--background-dark);
|
|
600
|
-
color: var(--text-primary);
|
|
601
|
-
max-width: 1200px;
|
|
602
|
-
margin: 0 auto;
|
|
603
|
-
padding: 2rem;
|
|
604
|
-
}
|
|
605
|
-
|
|
606
|
-
.header-anchor {
|
|
607
|
-
position: relative;
|
|
608
|
-
padding-left: 1.5rem;
|
|
609
|
-
}
|
|
610
|
-
|
|
611
|
-
.header-anchor::before {
|
|
612
|
-
content: "#";
|
|
613
|
-
position: absolute;
|
|
614
|
-
left: 0;
|
|
615
|
-
color: var(--text-secondary);
|
|
616
|
-
opacity: 0;
|
|
617
|
-
transition: opacity 0.2s;
|
|
618
|
-
}
|
|
619
|
-
|
|
620
|
-
.header-anchor:hover::before {
|
|
621
|
-
opacity: 1;
|
|
622
|
-
}
|
|
623
|
-
|
|
624
|
-
pre {
|
|
625
|
-
position: relative;
|
|
626
|
-
background: var(--background-darker);
|
|
627
|
-
padding: 1.5rem;
|
|
628
|
-
border-radius: 8px;
|
|
629
|
-
overflow-x: auto;
|
|
630
|
-
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.3);
|
|
631
|
-
}
|
|
632
|
-
|
|
633
|
-
.copy-button {
|
|
634
|
-
position: absolute;
|
|
635
|
-
top: 0.5rem;
|
|
636
|
-
right: 0.5rem;
|
|
637
|
-
background: var(--background-light);
|
|
638
|
-
color: var(--text-primary);
|
|
639
|
-
border: none;
|
|
640
|
-
border-radius: 4px;
|
|
641
|
-
padding: 0.25rem 0.5rem;
|
|
642
|
-
cursor: pointer;
|
|
643
|
-
opacity: 0;
|
|
644
|
-
transition: opacity 0.2s, background 0.2s;
|
|
645
|
-
}
|
|
646
|
-
|
|
647
|
-
pre:hover .copy-button {
|
|
648
|
-
opacity: 1;
|
|
649
|
-
}
|
|
650
|
-
|
|
651
|
-
.copy-button:hover {
|
|
652
|
-
background: var(--primary-color);
|
|
653
|
-
color: var(--background-dark);
|
|
654
|
-
}
|
|
655
|
-
|
|
656
|
-
.copy-button.copied {
|
|
657
|
-
background: var(--success-color);
|
|
658
|
-
color: white;
|
|
659
|
-
}
|
|
660
|
-
|
|
661
|
-
code {
|
|
662
|
-
font-family: 'Fira Code', 'Courier New', monospace;
|
|
663
|
-
background: var(--background-darker);
|
|
664
|
-
padding: 0.2rem 0.4rem;
|
|
665
|
-
border-radius: 4px;
|
|
666
|
-
color: var(--secondary-color);
|
|
667
|
-
font-size: 0.9em;
|
|
668
|
-
word-wrap: break-word;
|
|
669
|
-
}
|
|
670
|
-
|
|
671
|
-
h1, h2, h3, h4, h5, h6 {
|
|
672
|
-
color: var(--primary-color);
|
|
673
|
-
margin-top: 1.8em;
|
|
674
|
-
margin-bottom: 0.8em;
|
|
675
|
-
scroll-margin-top: 1em;
|
|
676
|
-
}
|
|
677
|
-
|
|
678
|
-
h1 {
|
|
679
|
-
font-size: 2.4rem;
|
|
680
|
-
border-bottom: 2px solid var(--primary-color);
|
|
681
|
-
padding-bottom: 0.5rem;
|
|
682
|
-
}
|
|
683
|
-
|
|
684
|
-
h2 { font-size: 2rem; }
|
|
685
|
-
h3 { font-size: 1.6rem; }
|
|
686
|
-
|
|
687
|
-
a {
|
|
688
|
-
color: var(--secondary-color);
|
|
689
|
-
text-decoration: none;
|
|
690
|
-
transition: color 0.2s;
|
|
691
|
-
}
|
|
692
|
-
|
|
693
|
-
a:hover {
|
|
694
|
-
color: var(--primary-color);
|
|
695
|
-
text-decoration: underline;
|
|
696
|
-
}
|
|
697
|
-
|
|
698
|
-
.toc-link {
|
|
699
|
-
display: inline-block;
|
|
700
|
-
padding: 0.2rem 0;
|
|
701
|
-
}
|
|
702
|
-
|
|
703
|
-
.toc-link::before {
|
|
704
|
-
content: "→ ";
|
|
705
|
-
opacity: 0;
|
|
706
|
-
transition: opacity 0.2s;
|
|
707
|
-
}
|
|
708
|
-
|
|
709
|
-
.toc-link:hover::before {
|
|
710
|
-
opacity: 1;
|
|
711
|
-
}
|
|
712
|
-
|
|
713
|
-
blockquote {
|
|
714
|
-
border-left: 4px solid var(--primary-color);
|
|
715
|
-
padding-left: 1.5rem;
|
|
716
|
-
margin-left: 0;
|
|
717
|
-
color: var(--text-secondary);
|
|
718
|
-
font-style: italic;
|
|
719
|
-
background: rgba(187, 134, 252, 0.05);
|
|
720
|
-
border-radius: 0 4px 4px 0;
|
|
721
|
-
padding: 1rem;
|
|
722
|
-
}
|
|
723
|
-
|
|
724
|
-
table {
|
|
725
|
-
border-collapse: collapse;
|
|
726
|
-
width: 100%;
|
|
727
|
-
margin: 1.5rem 0;
|
|
728
|
-
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
|
|
729
|
-
}
|
|
730
|
-
|
|
731
|
-
th, td {
|
|
732
|
-
border: 1px solid #444;
|
|
733
|
-
padding: 0.75rem;
|
|
734
|
-
text-align: left;
|
|
735
|
-
}
|
|
736
|
-
|
|
737
|
-
th {
|
|
738
|
-
background-color: var(--background-darker);
|
|
739
|
-
font-weight: 600;
|
|
740
|
-
}
|
|
741
|
-
|
|
742
|
-
tr:nth-child(even) {
|
|
743
|
-
background-color: rgba(255, 255, 255, 0.05);
|
|
744
|
-
}
|
|
745
|
-
|
|
746
|
-
tr:hover {
|
|
747
|
-
background-color: rgba(187, 134, 252, 0.1);
|
|
748
|
-
}
|
|
749
|
-
|
|
750
|
-
img {
|
|
751
|
-
max-width: 100%;
|
|
752
|
-
height: auto;
|
|
753
|
-
border-radius: 8px;
|
|
754
|
-
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.2);
|
|
755
|
-
}
|
|
756
|
-
|
|
757
|
-
hr {
|
|
758
|
-
border: none;
|
|
759
|
-
height: 1px;
|
|
760
|
-
background-color: #444;
|
|
761
|
-
margin: 2rem 0;
|
|
762
|
-
}
|
|
763
|
-
|
|
764
|
-
/* Dark mode toggle */
|
|
765
|
-
.theme-toggle {
|
|
766
|
-
position: fixed;
|
|
767
|
-
bottom: 1rem;
|
|
768
|
-
right: 1rem;
|
|
769
|
-
background: var(--background-light);
|
|
770
|
-
border: none;
|
|
771
|
-
border-radius: 50%;
|
|
772
|
-
width: 3rem;
|
|
773
|
-
height: 3rem;
|
|
774
|
-
display: flex;
|
|
775
|
-
align-items: center;
|
|
776
|
-
justify-content: center;
|
|
777
|
-
cursor: pointer;
|
|
778
|
-
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.3);
|
|
779
|
-
z-index: 100;
|
|
780
|
-
}
|
|
781
|
-
|
|
782
|
-
/* Responsive design */
|
|
783
|
-
@media (max-width: 768px) {
|
|
784
|
-
body {
|
|
785
|
-
padding: 1rem;
|
|
786
|
-
}
|
|
787
|
-
|
|
788
|
-
h1 {
|
|
789
|
-
font-size: 2rem;
|
|
790
|
-
}
|
|
791
|
-
|
|
792
|
-
h2 {
|
|
793
|
-
font-size: 1.7rem;
|
|
794
|
-
}
|
|
795
|
-
|
|
796
|
-
pre {
|
|
797
|
-
padding: 1rem;
|
|
798
|
-
font-size: 0.9em;
|
|
799
|
-
}
|
|
800
|
-
}
|
|
801
|
-
|
|
802
|
-
/* Print styles */
|
|
803
|
-
@media print {
|
|
804
|
-
body {
|
|
805
|
-
background-color: white;
|
|
806
|
-
color: black;
|
|
807
|
-
padding: 0;
|
|
808
|
-
}
|
|
809
|
-
|
|
810
|
-
a {
|
|
811
|
-
color: #0066cc;
|
|
812
|
-
}
|
|
813
|
-
|
|
814
|
-
pre, code {
|
|
815
|
-
background-color: #f5f5f5;
|
|
816
|
-
color: #333;
|
|
817
|
-
}
|
|
818
|
-
}
|
|
819
|
-
</style>
|
|
820
|
-
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600&family=Fira+Code&display=swap" rel="stylesheet">
|
|
821
|
-
</head>
|
|
822
|
-
<body>
|
|
823
|
-
<a href="/mbkauthe/info/" class="toc-link">mbkauthe Info</a>
|
|
824
|
-
<main>
|
|
825
|
-
${contentHtml}
|
|
826
|
-
</main>
|
|
827
|
-
|
|
828
|
-
<button class="theme-toggle" aria-label="Toggle theme">🌓</button>
|
|
829
|
-
|
|
830
|
-
<script>
|
|
831
|
-
document.addEventListener('DOMContentLoaded', function() {
|
|
832
|
-
// Smooth scrolling for TOC links
|
|
833
|
-
document.querySelectorAll('a[href^="#"]').forEach(anchor => {
|
|
834
|
-
anchor.addEventListener('click', function(e) {
|
|
835
|
-
e.preventDefault();
|
|
836
|
-
const targetId = this.getAttribute('href');
|
|
837
|
-
const targetElement = document.querySelector(targetId);
|
|
838
|
-
|
|
839
|
-
if (targetElement) {
|
|
840
|
-
targetElement.scrollIntoView({
|
|
841
|
-
behavior: 'smooth',
|
|
842
|
-
block: 'start'
|
|
843
|
-
});
|
|
844
|
-
|
|
845
|
-
// Update URL without page jump
|
|
846
|
-
history.pushState(null, null, targetId);
|
|
847
|
-
}
|
|
848
|
-
});
|
|
849
|
-
});
|
|
850
|
-
|
|
851
|
-
// Copy button functionality
|
|
852
|
-
document.querySelectorAll('.copy-button').forEach(button => {
|
|
853
|
-
button.addEventListener('click', function() {
|
|
854
|
-
const pre = this.parentElement;
|
|
855
|
-
const code = pre.querySelector('code') || pre;
|
|
856
|
-
const range = document.createRange();
|
|
857
|
-
range.selectNode(code);
|
|
858
|
-
window.getSelection().removeAllRanges();
|
|
859
|
-
window.getSelection().addRange(range);
|
|
860
|
-
|
|
861
|
-
try {
|
|
862
|
-
const successful = document.execCommand('copy');
|
|
863
|
-
if (successful) {
|
|
864
|
-
this.textContent = '✓ Copied!';
|
|
865
|
-
this.classList.add('copied');
|
|
866
|
-
setTimeout(() => {
|
|
867
|
-
this.textContent = '📋';
|
|
868
|
-
this.classList.remove('copied');
|
|
869
|
-
}, 2000);
|
|
870
|
-
}
|
|
871
|
-
} catch (err) {
|
|
872
|
-
console.error('Failed to copy:', err);
|
|
873
|
-
}
|
|
874
|
-
|
|
875
|
-
window.getSelection().removeAllRanges();
|
|
876
|
-
});
|
|
877
|
-
});
|
|
878
|
-
|
|
879
|
-
// Highlight current section in view
|
|
880
|
-
const observerOptions = {
|
|
881
|
-
root: null,
|
|
882
|
-
rootMargin: '0px',
|
|
883
|
-
threshold: 0.5
|
|
884
|
-
};
|
|
885
|
-
|
|
886
|
-
const observer = new IntersectionObserver(function(entries) {
|
|
887
|
-
entries.forEach(function(entry) {
|
|
888
|
-
const id = entry.target.getAttribute('id');
|
|
889
|
-
if (entry.isIntersecting) {
|
|
890
|
-
document.querySelectorAll('a[href="#' + id + '"]').forEach(function(link) {
|
|
891
|
-
link.style.fontWeight = '600';
|
|
892
|
-
link.style.color = 'var(--primary-color)';
|
|
893
|
-
});
|
|
894
|
-
} else {
|
|
895
|
-
document.querySelectorAll('a[href="#' + id + '"]').forEach(function(link) {
|
|
896
|
-
link.style.fontWeight = '';
|
|
897
|
-
link.style.color = '';
|
|
898
|
-
});
|
|
899
|
-
}
|
|
900
|
-
});
|
|
901
|
-
}, observerOptions);
|
|
902
|
-
|
|
903
|
-
document.querySelectorAll('h1, h2, h3, h4, h5, h6').forEach(function(heading) {
|
|
904
|
-
if (heading.id) {
|
|
905
|
-
observer.observe(heading);
|
|
906
|
-
}
|
|
907
|
-
});
|
|
908
|
-
|
|
909
|
-
// Theme toggle functionality
|
|
910
|
-
const themeToggle = document.querySelector('.theme-toggle');
|
|
911
|
-
themeToggle.addEventListener('click', function() {
|
|
912
|
-
document.body.classList.toggle('light-theme');
|
|
913
|
-
const isLight = document.body.classList.contains('light-theme');
|
|
914
|
-
this.textContent = isLight ? '🌙' : '🌓';
|
|
915
|
-
localStorage.setItem('themePreference', isLight ? 'light' : 'dark');
|
|
916
|
-
});
|
|
917
|
-
|
|
918
|
-
// Load saved theme preference
|
|
919
|
-
const savedTheme = localStorage.getItem('themePreference');
|
|
920
|
-
if (savedTheme === 'light') {
|
|
921
|
-
document.body.classList.add('light-theme');
|
|
922
|
-
themeToggle.textContent = '🌙';
|
|
923
|
-
}
|
|
924
|
-
});
|
|
925
|
-
</script>
|
|
926
|
-
</body>
|
|
927
|
-
</html>`;
|
|
928
|
-
}
|
|
929
|
-
|
|
930
|
-
function generateErrorHtml() {
|
|
931
|
-
return `<!DOCTYPE html>
|
|
932
|
-
<html lang="en">
|
|
933
|
-
<head>
|
|
934
|
-
<meta charset="UTF-8">
|
|
935
|
-
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
936
|
-
<title>Error Loading Documentation</title>
|
|
937
|
-
</head>
|
|
938
|
-
<body>
|
|
939
|
-
<h1>Error Loading Documentation</h1>
|
|
940
|
-
<p>Failed to load README.md file. Please try again later.</p>
|
|
941
|
-
<p>If the problem persists, contact your system administrator.</p>
|
|
942
|
-
<a href="/">Return to Home</a>
|
|
943
|
-
<div class="error-details">
|
|
944
|
-
Error: ${err.message || 'Unknown error'}
|
|
945
|
-
</div>
|
|
946
|
-
</body>
|
|
947
|
-
</html>`;
|
|
948
|
-
}
|
|
949
503
|
|
|
504
|
+
export { getLatestVersion };
|
|
950
505
|
export default router;
|
package/lib/main.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mbkauthe",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.8",
|
|
4
4
|
"description": "MBKTechStudio's reusable authentication system for Node.js applications.",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"type": "module",
|
|
@@ -32,11 +32,15 @@
|
|
|
32
32
|
"cookie-parser": "^1.4.7",
|
|
33
33
|
"dotenv": "^16.4.7",
|
|
34
34
|
"express": "^5.1.0",
|
|
35
|
+
"express-handlebars": "^8.0.1",
|
|
35
36
|
"express-rate-limit": "^7.5.0",
|
|
36
37
|
"express-session": "^1.18.1",
|
|
37
38
|
"marked": "^15.0.11",
|
|
38
39
|
"node-fetch": "^3.3.2",
|
|
39
|
-
"
|
|
40
|
+
"path": "^0.12.7",
|
|
41
|
+
"pg": "^8.14.1",
|
|
42
|
+
"speakeasy": "^2.0.0",
|
|
43
|
+
"url": "^0.11.4"
|
|
40
44
|
},
|
|
41
45
|
"devDependencies": {
|
|
42
46
|
"nodemon": "^2.0.22"
|
|
@@ -0,0 +1,570 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
{{> script/showmessage }}
|
|
4
|
+
|
|
5
|
+
<head>
|
|
6
|
+
<meta charset="UTF-8">
|
|
7
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
8
|
+
<meta name="description"
|
|
9
|
+
content="Log in to portal.mbktechstudio.com to access your resources and manage projects securely.">
|
|
10
|
+
<meta name="keywords" content="MBK Tech Studio, Web-Portal, Web, Portal, Admin-Panel, Admin, login">
|
|
11
|
+
<meta property="og:title" content="Portal Login | MBK Tech Studio" />
|
|
12
|
+
<meta property="og:image" content="https://www.mbktechstudio.com/Assets/Images/Icon/logo.png" />
|
|
13
|
+
<meta property="og:url" content="https://portal.mbktechstudio.com/login">
|
|
14
|
+
<title>Login | MBK Tech Studio Portal</title>
|
|
15
|
+
<link rel="icon" type="image/x-icon" href="/Assets/Images/dgicon.svg">
|
|
16
|
+
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css">
|
|
17
|
+
<link rel="preconnect" href="https://fonts.googleapis.com">
|
|
18
|
+
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
|
19
|
+
<link href="https://fonts.googleapis.com/css2?family=Poppins:wght@300;400;500;600;700&display=swap"
|
|
20
|
+
rel="stylesheet">
|
|
21
|
+
<script src="https://www.google.com/recaptcha/api.js" async defer></script>
|
|
22
|
+
<style>
|
|
23
|
+
:root {
|
|
24
|
+
--primary: #4361ee;
|
|
25
|
+
--primary-dark: #3a0ca3;
|
|
26
|
+
--primary-light: rgba(67, 97, 238, 0.1);
|
|
27
|
+
--secondary: #f72585;
|
|
28
|
+
--secondary-light: rgba(247, 37, 133, 0.1);
|
|
29
|
+
--dark: #121212;
|
|
30
|
+
--dark-light: #1e1e1e;
|
|
31
|
+
--darker: #0a0a0a;
|
|
32
|
+
--light: #f8f9fa;
|
|
33
|
+
--lighter: #ffffff;
|
|
34
|
+
--gray: #cccccc;
|
|
35
|
+
--gray-dark: #888888;
|
|
36
|
+
--success: #4cc9f0;
|
|
37
|
+
--warning: #f8961e;
|
|
38
|
+
--danger: #ef233c;
|
|
39
|
+
--gradient: linear-gradient(135deg, var(--primary), var(--secondary));
|
|
40
|
+
--glass: rgba(30, 30, 30, 0.5);
|
|
41
|
+
--glass-border: rgba(255, 255, 255, 0.1);
|
|
42
|
+
--transition: all 0.4s cubic-bezier(0.175, 0.885, 0.32, 1.1);
|
|
43
|
+
--shadow-sm: 0 4px 6px rgba(0, 0, 0, 0.1);
|
|
44
|
+
--shadow-md: 0 8px 30px rgba(0, 0, 0, 0.2);
|
|
45
|
+
--shadow-lg: 0 15px 40px rgba(0, 0, 0, 0.3);
|
|
46
|
+
--radius-sm: 8px;
|
|
47
|
+
--radius-md: 12px;
|
|
48
|
+
--radius-lg: 16px;
|
|
49
|
+
--radius-xl: 24px;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
* {
|
|
53
|
+
margin: 0;
|
|
54
|
+
padding: 0;
|
|
55
|
+
box-sizing: border-box;
|
|
56
|
+
font-family: 'Poppins', sans-serif;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
body {
|
|
60
|
+
background: var(--dark);
|
|
61
|
+
color: var(--light);
|
|
62
|
+
line-height: 1.6;
|
|
63
|
+
overflow-x: hidden;
|
|
64
|
+
min-height: 100vh;
|
|
65
|
+
display: flex;
|
|
66
|
+
flex-direction: column;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/* Header - Consistent with index */
|
|
70
|
+
header {
|
|
71
|
+
position: fixed;
|
|
72
|
+
top: 0;
|
|
73
|
+
left: 0;
|
|
74
|
+
width: 100%;
|
|
75
|
+
z-index: 1000;
|
|
76
|
+
transition: var(--transition);
|
|
77
|
+
background: linear-gradient(to bottom, rgba(10, 10, 10, 0.9), rgba(10, 10, 10, 0.7));
|
|
78
|
+
backdrop-filter: blur(10px);
|
|
79
|
+
border-bottom: 1px solid var(--glass-border);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
nav {
|
|
83
|
+
padding: 15px 5%;
|
|
84
|
+
max-width: 1400px;
|
|
85
|
+
margin: 0 auto;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
.navbar {
|
|
89
|
+
display: flex;
|
|
90
|
+
justify-content: space-between;
|
|
91
|
+
align-items: center;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
.logo {
|
|
95
|
+
display: flex;
|
|
96
|
+
align-items: center;
|
|
97
|
+
gap: 10px;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
.logo img {
|
|
101
|
+
height: 30px;
|
|
102
|
+
width: auto;
|
|
103
|
+
transition: var(--transition);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
.logo:hover img {
|
|
107
|
+
transform: rotate(15deg);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
.logo-text {
|
|
111
|
+
font-size: 1.8rem;
|
|
112
|
+
font-weight: 700;
|
|
113
|
+
background: var(--gradient);
|
|
114
|
+
-webkit-background-clip: text;
|
|
115
|
+
background-clip: text;
|
|
116
|
+
color: transparent;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/* Login Container */
|
|
120
|
+
.login-container {
|
|
121
|
+
flex: 1;
|
|
122
|
+
display: flex;
|
|
123
|
+
align-items: center;
|
|
124
|
+
justify-content: center;
|
|
125
|
+
padding: 120px 5% 80px;
|
|
126
|
+
position: relative;
|
|
127
|
+
overflow: hidden;
|
|
128
|
+
background: radial-gradient(circle at 70% 20%, rgba(67, 97, 238, 0.15), transparent 60%);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
.login-box {
|
|
132
|
+
background: var(--dark-light);
|
|
133
|
+
border-radius: var(--radius-xl);
|
|
134
|
+
padding: 3rem;
|
|
135
|
+
width: 100%;
|
|
136
|
+
max-width: 500px;
|
|
137
|
+
box-shadow: var(--shadow-lg);
|
|
138
|
+
border: 1px solid var(--glass-border);
|
|
139
|
+
position: relative;
|
|
140
|
+
z-index: 2;
|
|
141
|
+
transition: var(--transition);
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
.login-box:hover {
|
|
145
|
+
box-shadow: var(--shadow-lg);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
.login-title {
|
|
149
|
+
text-align: center;
|
|
150
|
+
margin-bottom: 2rem;
|
|
151
|
+
font-size: 2rem;
|
|
152
|
+
position: relative;
|
|
153
|
+
color: var(--lighter);
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
.login-title::after {
|
|
157
|
+
content: '';
|
|
158
|
+
position: absolute;
|
|
159
|
+
bottom: -10px;
|
|
160
|
+
left: 50%;
|
|
161
|
+
transform: translateX(-50%);
|
|
162
|
+
width: 80px;
|
|
163
|
+
height: 4px;
|
|
164
|
+
background: var(--gradient);
|
|
165
|
+
border-radius: 2px;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
/* Form Elements */
|
|
169
|
+
.form-group {
|
|
170
|
+
position: relative;
|
|
171
|
+
margin-bottom: 2rem;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
.form-input {
|
|
175
|
+
width: 100%;
|
|
176
|
+
padding: 15px 20px;
|
|
177
|
+
background: var(--darker);
|
|
178
|
+
border: 2px solid var(--glass-border);
|
|
179
|
+
border-radius: var(--radius-sm);
|
|
180
|
+
color: var(--light);
|
|
181
|
+
font-size: 1rem;
|
|
182
|
+
transition: var(--transition);
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
.form-input:focus {
|
|
186
|
+
outline: none;
|
|
187
|
+
border-color: var(--primary);
|
|
188
|
+
box-shadow: 0 0 0 3px var(--primary-light);
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
.form-label {
|
|
192
|
+
position: absolute;
|
|
193
|
+
top: 15px;
|
|
194
|
+
left: 20px;
|
|
195
|
+
color: var(--gray);
|
|
196
|
+
transition: var(--transition);
|
|
197
|
+
pointer-events: none;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
.form-input:focus+.form-label,
|
|
201
|
+
.form-input:not(:placeholder-shown)+.form-label {
|
|
202
|
+
top: -10px;
|
|
203
|
+
left: 15px;
|
|
204
|
+
font-size: 0.8rem;
|
|
205
|
+
background: var(--dark-light);
|
|
206
|
+
padding: 0 5px;
|
|
207
|
+
color: var(--primary);
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
.input-icon {
|
|
211
|
+
position: absolute;
|
|
212
|
+
right: 20px;
|
|
213
|
+
top: 50%;
|
|
214
|
+
transform: translateY(-50%);
|
|
215
|
+
color: var(--gray);
|
|
216
|
+
cursor: pointer;
|
|
217
|
+
transition: var(--transition);
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
.input-icon:hover {
|
|
221
|
+
color: var(--primary);
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
.btn-login {
|
|
225
|
+
width: 100%;
|
|
226
|
+
padding: 15px;
|
|
227
|
+
border-radius: var(--radius-sm);
|
|
228
|
+
background: var(--primary);
|
|
229
|
+
color: white;
|
|
230
|
+
font-weight: 600;
|
|
231
|
+
font-size: 1rem;
|
|
232
|
+
border: none;
|
|
233
|
+
cursor: pointer;
|
|
234
|
+
transition: var(--transition);
|
|
235
|
+
box-shadow: var(--shadow-sm);
|
|
236
|
+
margin-top: 1rem;
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
.btn-login:hover {
|
|
240
|
+
background: var(--primary-dark);
|
|
241
|
+
transform: translateY(-3px);
|
|
242
|
+
box-shadow: var(--shadow-md);
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
.btn-login:disabled {
|
|
246
|
+
background: var(--gray-dark);
|
|
247
|
+
cursor: not-allowed;
|
|
248
|
+
transform: none;
|
|
249
|
+
box-shadow: none;
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
/* Additional Links */
|
|
253
|
+
.login-links {
|
|
254
|
+
display: flex;
|
|
255
|
+
justify-content: space-between;
|
|
256
|
+
margin-top: 1.5rem;
|
|
257
|
+
font-size: 0.9rem;
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
.login-link {
|
|
261
|
+
color: var(--gray);
|
|
262
|
+
transition: var(--transition);
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
.login-link:hover {
|
|
266
|
+
color: var(--primary);
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
/* Terms Info */
|
|
270
|
+
.terms-info {
|
|
271
|
+
margin-top: 2rem;
|
|
272
|
+
font-size: 0.8rem;
|
|
273
|
+
color: var(--gray);
|
|
274
|
+
text-align: center;
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
.terms-link {
|
|
278
|
+
color: var(--primary);
|
|
279
|
+
font-weight: 500;
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
/* Recaptcha */
|
|
283
|
+
.recaptcha-container {
|
|
284
|
+
margin: 2rem 0;
|
|
285
|
+
display: flex;
|
|
286
|
+
justify-content: center;
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
/* 2FA Token Container */
|
|
290
|
+
.token-container {
|
|
291
|
+
animation: fadeInUp 0.4s ease-out;
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
.token-container.disable {
|
|
295
|
+
display: none;
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
.token-container.enable {
|
|
299
|
+
display: block;
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
/* Floating Elements */
|
|
303
|
+
.ai-element {
|
|
304
|
+
position: absolute;
|
|
305
|
+
opacity: 0.1;
|
|
306
|
+
z-index: 1;
|
|
307
|
+
animation: float 6s ease-in-out infinite;
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
.ai-element:nth-child(1) {
|
|
311
|
+
top: 20%;
|
|
312
|
+
left: 10%;
|
|
313
|
+
font-size: 5rem;
|
|
314
|
+
animation-delay: 0s;
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
.ai-element:nth-child(2) {
|
|
318
|
+
top: 60%;
|
|
319
|
+
left: 80%;
|
|
320
|
+
font-size: 4rem;
|
|
321
|
+
animation-delay: 1s;
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
.ai-element:nth-child(3) {
|
|
325
|
+
top: 30%;
|
|
326
|
+
left: 70%;
|
|
327
|
+
font-size: 3rem;
|
|
328
|
+
animation-delay: 2s;
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
.ai-element:nth-child(4) {
|
|
332
|
+
top: 80%;
|
|
333
|
+
left: 20%;
|
|
334
|
+
font-size: 6rem;
|
|
335
|
+
animation-delay: 3s;
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
@keyframes float {
|
|
339
|
+
|
|
340
|
+
0%,
|
|
341
|
+
100% {
|
|
342
|
+
transform: translateY(0) rotate(0deg);
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
50% {
|
|
346
|
+
transform: translateY(-20px) rotate(5deg);
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
@keyframes fadeInUp {
|
|
351
|
+
from {
|
|
352
|
+
opacity: 0;
|
|
353
|
+
transform: translateY(20px);
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
to {
|
|
357
|
+
opacity: 1;
|
|
358
|
+
transform: translateY(0);
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
/* Responsive Styles */
|
|
363
|
+
@media (max-width: 768px) {
|
|
364
|
+
.login-box {
|
|
365
|
+
padding: 2rem;
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
.login-title {
|
|
369
|
+
font-size: 1.8rem;
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
@media (max-width: 576px) {
|
|
374
|
+
.login-box {
|
|
375
|
+
padding: 1.5rem;
|
|
376
|
+
border-radius: var(--radius-lg);
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
.login-links {
|
|
380
|
+
flex-direction: column;
|
|
381
|
+
gap: 0.5rem;
|
|
382
|
+
align-items: center;
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
</style>
|
|
386
|
+
</head>
|
|
387
|
+
|
|
388
|
+
<body>
|
|
389
|
+
<header>
|
|
390
|
+
<nav>
|
|
391
|
+
<div class="navbar">
|
|
392
|
+
<a class="logo">
|
|
393
|
+
<img src="/Assets/Images/dg.svg" alt="MBK Tech Studio Logo">
|
|
394
|
+
<span class="logo-text">MBK Authe</span>
|
|
395
|
+
</a>
|
|
396
|
+
</div>
|
|
397
|
+
</nav>
|
|
398
|
+
</header>
|
|
399
|
+
|
|
400
|
+
<section class="login-container">
|
|
401
|
+
<!-- Floating AI elements -->
|
|
402
|
+
<i class="fas fa-robot ai-element"></i>
|
|
403
|
+
<i class="fas fa-microchip ai-element"></i>
|
|
404
|
+
<i class="fas fa-user-astronaut ai-element"></i>
|
|
405
|
+
<i class="fas fa-satellite-dish ai-element"></i>
|
|
406
|
+
<i class="fas fa-cloud ai-element"></i>
|
|
407
|
+
<i class="fas fa-shield-alt ai-element"></i>
|
|
408
|
+
|
|
409
|
+
<div class="login-box">
|
|
410
|
+
<h1 class="login-title">Login</h1>
|
|
411
|
+
|
|
412
|
+
<form id="loginForm" method="POST">
|
|
413
|
+
<div class="form-group">
|
|
414
|
+
<input id="loginUsername" class="form-input" type="text" name="username" placeholder=" " required
|
|
415
|
+
pattern="^[a-z0-9.]+$"
|
|
416
|
+
title="Username must contain lowercase letters, numbers, and periods only, no spaces, no special characters."
|
|
417
|
+
oninput="this.value = this.value.toLowerCase().replace(/[^a-z0-9.]/g, '')" />
|
|
418
|
+
<label class="form-label">Username</label>
|
|
419
|
+
<i class="fas fa-info-circle input-icon" onclick="usernameinfo()"></i>
|
|
420
|
+
</div>
|
|
421
|
+
|
|
422
|
+
<div class="form-group">
|
|
423
|
+
<input id="loginPassword" class="form-input" type="password" name="Password" placeholder=" "
|
|
424
|
+
required />
|
|
425
|
+
<label class="form-label">Password</label>
|
|
426
|
+
<i class="fas fa-eye input-icon" id="togglePassword"></i>
|
|
427
|
+
</div>
|
|
428
|
+
|
|
429
|
+
<div class="form-group token-container disable" id="tokenCon">
|
|
430
|
+
<input id="token" class="form-input" type="text" name="token" placeholder=" " pattern="\d{6}"
|
|
431
|
+
title="Token must be exactly 6 digits" maxlength="6" minlength="6" />
|
|
432
|
+
<label class="form-label">2FA Token</label>
|
|
433
|
+
<i class="fas fa-info-circle input-icon" onclick="tokeninfo()"></i>
|
|
434
|
+
</div>
|
|
435
|
+
|
|
436
|
+
<div class="recaptcha-container">
|
|
437
|
+
<div class="g-recaptcha" data-theme="dark" data-sitekey="6LfhaPgqAAAAAPgOw7r3rNOHKKfh5d7K3MMJeUHo">
|
|
438
|
+
</div>
|
|
439
|
+
</div>
|
|
440
|
+
|
|
441
|
+
<button type="submit" class="btn-login" id="loginButton">
|
|
442
|
+
<span id="loginButtonText">Login</span>
|
|
443
|
+
</button>
|
|
444
|
+
|
|
445
|
+
<div class="login-links">
|
|
446
|
+
<a onclick="fpass()" class="login-link">Forgot Password?</a>
|
|
447
|
+
<a href="https://www.mbktechstudio.com/Support" target="_blank" class="login-link">Need Help?</a>
|
|
448
|
+
</div>
|
|
449
|
+
|
|
450
|
+
<p class="terms-info">
|
|
451
|
+
By logging in, you agree to our
|
|
452
|
+
<a href="/info/Terms&Conditions" class="terms-link">Terms & Conditions</a>
|
|
453
|
+
and
|
|
454
|
+
<a href="/info/PrivacyPolicy" class="terms-link">Privacy Policy</a>.
|
|
455
|
+
</p>
|
|
456
|
+
</form>
|
|
457
|
+
</div>
|
|
458
|
+
</section>
|
|
459
|
+
|
|
460
|
+
<script>
|
|
461
|
+
|
|
462
|
+
|
|
463
|
+
// Toggle password visibility
|
|
464
|
+
const togglePassword = document.getElementById('togglePassword');
|
|
465
|
+
const passwordInput = document.getElementById('loginPassword');
|
|
466
|
+
|
|
467
|
+
togglePassword.addEventListener('click', function () {
|
|
468
|
+
const type = passwordInput.getAttribute('type') === 'password' ? 'text' : 'password';
|
|
469
|
+
passwordInput.setAttribute('type', type);
|
|
470
|
+
togglePassword.classList.toggle('fa-eye');
|
|
471
|
+
togglePassword.classList.toggle('fa-eye-slash');
|
|
472
|
+
});
|
|
473
|
+
|
|
474
|
+
function fpass() {
|
|
475
|
+
showMessage(`If you have forgotten your password, please contact support at <a href="https://www.mbktechstudio.com/Support" target="_blank">https://www.mbktechstudio.com/Support</a> to reset it.`, `Forgot Password`);
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
// Info dialogs
|
|
479
|
+
function usernameinfo() {
|
|
480
|
+
showMessage(`If you are a member of the MBK Tech Studio team, your username is the first part of your email address (e.g., for abc.xyz@mbktechstudio.com, your username is abc.xyz). If you are a guest or have forgotten your username and password, please contact support.`, `What is my username?`);
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
function tokeninfo() {
|
|
484
|
+
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?`);
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
// Form submission
|
|
488
|
+
document.getElementById('loginForm').addEventListener('submit', function (event) {
|
|
489
|
+
event.preventDefault();
|
|
490
|
+
|
|
491
|
+
const username = document.getElementById('loginUsername').value.trim();
|
|
492
|
+
const password = document.getElementById('loginPassword').value.trim();
|
|
493
|
+
const token = document.getElementById('token') ? document.getElementById('token').value.trim() : '';
|
|
494
|
+
const recaptchaResponse = grecaptcha.getResponse();
|
|
495
|
+
const loginButton = document.getElementById('loginButton');
|
|
496
|
+
const loginButtonText = document.getElementById('loginButtonText');
|
|
497
|
+
|
|
498
|
+
if (!username || !password) {
|
|
499
|
+
showMessage('Username and password are required', 'Login Error');
|
|
500
|
+
return;
|
|
501
|
+
}
|
|
502
|
+
|
|
503
|
+
loginButton.disabled = true;
|
|
504
|
+
loginButtonText.textContent = 'Authenticating...';
|
|
505
|
+
|
|
506
|
+
fetch('/mbkauthe/api/login', {
|
|
507
|
+
method: 'POST',
|
|
508
|
+
headers: {
|
|
509
|
+
'Content-Type': 'application/json'
|
|
510
|
+
},
|
|
511
|
+
body: JSON.stringify({
|
|
512
|
+
username,
|
|
513
|
+
password,
|
|
514
|
+
token,
|
|
515
|
+
recaptcha: recaptchaResponse
|
|
516
|
+
})
|
|
517
|
+
})
|
|
518
|
+
.then(response => response.json())
|
|
519
|
+
.then(data => {
|
|
520
|
+
if (data.success) {
|
|
521
|
+
loginButtonText.textContent = 'Success! Redirecting...';
|
|
522
|
+
sessionStorage.setItem('sessionId', data.sessionId);
|
|
523
|
+
|
|
524
|
+
// Redirect to the appropriate page
|
|
525
|
+
const redirectUrl = new URLSearchParams(window.location.search).get('redirect');
|
|
526
|
+
window.location.href = redirectUrl ? decodeURIComponent(redirectUrl) : '/chatbot';
|
|
527
|
+
} else {
|
|
528
|
+
// Handle errors
|
|
529
|
+
grecaptcha.reset();
|
|
530
|
+
loginButton.disabled = false;
|
|
531
|
+
loginButtonText.textContent = 'Login';
|
|
532
|
+
|
|
533
|
+
if (data.message === "Please Enter 2FA code") {
|
|
534
|
+
console.log('2FA required');
|
|
535
|
+
document.getElementById('tokenCon').classList.remove('disable');
|
|
536
|
+
document.getElementById('tokenCon').classList.add('enable');
|
|
537
|
+
document.getElementById('tokenCon').style.animation = 'fadeInUp 0.4s ease-out';
|
|
538
|
+
showMessage('Please enter your 2FA token', '2FA Required');
|
|
539
|
+
} else {
|
|
540
|
+
showMessage(data.message || 'Login failed. Please try again.', 'Login Error');
|
|
541
|
+
}
|
|
542
|
+
}
|
|
543
|
+
})
|
|
544
|
+
.catch(error => {
|
|
545
|
+
grecaptcha.reset();
|
|
546
|
+
loginButton.disabled = false;
|
|
547
|
+
loginButtonText.textContent = 'Login';
|
|
548
|
+
console.error('Error:', error);
|
|
549
|
+
showMessage('An error occurred. Please try again.', 'Login Error');
|
|
550
|
+
});
|
|
551
|
+
});
|
|
552
|
+
|
|
553
|
+
// Check for URL parameters
|
|
554
|
+
document.addEventListener('DOMContentLoaded', function () {
|
|
555
|
+
const urlParams = new URLSearchParams(window.location.search);
|
|
556
|
+
const usernameFromUrl = urlParams.get('username');
|
|
557
|
+
const passwordFromUrl = urlParams.get('password');
|
|
558
|
+
|
|
559
|
+
if (usernameFromUrl) {
|
|
560
|
+
document.getElementById('loginUsername').value = usernameFromUrl;
|
|
561
|
+
}
|
|
562
|
+
|
|
563
|
+
if (passwordFromUrl) {
|
|
564
|
+
document.getElementById('loginPassword').value = passwordFromUrl;
|
|
565
|
+
}
|
|
566
|
+
});
|
|
567
|
+
</script>
|
|
568
|
+
</body>
|
|
569
|
+
|
|
570
|
+
</html>
|