Security: Implement strict QR validation (URLs only, whitelisted domains, and username check)

This commit is contained in:
dyzulk
2026-01-12 09:10:11 +07:00
parent 7bddcf24c4
commit a4e8a472f9

View File

@@ -24,9 +24,10 @@ function safeResume() {
function handleDecodedText(decodedText) { function handleDecodedText(decodedText) {
console.log(`Scan result: ${decodedText}`); console.log(`Scan result: ${decodedText}`);
let username = decodedText; let username = "";
let password = ""; let password = "";
let isUnauthorized = false; let isUnauthorized = false;
let blockReason = ""; // Track why it was blocked
scannedUrl = ""; scannedUrl = "";
// Check if result is a URL // Check if result is a URL
@@ -36,35 +37,46 @@ function handleDecodedText(decodedText) {
const hostname = url.hostname; const hostname = url.hostname;
const currentHostname = window.location.hostname; const currentHostname = window.location.hostname;
// SECURITY CHECK: // SECURITY CHECK 1: Domain Whitelist
const isAllowed = (hostname === currentHostname) || (brandConfig.allowedDomains && brandConfig.allowedDomains.some(domain => const isAllowed = (hostname === currentHostname) || (brandConfig.allowedDomains && brandConfig.allowedDomains.some(domain =>
hostname === domain || hostname.endsWith('.' + domain) hostname === domain || hostname.endsWith('.' + domain)
)); ));
if (isAllowed) { if (isAllowed) {
scannedUrl = decodedText; // Store for redirection // SECURITY CHECK 2: MikroTik Standards (Must have at least username)
const searchParams = url.search || (decodedText.includes('?') ? '?' + decodedText.split('?')[1] : ''); const searchParams = url.search || (decodedText.includes('?') ? '?' + decodedText.split('?')[1] : '');
const params = new URLSearchParams(searchParams); const params = new URLSearchParams(searchParams);
if (params.has('username')) { if (params.has('username')) {
scannedUrl = decodedText; // Approved for redirection
username = params.get('username'); username = params.get('username');
}
if (params.has('password')) { if (params.has('password')) {
password = params.get('password'); password = params.get('password');
} }
} else {
isUnauthorized = true;
blockReason = "Invalid MikroTik Login URL";
}
} else { } else {
// ILLEGAL DOMAIN: Strict blocking // ILLEGAL DOMAIN: Strict blocking
console.warn(`Blocked unauthorized domain: ${hostname}`); console.warn(`Blocked unauthorized domain: ${hostname}`);
isUnauthorized = true; isUnauthorized = true;
username = hostname; // Show the blocked domain name blockReason = `Unauthorized Domain: ${hostname}`;
} }
} else {
// NOT A URL: Block plain text / WiFi SSIDs per requirement
isUnauthorized = true;
blockReason = "Invalid Content (Only URL allowed)";
console.warn("Blocked non-URL content:", decodedText);
} }
} catch (e) { } catch (e) {
console.error("Error parsing QR URL:", e); console.error("Error parsing QR URL:", e);
isUnauthorized = true;
blockReason = "QR Parse Error";
} }
// Fill inputs (only if authorized) // Fill inputs (only if authorized)
if (!isUnauthorized) { if (!isUnauthorized && username) {
const voucherInput = document.getElementById('voucher-input'); const voucherInput = document.getElementById('voucher-input');
const passField = document.getElementById('voucher-pass'); const passField = document.getElementById('voucher-pass');
if (voucherInput) voucherInput.value = username; if (voucherInput) voucherInput.value = username;
@@ -78,7 +90,7 @@ function handleDecodedText(decodedText) {
if (overlay && confirmUser) { if (overlay && confirmUser) {
if (isUnauthorized) { if (isUnauthorized) {
confirmUser.innerHTML = `<span style="color: #ff4d4d;">Blocked: ${username}</span>`; confirmUser.innerHTML = `<span style="color: #ff4d4d;">Blocked: ${blockReason}</span>`;
if (connectBtn) connectBtn.style.display = 'none'; if (connectBtn) connectBtn.style.display = 'none';
} else { } else {
confirmUser.innerText = username; confirmUser.innerText = username;