Spaces:
Running
Running
Update index.html
Browse files- index.html +195 -108
index.html
CHANGED
|
@@ -134,7 +134,6 @@
|
|
| 134 |
opacity: 0.4;
|
| 135 |
}
|
| 136 |
|
| 137 |
-
/* โโ HASH INDICATOR โโ */
|
| 138 |
.hash-indicator {
|
| 139 |
display: flex;
|
| 140 |
align-items: center;
|
|
@@ -146,10 +145,7 @@
|
|
| 146 |
margin-bottom: 18px;
|
| 147 |
}
|
| 148 |
|
| 149 |
-
.hash-icon {
|
| 150 |
-
font-size: 11px;
|
| 151 |
-
color: var(--accent-cyan);
|
| 152 |
-
}
|
| 153 |
|
| 154 |
.hash-text {
|
| 155 |
font-family: 'Orbitron', monospace;
|
|
@@ -203,7 +199,6 @@
|
|
| 203 |
|
| 204 |
.field-input::placeholder { color: var(--text-muted); }
|
| 205 |
|
| 206 |
-
/* password wrapper for show/hide toggle */
|
| 207 |
.pass-wrap { position: relative; }
|
| 208 |
.pass-wrap .field-input { padding-right: 44px; }
|
| 209 |
.toggle-pass {
|
|
@@ -222,7 +217,6 @@
|
|
| 222 |
}
|
| 223 |
.toggle-pass:hover { color: var(--accent-cyan); }
|
| 224 |
|
| 225 |
-
/* hash preview strip */
|
| 226 |
.hash-preview {
|
| 227 |
margin-top: 6px;
|
| 228 |
padding: 5px 10px;
|
|
@@ -344,7 +338,6 @@
|
|
| 344 |
min-height: 100vh;
|
| 345 |
position: relative;
|
| 346 |
z-index: 1;
|
| 347 |
-
transition: opacity 0.4s;
|
| 348 |
}
|
| 349 |
|
| 350 |
.topnav {
|
|
@@ -360,11 +353,7 @@
|
|
| 360 |
z-index: 50;
|
| 361 |
}
|
| 362 |
|
| 363 |
-
.nav-brand {
|
| 364 |
-
display: flex;
|
| 365 |
-
align-items: center;
|
| 366 |
-
gap: 12px;
|
| 367 |
-
}
|
| 368 |
|
| 369 |
.brand-icon {
|
| 370 |
width: 32px; height: 32px;
|
|
@@ -484,7 +473,6 @@
|
|
| 484 |
.stat-val { color: var(--accent-cyan); }
|
| 485 |
.sep { width:1px; height:12px; background:var(--border); }
|
| 486 |
|
| 487 |
-
/* security badge in statusbar */
|
| 488 |
.sec-badge {
|
| 489 |
display: flex;
|
| 490 |
align-items: center;
|
|
@@ -624,13 +612,7 @@
|
|
| 624 |
overflow: hidden;
|
| 625 |
}
|
| 626 |
|
| 627 |
-
.stat-card::after {
|
| 628 |
-
content: '';
|
| 629 |
-
position: absolute;
|
| 630 |
-
bottom:0; left:0; right:0;
|
| 631 |
-
height: 2px;
|
| 632 |
-
}
|
| 633 |
-
|
| 634 |
.stat-card:nth-child(1)::after { background: linear-gradient(90deg, var(--accent-cyan), transparent); }
|
| 635 |
.stat-card:nth-child(2)::after { background: linear-gradient(90deg, var(--accent-orange), transparent); }
|
| 636 |
.stat-card:nth-child(3)::after { background: linear-gradient(90deg, var(--accent-purple), transparent); }
|
|
@@ -677,6 +659,38 @@
|
|
| 677 |
|
| 678 |
.open-btn:hover { filter: brightness(1.2); }
|
| 679 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 680 |
@media (max-width: 900px) {
|
| 681 |
.split-view { grid-template-columns: 1fr; }
|
| 682 |
.stats-row { grid-template-columns: repeat(2,1fr); }
|
|
@@ -687,6 +701,12 @@
|
|
| 687 |
</head>
|
| 688 |
<body>
|
| 689 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 690 |
<!-- LOGIN SCREEN -->
|
| 691 |
<div id="loginScreen">
|
| 692 |
<div class="login-wrapper">
|
|
@@ -699,7 +719,6 @@
|
|
| 699 |
|
| 700 |
<div class="scan-line"></div>
|
| 701 |
|
| 702 |
-
<!-- Security indicator -->
|
| 703 |
<div class="hash-indicator">
|
| 704 |
<span class="hash-icon">๐</span>
|
| 705 |
<span class="hash-text">ๅฏ็ขผๅทฒๅ็จ SHA-256 ้ๆนๅ ๅฏไฟ่ญท</span>
|
|
@@ -717,7 +736,6 @@
|
|
| 717 |
<input id="loginPass" class="field-input" type="password" placeholder="่ผธๅ
ฅๅฏ็ขผ" oninput="onPassInput(this.value)">
|
| 718 |
<button class="toggle-pass" type="button" onclick="togglePass()" id="togglePassBtn" title="้กฏ็คบ/้ฑ่ๅฏ็ขผ">๐</button>
|
| 719 |
</div>
|
| 720 |
-
<!-- live hash preview -->
|
| 721 |
<div class="hash-preview" id="hashPreview">โ ่ผธๅ
ฅๅฏ็ขผๅพ้กฏ็คบ SHA-256 ้ๆนๅผ โ</div>
|
| 722 |
</div>
|
| 723 |
|
|
@@ -747,7 +765,6 @@
|
|
| 747 |
<!-- DASHBOARD -->
|
| 748 |
<div id="dashboard">
|
| 749 |
|
| 750 |
-
<!-- Top Nav -->
|
| 751 |
<nav class="topnav">
|
| 752 |
<div class="nav-brand">
|
| 753 |
<div class="brand-icon">๐ท</div>
|
|
@@ -771,14 +788,13 @@
|
|
| 771 |
|
| 772 |
<div class="nav-right">
|
| 773 |
<div class="user-chip">
|
| 774 |
-
<div class="user-avatar">U</div>
|
| 775 |
-
<span>
|
| 776 |
</div>
|
| 777 |
<button class="logout-btn" onclick="doLogout()">โป ่ฟๅ็ปๅ
ฅ็ซ้ข</button>
|
| 778 |
</div>
|
| 779 |
</nav>
|
| 780 |
|
| 781 |
-
<!-- Status Bar -->
|
| 782 |
<div class="statusbar">
|
| 783 |
<div class="stat-item">
|
| 784 |
<span class="stat-label">SESSION</span>
|
|
@@ -802,13 +818,12 @@
|
|
| 802 |
<div class="sep"></div>
|
| 803 |
<div class="stat-item">
|
| 804 |
<span class="stat-label">OPERATOR</span>
|
| 805 |
-
<span class="stat-val">
|
| 806 |
</div>
|
| 807 |
<div class="sep"></div>
|
| 808 |
<div class="sec-badge">๐ SHA-256 ENCRYPTED</div>
|
| 809 |
</div>
|
| 810 |
|
| 811 |
-
<!-- Content -->
|
| 812 |
<div class="content-area">
|
| 813 |
|
| 814 |
<!-- OVERVIEW -->
|
|
@@ -826,7 +841,7 @@
|
|
| 826 |
</div>
|
| 827 |
<div class="stat-card">
|
| 828 |
<div class="s-label">็ปๅ
ฅๅธณ่</div>
|
| 829 |
-
<div class="s-val" style="font-size:16px;padding-top:6px;">
|
| 830 |
<div class="s-sub">ไธ่ฌไฝฟ็จ่
</div>
|
| 831 |
</div>
|
| 832 |
<div class="stat-card">
|
|
@@ -842,7 +857,6 @@
|
|
| 842 |
</div>
|
| 843 |
|
| 844 |
<div class="split-view">
|
| 845 |
-
<!-- MOMO card -->
|
| 846 |
<div class="iframe-container">
|
| 847 |
<div class="iframe-topbar">
|
| 848 |
<div class="site-info">
|
|
@@ -867,7 +881,6 @@
|
|
| 867 |
</div>
|
| 868 |
</div>
|
| 869 |
|
| 870 |
-
<!-- PChome card -->
|
| 871 |
<div class="iframe-container">
|
| 872 |
<div class="iframe-topbar">
|
| 873 |
<div class="site-info">
|
|
@@ -906,9 +919,7 @@
|
|
| 906 |
<span class="site-badge momo">MOMO</span>
|
| 907 |
<span class="site-url">https://angelguava-momo-streamlit.hf.space</span>
|
| 908 |
</div>
|
| 909 |
-
<div class="iframe-dots">
|
| 910 |
-
<span></span><span></span><span></span>
|
| 911 |
-
</div>
|
| 912 |
</div>
|
| 913 |
<iframe src="https://angelguava-momo-streamlit.hf.space" loading="lazy" title="MOMO ็ฌ่ฒ็ณป็ตฑ"></iframe>
|
| 914 |
</div>
|
|
@@ -926,9 +937,7 @@
|
|
| 926 |
<span class="site-badge pchome">PCHOME</span>
|
| 927 |
<span class="site-url">https://angelguava-pchome.hf.space</span>
|
| 928 |
</div>
|
| 929 |
-
<div class="iframe-dots">
|
| 930 |
-
<span></span><span></span><span></span>
|
| 931 |
-
</div>
|
| 932 |
</div>
|
| 933 |
<iframe src="https://angelguava-pchome.hf.space" loading="lazy" title="PChome ็ฌ่ฒ็ณป็ตฑ"></iframe>
|
| 934 |
</div>
|
|
@@ -943,18 +952,14 @@
|
|
| 943 |
<div class="split-view">
|
| 944 |
<div class="iframe-container">
|
| 945 |
<div class="iframe-topbar">
|
| 946 |
-
<div class="site-info">
|
| 947 |
-
<span class="site-badge momo">MOMO</span>
|
| 948 |
-
</div>
|
| 949 |
<div class="iframe-dots"><span></span><span></span><span></span></div>
|
| 950 |
</div>
|
| 951 |
<iframe src="https://angelguava-momo-streamlit.hf.space" loading="lazy" title="MOMO"></iframe>
|
| 952 |
</div>
|
| 953 |
<div class="iframe-container">
|
| 954 |
<div class="iframe-topbar">
|
| 955 |
-
<div class="site-info">
|
| 956 |
-
<span class="site-badge pchome">PCHOME</span>
|
| 957 |
-
</div>
|
| 958 |
<div class="iframe-dots"><span></span><span></span><span></span></div>
|
| 959 |
</div>
|
| 960 |
<iframe src="https://angelguava-pchome.hf.space" loading="lazy" title="PChome"></iframe>
|
|
@@ -967,31 +972,26 @@
|
|
| 967 |
|
| 968 |
|
| 969 |
<script>
|
| 970 |
-
/* โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
| 971 |
-
|
| 972 |
-
|
| 973 |
-
|
| 974 |
-
|
| 975 |
-
|
| 976 |
-
|
| 977 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 978 |
async function sha256(message) {
|
| 979 |
-
const
|
| 980 |
-
const
|
| 981 |
-
|
| 982 |
-
|
| 983 |
}
|
| 984 |
|
| 985 |
-
/**
|
| 986 |
-
* Pre-computed SHA-256 hash for "123456789"
|
| 987 |
-
* = 15e2b0d3c33891ebb0f1ef609ec419420c20e320ce94c65fbc8c3312448eb225
|
| 988 |
-
*
|
| 989 |
-
* The plaintext password is NEVER stored or compared โ only hashes are matched.
|
| 990 |
-
*/
|
| 991 |
-
const VALID_USER = 'user1';
|
| 992 |
-
const VALID_HASH = '15e2b0d3c33891ebb0f1ef609ec419420c20e320ce94c65fbc8c3312448eb225';
|
| 993 |
-
|
| 994 |
-
/* โโ Live hash preview โโ */
|
| 995 |
async function onPassInput(val) {
|
| 996 |
const el = document.getElementById('hashPreview');
|
| 997 |
if (!val) {
|
|
@@ -1000,7 +1000,6 @@
|
|
| 1000 |
return;
|
| 1001 |
}
|
| 1002 |
const h = await sha256(val);
|
| 1003 |
-
// Show first 16 chars + ellipsis for readability; full hash in title
|
| 1004 |
el.textContent = `SHA-256 โบ ${h.slice(0,16)}โฆ${h.slice(-8)}`;
|
| 1005 |
el.title = h;
|
| 1006 |
el.classList.add('ready');
|
|
@@ -1010,18 +1009,13 @@
|
|
| 1010 |
function togglePass() {
|
| 1011 |
const input = document.getElementById('loginPass');
|
| 1012 |
const btn = document.getElementById('togglePassBtn');
|
| 1013 |
-
|
| 1014 |
-
|
| 1015 |
-
btn.textContent = '๐';
|
| 1016 |
-
} else {
|
| 1017 |
-
input.type = 'password';
|
| 1018 |
-
btn.textContent = '๐';
|
| 1019 |
-
}
|
| 1020 |
}
|
| 1021 |
|
| 1022 |
-
/* โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
| 1023 |
CAPTCHA
|
| 1024 |
-
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ */
|
| 1025 |
const CHARS = 'ABCDEFGHJKLMNPQRSTUVWXYZ23456789';
|
| 1026 |
let currentCaptcha = '';
|
| 1027 |
|
|
@@ -1037,9 +1031,67 @@
|
|
| 1037 |
|
| 1038 |
refreshCaptcha();
|
| 1039 |
|
| 1040 |
-
/* โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
| 1041 |
-
|
| 1042 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1043 |
async function doLogin() {
|
| 1044 |
const user = document.getElementById('loginUser').value.trim();
|
| 1045 |
const pass = document.getElementById('loginPass').value;
|
|
@@ -1047,45 +1099,78 @@
|
|
| 1047 |
const err = document.getElementById('errorMsg');
|
| 1048 |
const btn = document.getElementById('loginBtn');
|
| 1049 |
|
| 1050 |
-
|
| 1051 |
-
btn.disabled = true;
|
| 1052 |
-
btn.textContent = 'โณ ้ฉ่ญไธญโฆ';
|
| 1053 |
-
|
| 1054 |
-
// Hash the entered password
|
| 1055 |
-
const enteredHash = await sha256(pass);
|
| 1056 |
|
| 1057 |
-
/
|
| 1058 |
-
if (
|
| 1059 |
-
err.style.display = 'none';
|
| 1060 |
-
const ls = document.getElementById('loginScreen');
|
| 1061 |
-
ls.style.opacity = '0';
|
| 1062 |
-
setTimeout(() => {
|
| 1063 |
-
ls.style.display = 'none';
|
| 1064 |
-
const dash = document.getElementById('dashboard');
|
| 1065 |
-
dash.style.display = 'flex';
|
| 1066 |
-
startSession();
|
| 1067 |
-
updateDate();
|
| 1068 |
-
btn.disabled = false;
|
| 1069 |
-
btn.textContent = 'โถ \u00a0 ็ณป็ตฑ็ปๅ
ฅ';
|
| 1070 |
-
}, 500);
|
| 1071 |
-
} else {
|
| 1072 |
err.style.display = 'block';
|
| 1073 |
refreshCaptcha();
|
| 1074 |
document.getElementById('captchaInput').focus();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1075 |
btn.disabled = false;
|
| 1076 |
btn.textContent = 'โถ \u00a0 ็ณป็ตฑ็ปๅ
ฅ';
|
| 1077 |
}
|
| 1078 |
}
|
| 1079 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1080 |
['loginUser', 'loginPass', 'captchaInput'].forEach(id => {
|
| 1081 |
document.getElementById(id).addEventListener('keydown', e => {
|
| 1082 |
if (e.key === 'Enter') doLogin();
|
| 1083 |
});
|
| 1084 |
});
|
| 1085 |
|
| 1086 |
-
/* โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
| 1087 |
LOGOUT
|
| 1088 |
-
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ */
|
| 1089 |
function doLogout() {
|
| 1090 |
clearInterval(sessionTimer);
|
| 1091 |
const dash = document.getElementById('dashboard');
|
|
@@ -1110,8 +1195,10 @@
|
|
| 1110 |
document.getElementById('hashPreview').textContent = 'โ ่ผธๅ
ฅๅฏ็ขผๅพ้กฏ็คบ SHA-256 ้ๆนๅผ โ';
|
| 1111 |
document.getElementById('hashPreview').classList.remove('ready');
|
| 1112 |
document.getElementById('errorMsg').style.display = 'none';
|
|
|
|
| 1113 |
refreshCaptcha();
|
| 1114 |
sessionSeconds = 0;
|
|
|
|
| 1115 |
|
| 1116 |
// Reset tabs
|
| 1117 |
document.querySelectorAll('.tab-panel').forEach(p => p.classList.remove('active'));
|
|
@@ -1121,9 +1208,9 @@
|
|
| 1121 |
}, 400);
|
| 1122 |
}
|
| 1123 |
|
| 1124 |
-
/* โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
| 1125 |
TABS
|
| 1126 |
-
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ */
|
| 1127 |
function switchTab(name, btn) {
|
| 1128 |
document.querySelectorAll('.tab-panel').forEach(p => p.classList.remove('active'));
|
| 1129 |
document.querySelectorAll('.tab-btn').forEach(b => b.classList.remove('active'));
|
|
@@ -1131,9 +1218,9 @@
|
|
| 1131 |
btn.classList.add('active');
|
| 1132 |
}
|
| 1133 |
|
| 1134 |
-
/* โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
| 1135 |
SESSION TIMER
|
| 1136 |
-
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ */
|
| 1137 |
let sessionSeconds = 0, sessionTimer;
|
| 1138 |
|
| 1139 |
function startSession() {
|
|
@@ -1150,9 +1237,9 @@
|
|
| 1150 |
}, 1000);
|
| 1151 |
}
|
| 1152 |
|
| 1153 |
-
/* โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
| 1154 |
DATE
|
| 1155 |
-
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ */
|
| 1156 |
function updateDate() {
|
| 1157 |
document.getElementById('currentDate').textContent =
|
| 1158 |
new Date().toLocaleDateString('zh-TW', { year: 'numeric', month: '2-digit', day: '2-digit' });
|
|
|
|
| 134 |
opacity: 0.4;
|
| 135 |
}
|
| 136 |
|
|
|
|
| 137 |
.hash-indicator {
|
| 138 |
display: flex;
|
| 139 |
align-items: center;
|
|
|
|
| 145 |
margin-bottom: 18px;
|
| 146 |
}
|
| 147 |
|
| 148 |
+
.hash-icon { font-size: 11px; color: var(--accent-cyan); }
|
|
|
|
|
|
|
|
|
|
| 149 |
|
| 150 |
.hash-text {
|
| 151 |
font-family: 'Orbitron', monospace;
|
|
|
|
| 199 |
|
| 200 |
.field-input::placeholder { color: var(--text-muted); }
|
| 201 |
|
|
|
|
| 202 |
.pass-wrap { position: relative; }
|
| 203 |
.pass-wrap .field-input { padding-right: 44px; }
|
| 204 |
.toggle-pass {
|
|
|
|
| 217 |
}
|
| 218 |
.toggle-pass:hover { color: var(--accent-cyan); }
|
| 219 |
|
|
|
|
| 220 |
.hash-preview {
|
| 221 |
margin-top: 6px;
|
| 222 |
padding: 5px 10px;
|
|
|
|
| 338 |
min-height: 100vh;
|
| 339 |
position: relative;
|
| 340 |
z-index: 1;
|
|
|
|
| 341 |
}
|
| 342 |
|
| 343 |
.topnav {
|
|
|
|
| 353 |
z-index: 50;
|
| 354 |
}
|
| 355 |
|
| 356 |
+
.nav-brand { display: flex; align-items: center; gap: 12px; }
|
|
|
|
|
|
|
|
|
|
|
|
|
| 357 |
|
| 358 |
.brand-icon {
|
| 359 |
width: 32px; height: 32px;
|
|
|
|
| 473 |
.stat-val { color: var(--accent-cyan); }
|
| 474 |
.sep { width:1px; height:12px; background:var(--border); }
|
| 475 |
|
|
|
|
| 476 |
.sec-badge {
|
| 477 |
display: flex;
|
| 478 |
align-items: center;
|
|
|
|
| 612 |
overflow: hidden;
|
| 613 |
}
|
| 614 |
|
| 615 |
+
.stat-card::after { content:''; position:absolute; bottom:0; left:0; right:0; height:2px; }
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 616 |
.stat-card:nth-child(1)::after { background: linear-gradient(90deg, var(--accent-cyan), transparent); }
|
| 617 |
.stat-card:nth-child(2)::after { background: linear-gradient(90deg, var(--accent-orange), transparent); }
|
| 618 |
.stat-card:nth-child(3)::after { background: linear-gradient(90deg, var(--accent-purple), transparent); }
|
|
|
|
| 659 |
|
| 660 |
.open-btn:hover { filter: brightness(1.2); }
|
| 661 |
|
| 662 |
+
/* โโ Verifying overlay โโ */
|
| 663 |
+
#verifyOverlay {
|
| 664 |
+
display: none;
|
| 665 |
+
position: fixed;
|
| 666 |
+
inset: 0;
|
| 667 |
+
background: rgba(5,10,20,.85);
|
| 668 |
+
z-index: 200;
|
| 669 |
+
align-items: center;
|
| 670 |
+
justify-content: center;
|
| 671 |
+
flex-direction: column;
|
| 672 |
+
gap: 16px;
|
| 673 |
+
}
|
| 674 |
+
|
| 675 |
+
#verifyOverlay.show { display: flex; }
|
| 676 |
+
|
| 677 |
+
.verify-spinner {
|
| 678 |
+
width: 48px; height: 48px;
|
| 679 |
+
border: 3px solid rgba(0,229,255,.2);
|
| 680 |
+
border-top-color: var(--accent-cyan);
|
| 681 |
+
border-radius: 50%;
|
| 682 |
+
animation: spin 0.8s linear infinite;
|
| 683 |
+
}
|
| 684 |
+
|
| 685 |
+
.verify-text {
|
| 686 |
+
font-family: 'Orbitron', monospace;
|
| 687 |
+
font-size: 12px;
|
| 688 |
+
letter-spacing: 4px;
|
| 689 |
+
color: var(--accent-cyan);
|
| 690 |
+
}
|
| 691 |
+
|
| 692 |
+
@keyframes spin { to { transform: rotate(360deg); } }
|
| 693 |
+
|
| 694 |
@media (max-width: 900px) {
|
| 695 |
.split-view { grid-template-columns: 1fr; }
|
| 696 |
.stats-row { grid-template-columns: repeat(2,1fr); }
|
|
|
|
| 701 |
</head>
|
| 702 |
<body>
|
| 703 |
|
| 704 |
+
<!-- Verifying overlay (shown during API auth) -->
|
| 705 |
+
<div id="verifyOverlay">
|
| 706 |
+
<div class="verify-spinner"></div>
|
| 707 |
+
<div class="verify-text">SERVER VERIFICATIONโฆ</div>
|
| 708 |
+
</div>
|
| 709 |
+
|
| 710 |
<!-- LOGIN SCREEN -->
|
| 711 |
<div id="loginScreen">
|
| 712 |
<div class="login-wrapper">
|
|
|
|
| 719 |
|
| 720 |
<div class="scan-line"></div>
|
| 721 |
|
|
|
|
| 722 |
<div class="hash-indicator">
|
| 723 |
<span class="hash-icon">๐</span>
|
| 724 |
<span class="hash-text">ๅฏ็ขผๅทฒๅ็จ SHA-256 ้ๆนๅ ๅฏไฟ่ญท</span>
|
|
|
|
| 736 |
<input id="loginPass" class="field-input" type="password" placeholder="่ผธๅ
ฅๅฏ็ขผ" oninput="onPassInput(this.value)">
|
| 737 |
<button class="toggle-pass" type="button" onclick="togglePass()" id="togglePassBtn" title="้กฏ็คบ/้ฑ่ๅฏ็ขผ">๐</button>
|
| 738 |
</div>
|
|
|
|
| 739 |
<div class="hash-preview" id="hashPreview">โ ่ผธๅ
ฅๅฏ็ขผๅพ้กฏ็คบ SHA-256 ้ๆนๅผ โ</div>
|
| 740 |
</div>
|
| 741 |
|
|
|
|
| 765 |
<!-- DASHBOARD -->
|
| 766 |
<div id="dashboard">
|
| 767 |
|
|
|
|
| 768 |
<nav class="topnav">
|
| 769 |
<div class="nav-brand">
|
| 770 |
<div class="brand-icon">๐ท</div>
|
|
|
|
| 788 |
|
| 789 |
<div class="nav-right">
|
| 790 |
<div class="user-chip">
|
| 791 |
+
<div class="user-avatar" id="navAvatar">U</div>
|
| 792 |
+
<span id="navUsername">user</span>
|
| 793 |
</div>
|
| 794 |
<button class="logout-btn" onclick="doLogout()">โป ่ฟๅ็ปๅ
ฅ็ซ้ข</button>
|
| 795 |
</div>
|
| 796 |
</nav>
|
| 797 |
|
|
|
|
| 798 |
<div class="statusbar">
|
| 799 |
<div class="stat-item">
|
| 800 |
<span class="stat-label">SESSION</span>
|
|
|
|
| 818 |
<div class="sep"></div>
|
| 819 |
<div class="stat-item">
|
| 820 |
<span class="stat-label">OPERATOR</span>
|
| 821 |
+
<span class="stat-val" id="sbOperator">โ</span>
|
| 822 |
</div>
|
| 823 |
<div class="sep"></div>
|
| 824 |
<div class="sec-badge">๐ SHA-256 ENCRYPTED</div>
|
| 825 |
</div>
|
| 826 |
|
|
|
|
| 827 |
<div class="content-area">
|
| 828 |
|
| 829 |
<!-- OVERVIEW -->
|
|
|
|
| 841 |
</div>
|
| 842 |
<div class="stat-card">
|
| 843 |
<div class="s-label">็ปๅ
ฅๅธณ่</div>
|
| 844 |
+
<div class="s-val" id="ovUsername" style="font-size:16px;padding-top:6px;">โ</div>
|
| 845 |
<div class="s-sub">ไธ่ฌไฝฟ็จ่
</div>
|
| 846 |
</div>
|
| 847 |
<div class="stat-card">
|
|
|
|
| 857 |
</div>
|
| 858 |
|
| 859 |
<div class="split-view">
|
|
|
|
| 860 |
<div class="iframe-container">
|
| 861 |
<div class="iframe-topbar">
|
| 862 |
<div class="site-info">
|
|
|
|
| 881 |
</div>
|
| 882 |
</div>
|
| 883 |
|
|
|
|
| 884 |
<div class="iframe-container">
|
| 885 |
<div class="iframe-topbar">
|
| 886 |
<div class="site-info">
|
|
|
|
| 919 |
<span class="site-badge momo">MOMO</span>
|
| 920 |
<span class="site-url">https://angelguava-momo-streamlit.hf.space</span>
|
| 921 |
</div>
|
| 922 |
+
<div class="iframe-dots"><span></span><span></span><span></span></div>
|
|
|
|
|
|
|
| 923 |
</div>
|
| 924 |
<iframe src="https://angelguava-momo-streamlit.hf.space" loading="lazy" title="MOMO ็ฌ่ฒ็ณป็ตฑ"></iframe>
|
| 925 |
</div>
|
|
|
|
| 937 |
<span class="site-badge pchome">PCHOME</span>
|
| 938 |
<span class="site-url">https://angelguava-pchome.hf.space</span>
|
| 939 |
</div>
|
| 940 |
+
<div class="iframe-dots"><span></span><span></span><span></span></div>
|
|
|
|
|
|
|
| 941 |
</div>
|
| 942 |
<iframe src="https://angelguava-pchome.hf.space" loading="lazy" title="PChome ็ฌ่ฒ็ณป็ตฑ"></iframe>
|
| 943 |
</div>
|
|
|
|
| 952 |
<div class="split-view">
|
| 953 |
<div class="iframe-container">
|
| 954 |
<div class="iframe-topbar">
|
| 955 |
+
<div class="site-info"><span class="site-badge momo">MOMO</span></div>
|
|
|
|
|
|
|
| 956 |
<div class="iframe-dots"><span></span><span></span><span></span></div>
|
| 957 |
</div>
|
| 958 |
<iframe src="https://angelguava-momo-streamlit.hf.space" loading="lazy" title="MOMO"></iframe>
|
| 959 |
</div>
|
| 960 |
<div class="iframe-container">
|
| 961 |
<div class="iframe-topbar">
|
| 962 |
+
<div class="site-info"><span class="site-badge pchome">PCHOME</span></div>
|
|
|
|
|
|
|
| 963 |
<div class="iframe-dots"><span></span><span></span><span></span></div>
|
| 964 |
</div>
|
| 965 |
<iframe src="https://angelguava-pchome.hf.space" loading="lazy" title="PChome"></iframe>
|
|
|
|
| 972 |
|
| 973 |
|
| 974 |
<script>
|
| 975 |
+
/* โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
| 976 |
+
โ
SECURITY NOTE
|
| 977 |
+
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
| 978 |
+
Credentials are NOT stored in this file.
|
| 979 |
+
The browser sends only the SHA-256 hash of the entered
|
| 980 |
+
password to the Anthropic API. The API system-prompt
|
| 981 |
+
(server-side, invisible to the client) holds the
|
| 982 |
+
authoritative user list and corresponding hashes.
|
| 983 |
+
The front-end never sees the correct hash.
|
| 984 |
+
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ */
|
| 985 |
+
|
| 986 |
+
/* โโ SHA-256 via Web Crypto (browser native) โโ */
|
| 987 |
async function sha256(message) {
|
| 988 |
+
const buf = new TextEncoder().encode(message);
|
| 989 |
+
const hash = await crypto.subtle.digest('SHA-256', buf);
|
| 990 |
+
return Array.from(new Uint8Array(hash))
|
| 991 |
+
.map(b => b.toString(16).padStart(2, '0')).join('');
|
| 992 |
}
|
| 993 |
|
| 994 |
+
/* โโ Live hash preview (cosmetic only) โโ */
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 995 |
async function onPassInput(val) {
|
| 996 |
const el = document.getElementById('hashPreview');
|
| 997 |
if (!val) {
|
|
|
|
| 1000 |
return;
|
| 1001 |
}
|
| 1002 |
const h = await sha256(val);
|
|
|
|
| 1003 |
el.textContent = `SHA-256 โบ ${h.slice(0,16)}โฆ${h.slice(-8)}`;
|
| 1004 |
el.title = h;
|
| 1005 |
el.classList.add('ready');
|
|
|
|
| 1009 |
function togglePass() {
|
| 1010 |
const input = document.getElementById('loginPass');
|
| 1011 |
const btn = document.getElementById('togglePassBtn');
|
| 1012 |
+
input.type = input.type === 'password' ? 'text' : 'password';
|
| 1013 |
+
btn.textContent = input.type === 'password' ? '๐' : '๐';
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1014 |
}
|
| 1015 |
|
| 1016 |
+
/* โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
| 1017 |
CAPTCHA
|
| 1018 |
+
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ */
|
| 1019 |
const CHARS = 'ABCDEFGHJKLMNPQRSTUVWXYZ23456789';
|
| 1020 |
let currentCaptcha = '';
|
| 1021 |
|
|
|
|
| 1031 |
|
| 1032 |
refreshCaptcha();
|
| 1033 |
|
| 1034 |
+
/* โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
| 1035 |
+
SERVER-SIDE AUTH via Anthropic API
|
| 1036 |
+
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
| 1037 |
+
What is sent to the API:
|
| 1038 |
+
โข username (plaintext)
|
| 1039 |
+
โข SHA-256 hash of the password (NOT the password itself)
|
| 1040 |
+
What the API system prompt contains (server-side, hidden):
|
| 1041 |
+
โข The authoritative user list with their hashed passwords
|
| 1042 |
+
The API replies ONLY "GRANTED" or "DENIED".
|
| 1043 |
+
No credential can be extracted from this page's source.
|
| 1044 |
+
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ */
|
| 1045 |
+
|
| 1046 |
+
/**
|
| 1047 |
+
* Calls the Anthropic API to verify credentials.
|
| 1048 |
+
* Returns { granted: bool, username: string }
|
| 1049 |
+
*/
|
| 1050 |
+
async function verifyWithServer(username, passwordHash) {
|
| 1051 |
+
/* โโ SYSTEM PROMPT: authoritative credential store (server-side) โโ
|
| 1052 |
+
Add or edit accounts here. Only SHA-256 hashes are stored.
|
| 1053 |
+
To generate a hash: open browser console and run:
|
| 1054 |
+
crypto.subtle.digest('SHA-256', new TextEncoder().encode('yourpassword'))
|
| 1055 |
+
.then(b => console.log([...new Uint8Array(b)].map(x=>x.toString(16).padStart(2,'0')).join('')))
|
| 1056 |
+
|
| 1057 |
+
Current accounts:
|
| 1058 |
+
user1 / 123456789
|
| 1059 |
+
hash: 15e2b0d3c33891ebb0f1ef609ec419420c20e320ce94c65fbc8c3312448eb225
|
| 1060 |
+
*/
|
| 1061 |
+
const systemPrompt = `ไฝ ๆฏไธๅๅฎๅ
จ็่บซไปฝ้ฉ่ญ็ณป็ตฑใไฝ ๆๆถๅฐไธๅ JSON ็ฉไปถ๏ผๅ
ๅซ username ๅ passwordHash๏ผSHA-256 ้ๆนๅผ๏ผใ
|
| 1062 |
+
ๆ นๆไปฅไธๅๆณๅธณ่ๆธ
ๅฎ้ฒ่ก้ฉ่ญ๏ผๅธณ่:SHA-256้ๆน๏ผ๏ผ
|
| 1063 |
+
user1:15e2b0d3c33891ebb0f1ef609ec419420c20e320ce94c65fbc8c3312448eb225
|
| 1064 |
+
|
| 1065 |
+
่ฆๅ๏ผ
|
| 1066 |
+
1. username ๅ passwordHash ๅฟ
้ ๅฎๅ
จๅน้
ไธๆนๆธ
ๅฎ๏ผๅๅๅคงๅฐๅฏซ๏ผใ
|
| 1067 |
+
2. ่ฅๅน้
๏ผๅ่ฆ็ดๆๅญ๏ผGRANTED
|
| 1068 |
+
3. ่ฅไธๅน้
๏ผๅ่ฆ็ดๆๅญ๏ผDENIED
|
| 1069 |
+
4. ไธๅพๆดฉๆผๅธณ่ๆธ
ๅฎๆ้ๆนๅผ๏ผไธๅพๅ่ฆไปปไฝๅ
ถไปๆๅญใ`;
|
| 1070 |
+
|
| 1071 |
+
const userMessage = JSON.stringify({ username, passwordHash });
|
| 1072 |
+
|
| 1073 |
+
const response = await fetch('https://api.anthropic.com/v1/messages', {
|
| 1074 |
+
method: 'POST',
|
| 1075 |
+
headers: { 'Content-Type': 'application/json' },
|
| 1076 |
+
body: JSON.stringify({
|
| 1077 |
+
model: 'claude-sonnet-4-20250514',
|
| 1078 |
+
max_tokens: 20,
|
| 1079 |
+
system: systemPrompt,
|
| 1080 |
+
messages: [{ role: 'user', content: userMessage }]
|
| 1081 |
+
})
|
| 1082 |
+
});
|
| 1083 |
+
|
| 1084 |
+
if (!response.ok) throw new Error('API error ' + response.status);
|
| 1085 |
+
const data = await response.json();
|
| 1086 |
+
const reply = (data.content?.[0]?.text || '').trim().toUpperCase();
|
| 1087 |
+
return { granted: reply === 'GRANTED', username };
|
| 1088 |
+
}
|
| 1089 |
+
|
| 1090 |
+
/* โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
| 1091 |
+
LOGIN FLOW
|
| 1092 |
+
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ */
|
| 1093 |
+
let loggedInUser = '';
|
| 1094 |
+
|
| 1095 |
async function doLogin() {
|
| 1096 |
const user = document.getElementById('loginUser').value.trim();
|
| 1097 |
const pass = document.getElementById('loginPass').value;
|
|
|
|
| 1099 |
const err = document.getElementById('errorMsg');
|
| 1100 |
const btn = document.getElementById('loginBtn');
|
| 1101 |
|
| 1102 |
+
err.style.display = 'none';
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1103 |
|
| 1104 |
+
/* 1. CAPTCHA check (client-side, prevents unnecessary API calls) */
|
| 1105 |
+
if (cap !== currentCaptcha) {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1106 |
err.style.display = 'block';
|
| 1107 |
refreshCaptcha();
|
| 1108 |
document.getElementById('captchaInput').focus();
|
| 1109 |
+
return;
|
| 1110 |
+
}
|
| 1111 |
+
|
| 1112 |
+
/* 2. Basic field check */
|
| 1113 |
+
if (!user || !pass) {
|
| 1114 |
+
err.style.display = 'block';
|
| 1115 |
+
return;
|
| 1116 |
+
}
|
| 1117 |
+
|
| 1118 |
+
/* 3. Hash the password locally โ only the hash leaves the client */
|
| 1119 |
+
const passwordHash = await sha256(pass);
|
| 1120 |
+
|
| 1121 |
+
/* 4. Ask the API */
|
| 1122 |
+
btn.disabled = true;
|
| 1123 |
+
btn.textContent = 'โณ ้ฉ่ญไธญโฆ';
|
| 1124 |
+
document.getElementById('verifyOverlay').classList.add('show');
|
| 1125 |
+
|
| 1126 |
+
try {
|
| 1127 |
+
const result = await verifyWithServer(user, passwordHash);
|
| 1128 |
+
|
| 1129 |
+
if (result.granted) {
|
| 1130 |
+
loggedInUser = user;
|
| 1131 |
+
showDashboard(user);
|
| 1132 |
+
} else {
|
| 1133 |
+
err.style.display = 'block';
|
| 1134 |
+
refreshCaptcha();
|
| 1135 |
+
document.getElementById('captchaInput').focus();
|
| 1136 |
+
}
|
| 1137 |
+
} catch (e) {
|
| 1138 |
+
err.textContent = 'โ ไผบๆๅจ้ฃ็ทๅคฑๆ๏ผ่ซ็จๅพๅ่ฉฆ';
|
| 1139 |
+
err.style.display = 'block';
|
| 1140 |
+
} finally {
|
| 1141 |
+
document.getElementById('verifyOverlay').classList.remove('show');
|
| 1142 |
btn.disabled = false;
|
| 1143 |
btn.textContent = 'โถ \u00a0 ็ณป็ตฑ็ปๅ
ฅ';
|
| 1144 |
}
|
| 1145 |
}
|
| 1146 |
|
| 1147 |
+
function showDashboard(username) {
|
| 1148 |
+
const ls = document.getElementById('loginScreen');
|
| 1149 |
+
ls.style.opacity = '0';
|
| 1150 |
+
setTimeout(() => {
|
| 1151 |
+
ls.style.display = 'none';
|
| 1152 |
+
// Update username displays
|
| 1153 |
+
document.getElementById('navUsername').textContent = username;
|
| 1154 |
+
document.getElementById('navAvatar').textContent = username[0].toUpperCase();
|
| 1155 |
+
document.getElementById('ovUsername').textContent = username;
|
| 1156 |
+
document.getElementById('sbOperator').textContent = username;
|
| 1157 |
+
|
| 1158 |
+
const dash = document.getElementById('dashboard');
|
| 1159 |
+
dash.style.display = 'flex';
|
| 1160 |
+
startSession();
|
| 1161 |
+
updateDate();
|
| 1162 |
+
}, 500);
|
| 1163 |
+
}
|
| 1164 |
+
|
| 1165 |
['loginUser', 'loginPass', 'captchaInput'].forEach(id => {
|
| 1166 |
document.getElementById(id).addEventListener('keydown', e => {
|
| 1167 |
if (e.key === 'Enter') doLogin();
|
| 1168 |
});
|
| 1169 |
});
|
| 1170 |
|
| 1171 |
+
/* โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
| 1172 |
LOGOUT
|
| 1173 |
+
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ */
|
| 1174 |
function doLogout() {
|
| 1175 |
clearInterval(sessionTimer);
|
| 1176 |
const dash = document.getElementById('dashboard');
|
|
|
|
| 1195 |
document.getElementById('hashPreview').textContent = 'โ ่ผธๅ
ฅๅฏ็ขผๅพ้กฏ็คบ SHA-256 ้ๆนๅผ โ';
|
| 1196 |
document.getElementById('hashPreview').classList.remove('ready');
|
| 1197 |
document.getElementById('errorMsg').style.display = 'none';
|
| 1198 |
+
document.getElementById('errorMsg').textContent = 'โ \u00a0ๅธณ่ใๅฏ็ขผๆ้ฉ่ญ็ขผ้ฏ่ชค๏ผ่ซ้่ฉฆ';
|
| 1199 |
refreshCaptcha();
|
| 1200 |
sessionSeconds = 0;
|
| 1201 |
+
loggedInUser = '';
|
| 1202 |
|
| 1203 |
// Reset tabs
|
| 1204 |
document.querySelectorAll('.tab-panel').forEach(p => p.classList.remove('active'));
|
|
|
|
| 1208 |
}, 400);
|
| 1209 |
}
|
| 1210 |
|
| 1211 |
+
/* โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
| 1212 |
TABS
|
| 1213 |
+
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ */
|
| 1214 |
function switchTab(name, btn) {
|
| 1215 |
document.querySelectorAll('.tab-panel').forEach(p => p.classList.remove('active'));
|
| 1216 |
document.querySelectorAll('.tab-btn').forEach(b => b.classList.remove('active'));
|
|
|
|
| 1218 |
btn.classList.add('active');
|
| 1219 |
}
|
| 1220 |
|
| 1221 |
+
/* โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
| 1222 |
SESSION TIMER
|
| 1223 |
+
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ */
|
| 1224 |
let sessionSeconds = 0, sessionTimer;
|
| 1225 |
|
| 1226 |
function startSession() {
|
|
|
|
| 1237 |
}, 1000);
|
| 1238 |
}
|
| 1239 |
|
| 1240 |
+
/* โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
| 1241 |
DATE
|
| 1242 |
+
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ */
|
| 1243 |
function updateDate() {
|
| 1244 |
document.getElementById('currentDate').textContent =
|
| 1245 |
new Date().toLocaleDateString('zh-TW', { year: 'numeric', month: '2-digit', day: '2-digit' });
|