mirror of
https://github.com/pacnpal/simpleguardhome.git
synced 2025-12-20 04:21:13 -05:00
179 lines
10 KiB
HTML
179 lines
10 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<title>SimpleGuardHome</title>
|
|
<script src="https://unpkg.com/@tailwindcss/browser@4" integrity="sha384-fsXZ0Oru5QjGkveFx8DdmBAyKdwnJ7TnbRzDN5LROCKt8PAN8h7y7oqCwtk9cN68" crossorigin="anonymous"></script>
|
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/dompurify/2.3.4/purify.min.js" integrity="sha384-KGmzmwrs7oAU2sG5qfETslFsscVcCaxQrX2d7PW7I9bTrsuTD/eSMFr9jaMS9i+b" crossorigin="anonymous"></script>
|
|
<script>
|
|
function escapeHtml(unsafe) {
|
|
return unsafe.replace(/[&<"']/g, function (m) {
|
|
switch (m) {
|
|
case '&': return '&';
|
|
case '<': return '<';
|
|
case '>': return '>';
|
|
case '"': return '"';
|
|
case "'": return ''';
|
|
default: return m;
|
|
}
|
|
});
|
|
}
|
|
async function checkDomain(event) {
|
|
event.preventDefault();
|
|
const domain = DOMPurify.sanitize(document.getElementById('domain').value);
|
|
const resultDiv = document.getElementById('result');
|
|
const unblockDiv = document.getElementById('unblock-action');
|
|
const submitBtn = document.getElementById('submit-btn');
|
|
|
|
try {
|
|
// Show loading state
|
|
submitBtn.disabled = true;
|
|
submitBtn.innerHTML = '<span class="inline-flex items-center">Checking... <svg class="animate-spin ml-2 h-5 w-5 text-white" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24"><circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle><path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path></svg></span>';
|
|
|
|
const response = await fetch(`/control/filtering/check_host?name=${encodeURIComponent(domain)}`, {
|
|
method: 'GET',
|
|
headers: {
|
|
'Accept': 'application/json',
|
|
}
|
|
});
|
|
|
|
const data = await response.json();
|
|
|
|
if (response.ok) {
|
|
const isBlocked = data.reason.startsWith('Filtered');
|
|
if (isBlocked) {
|
|
resultDiv.innerHTML = `
|
|
<div class="bg-red-100 border-l-4 border-red-500 text-red-700 p-4 mb-4">
|
|
<p class="font-bold">Domain is blocked</p>
|
|
<p class="text-sm"><strong>${escapeHtml(domain)}</strong> is blocked</p>
|
|
<p class="text-sm">Reason: ${escapeHtml(data.reason)}</p>
|
|
${data.rules?.length ? `<p class="text-sm font-mono bg-red-50 p-2 mt-1 rounded">Rule: ${escapeHtml(data.rules[0].text)}</p>` : ''}
|
|
${data.service_name ? `<p class="text-sm mt-2">Service: ${escapeHtml(data.service_name)}</p>` : ''}
|
|
</div>`;
|
|
unblockDiv.innerHTML = `
|
|
<button onclick="unblockDomain('${domain}')"
|
|
class="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded transition-colors duration-200">
|
|
Unblock Domain
|
|
</button>`;
|
|
} else {
|
|
resultDiv.innerHTML = `
|
|
<div class="bg-green-100 border-l-4 border-green-500 text-green-700 p-4">
|
|
<p class="font-bold">Domain is not blocked</p>
|
|
<p class="text-sm"><strong>${escapeHtml(domain)}</strong> is allowed</p>
|
|
<p class="text-xs mt-2">Status: ${escapeHtml(data.reason)}</p>
|
|
</div>`;
|
|
unblockDiv.innerHTML = '';
|
|
}
|
|
} else {
|
|
let errorMsg = data.message || 'Unknown error occurred';
|
|
let errorType = response.status === 400 ? 'warning' : 'error';
|
|
let bgColor = errorType === 'warning' ? 'yellow' : 'red';
|
|
|
|
resultDiv.innerHTML = `
|
|
<div class="bg-${bgColor}-100 border-l-4 border-${bgColor}-500 text-${bgColor}-700 p-4">
|
|
<p class="font-bold">Error checking domain</p>
|
|
<p class="text-sm">${escapeHtml(errorMsg)}</p>
|
|
</div>`;
|
|
unblockDiv.innerHTML = '';
|
|
}
|
|
} catch (error) {
|
|
resultDiv.innerHTML = `
|
|
<div class="bg-red-100 border-l-4 border-red-500 text-red-700 p-4">
|
|
<p class="font-bold">Error checking domain</p>
|
|
<p class="text-sm">${escapeHtml(error.message)}</p>
|
|
</div>`;
|
|
unblockDiv.innerHTML = '';
|
|
} finally {
|
|
submitBtn.disabled = false;
|
|
submitBtn.innerHTML = 'Check Domain';
|
|
}
|
|
}
|
|
|
|
async function unblockDomain(domain) {
|
|
const resultDiv = document.getElementById('result');
|
|
const unblockDiv = document.getElementById('unblock-action');
|
|
const unblockBtn = unblockDiv.querySelector('button');
|
|
|
|
try {
|
|
unblockBtn.disabled = true;
|
|
unblockBtn.innerHTML = '<span class="inline-flex items-center">Unblocking... <svg class="animate-spin ml-2 h-5 w-5 text-white" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24"><circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle><path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path></svg></span>';
|
|
|
|
const response = await fetch('/control/filtering/set_rules', {
|
|
method: 'POST',
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
'Accept': 'application/json'
|
|
},
|
|
body: JSON.stringify({
|
|
rules: [`@@||${domain}^`]
|
|
})
|
|
});
|
|
|
|
if (response.ok) {
|
|
const data = await response.json();
|
|
resultDiv.innerHTML = `
|
|
<div class="bg-green-100 border-l-4 border-green-500 text-green-700 p-4">
|
|
<p class="font-bold">Success!</p>
|
|
<p class="text-sm">${data.message}</p>
|
|
<p class="text-xs mt-2">A backup of the rules has been saved for safety.</p>
|
|
</div>`;
|
|
unblockDiv.innerHTML = '';
|
|
} else {
|
|
const data = await response.json();
|
|
let errorMsg = data.message || 'Unknown error occurred';
|
|
let errorType = response.status === 400 ? 'warning' : 'error';
|
|
let bgColor = errorType === 'warning' ? 'yellow' : 'red';
|
|
|
|
resultDiv.innerHTML = `
|
|
<div class="bg-${bgColor}-100 border-l-4 border-${bgColor}-500 text-${bgColor}-700 p-4">
|
|
<p class="font-bold">Error unblocking domain</p>
|
|
<p class="text-sm">${errorMsg}</p>
|
|
${errorType !== 'warning' ? '<p class="text-xs mt-2">Previous rules have been restored from backup.</p>' : ''}
|
|
</div>`;
|
|
}
|
|
} catch (error) {
|
|
resultDiv.innerHTML = `
|
|
<div class="bg-red-100 border-l-4 border-red-500 text-red-700 p-4">
|
|
<p class="font-bold">Error unblocking domain</p>
|
|
<p class="text-sm">${error.message}</p>
|
|
<p class="text-xs mt-2">Previous rules have been restored from backup.</p>
|
|
</div>`;
|
|
}
|
|
}
|
|
</script>
|
|
</head>
|
|
<body class="bg-gray-100 min-h-screen">
|
|
<div class="container mx-auto px-4 py-8 max-w-2xl">
|
|
<h1 class="text-3xl font-bold text-center mb-8 text-gray-800">SimpleGuardHome</h1>
|
|
|
|
<div class="bg-white rounded-lg shadow-md p-6">
|
|
<form onsubmit="checkDomain(event)" class="mb-6">
|
|
<div class="mb-4">
|
|
<label for="domain" class="block text-gray-700 text-sm font-bold mb-2">
|
|
Enter Domain to Check
|
|
</label>
|
|
<input type="text" id="domain" name="domain" required pattern="^[a-zA-Z0-9][a-zA-Z0-9-]{0,61}[a-zA-Z0-9](\.[a-zA-Z0-9][a-zA-Z0-9-]{0,61}[a-zA-Z0-9])*$"
|
|
class="shadow appearance-none border rounded w-full py-2 px-3 text-gray-700 leading-tight focus:outline-none focus:shadow-outline"
|
|
placeholder="example.com"
|
|
title="Please enter a valid domain name">
|
|
</div>
|
|
<button id="submit-btn" type="submit"
|
|
class="bg-green-500 hover:bg-green-700 text-white font-bold py-2 px-4 rounded w-full transition-colors duration-200">
|
|
Check Domain
|
|
</button>
|
|
</form>
|
|
|
|
<div id="result"></div>
|
|
<div id="unblock-action" class="mt-4 text-center"></div>
|
|
</div>
|
|
|
|
<div class="mt-4 text-center text-gray-600 text-sm">
|
|
Make sure your AdGuard Home instance is running and properly configured in the .env file.
|
|
<br>
|
|
<span class="text-xs">Rules are automatically backed up before any changes.</span>
|
|
</div>
|
|
</div>
|
|
</body>
|
|
</html>
|