mirror of
https://github.com/pacnpal/simpleguardhome.git
synced 2025-12-20 12:31:16 -05:00
feat(userscript): add SimpleGuardHome 404 Checker userscript with domain blocking detection and configuration options
This commit is contained in:
79
userscript/README.md
Normal file
79
userscript/README.md
Normal file
@@ -0,0 +1,79 @@
|
||||
# SimpleGuardHome 404 Checker Userscript
|
||||
|
||||
A Tampermonkey userscript that detects 404 responses while browsing and automatically checks if the domains are blocked by your AdGuard Home instance. This helps identify when DNS blocking might be causing page load failures.
|
||||
|
||||
## Features
|
||||
|
||||
- Automatically detects 404 responses from both fetch and XMLHttpRequest calls
|
||||
- Checks failed domains against your AdGuard Home instance
|
||||
- Shows notifications for blocked domains with unblock option
|
||||
- Configurable AdGuard Home instance settings
|
||||
- Caches results to minimize API calls
|
||||
- Error handling with configuration shortcuts
|
||||
|
||||
## Installation
|
||||
|
||||
1. Install the [Tampermonkey](https://www.tampermonkey.net/) browser extension
|
||||
2. Click on the Tampermonkey icon and select "Create a new script"
|
||||
3. Copy the contents of `simpleguardhome-404-checker.user.js` into the editor
|
||||
4. Save the script (Ctrl+S or File -> Save)
|
||||
|
||||
## Configuration
|
||||
|
||||
1. Click on the Tampermonkey icon in your browser
|
||||
2. Select "Configure SimpleGuardHome Instance" under the script's menu
|
||||
3. Enter your AdGuard Home host (e.g., `http://localhost`)
|
||||
4. Enter your AdGuard Home port (default: 3000)
|
||||
|
||||
### Default Settings
|
||||
- Host: `http://localhost`
|
||||
- Port: `3000`
|
||||
|
||||
## How It Works
|
||||
|
||||
1. The script monitors all web requests on any website
|
||||
2. When a 404 response is detected:
|
||||
- Extracts the domain from the failed URL
|
||||
- Checks if the domain is blocked by AdGuard Home
|
||||
- Shows a notification if the domain is blocked
|
||||
- Provides a quick "Unblock" button to open SimpleGuardHome
|
||||
|
||||
3. Error handling:
|
||||
- Connection issues show a notification with configuration options
|
||||
- Results are cached for 1 hour to reduce API load
|
||||
- Failed requests provide clear error messages
|
||||
|
||||
## Technical Details
|
||||
|
||||
### Required Permissions
|
||||
- `GM_xmlhttpRequest`: For making cross-origin requests to AdGuard Home
|
||||
- `GM_getValue`/`GM_setValue`: For storing configuration
|
||||
- `GM_registerMenuCommand`: For adding configuration menu
|
||||
- `@connect *`: For connecting to custom AdGuard Home instances
|
||||
|
||||
### Cache System
|
||||
- Domain check results are cached for 1 hour
|
||||
- Cache includes:
|
||||
- Block status
|
||||
- Blocking reason
|
||||
- Applied rules
|
||||
- Timestamp
|
||||
|
||||
### Error Handling
|
||||
- Connection failures
|
||||
- Request timeouts
|
||||
- API errors
|
||||
- JSON parsing errors
|
||||
|
||||
## Development
|
||||
|
||||
The userscript is part of the SimpleGuardHome project and is designed to complement the main application by providing real-time feedback during web browsing.
|
||||
|
||||
To modify or extend the script:
|
||||
1. Make changes to `simpleguardhome-404-checker.user.js`
|
||||
2. Update version number in the metadata block
|
||||
3. Reinstall in Tampermonkey to test changes
|
||||
|
||||
## License
|
||||
|
||||
Same as the main SimpleGuardHome project
|
||||
197
userscript/simpleguardhome-404-checker.user.js
Normal file
197
userscript/simpleguardhome-404-checker.user.js
Normal file
@@ -0,0 +1,197 @@
|
||||
// ==UserScript==
|
||||
// @name SimpleGuardHome 404 Checker
|
||||
// @namespace http://tampermonkey.net/
|
||||
// @version 0.1
|
||||
// @description Detects 404 responses and checks if they are blocked by AdGuard Home
|
||||
// @author SimpleGuardHome
|
||||
// @match *://*/*
|
||||
// @grant GM_xmlhttpRequest
|
||||
// @grant GM_getValue
|
||||
// @grant GM_setValue
|
||||
// @grant GM_registerMenuCommand
|
||||
// @connect *
|
||||
// @run-at document-start
|
||||
// ==/UserScript==
|
||||
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
// Default configuration
|
||||
const DEFAULT_CONFIG = {
|
||||
host: 'http://localhost',
|
||||
port: 3000
|
||||
};
|
||||
|
||||
// Get current configuration
|
||||
function getConfig() {
|
||||
return {
|
||||
host: GM_getValue('host', DEFAULT_CONFIG.host),
|
||||
port: GM_getValue('port', DEFAULT_CONFIG.port)
|
||||
};
|
||||
}
|
||||
|
||||
// Show configuration dialog
|
||||
function showConfigDialog() {
|
||||
const config = getConfig();
|
||||
const host = prompt('Enter SimpleGuardHome host (e.g. http://localhost):', config.host);
|
||||
if (host === null) return;
|
||||
|
||||
const port = prompt('Enter SimpleGuardHome port:', config.port);
|
||||
if (port === null) return;
|
||||
|
||||
GM_setValue('host', host);
|
||||
GM_setValue('port', parseInt(port, 10) || DEFAULT_CONFIG.port);
|
||||
|
||||
alert('Configuration saved! The new settings will be used for future checks.');
|
||||
}
|
||||
|
||||
// Register configuration menu command
|
||||
GM_registerMenuCommand('Configure SimpleGuardHome Instance', showConfigDialog);
|
||||
|
||||
// Store check results to avoid repeated API calls
|
||||
const checkedDomains = new Map();
|
||||
|
||||
// Intercept 404 responses using a fetch handler
|
||||
const originalFetch = window.fetch;
|
||||
window.fetch = async function(...args) {
|
||||
try {
|
||||
const response = await originalFetch.apply(this, args);
|
||||
if (response.status === 404) {
|
||||
const url = new URL(args[0].toString());
|
||||
checkDomain(url.hostname);
|
||||
}
|
||||
return response;
|
||||
} catch (error) {
|
||||
console.error('SimpleGuardHome 404 Checker Error:', error);
|
||||
return originalFetch.apply(this, args);
|
||||
}
|
||||
};
|
||||
|
||||
// Also intercept XHR for broader compatibility
|
||||
const originalXHROpen = XMLHttpRequest.prototype.open;
|
||||
XMLHttpRequest.prototype.open = function(method, url, ...rest) {
|
||||
const originalOnReadyStateChange = this.onreadystatechange;
|
||||
this.onreadystatechange = function() {
|
||||
if (this.readyState === 4 && this.status === 404) {
|
||||
const urlObj = new URL(url, window.location.href);
|
||||
checkDomain(urlObj.hostname);
|
||||
}
|
||||
if (originalOnReadyStateChange) {
|
||||
originalOnReadyStateChange.apply(this, arguments);
|
||||
}
|
||||
};
|
||||
originalXHROpen.apply(this, [method, url, ...rest]);
|
||||
};
|
||||
|
||||
// Check if domain is blocked by AdGuard Home
|
||||
async function checkDomain(domain) {
|
||||
// Skip if already checked recently
|
||||
if (checkedDomains.has(domain)) {
|
||||
const cachedResult = checkedDomains.get(domain);
|
||||
if (Date.now() - cachedResult.timestamp < 3600000) { // Cache for 1 hour
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
const config = getConfig();
|
||||
const apiUrl = `${config.host}:${config.port}/control/filtering/check_host?name=${encodeURIComponent(domain)}`;
|
||||
|
||||
GM_xmlhttpRequest({
|
||||
method: 'GET',
|
||||
url: apiUrl,
|
||||
headers: {
|
||||
'Accept': 'application/json'
|
||||
},
|
||||
onload: function(response) {
|
||||
try {
|
||||
const data = JSON.parse(response.responseText);
|
||||
const isBlocked = data.reason.startsWith('Filtered');
|
||||
|
||||
// Cache the result
|
||||
checkedDomains.set(domain, {
|
||||
isBlocked,
|
||||
reason: data.reason,
|
||||
rules: data.rules,
|
||||
timestamp: Date.now()
|
||||
});
|
||||
|
||||
// Show notification if blocked
|
||||
if (isBlocked) {
|
||||
showNotification(domain, data);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('SimpleGuardHome parsing error:', error);
|
||||
}
|
||||
},
|
||||
onerror: function(error) {
|
||||
console.error('SimpleGuardHome API error:', error);
|
||||
showNotification(domain, null, 'Unable to connect to SimpleGuardHome instance. Please check your configuration.');
|
||||
},
|
||||
onabort: function() {
|
||||
console.error('SimpleGuardHome API request aborted');
|
||||
showNotification(domain, null, 'Request to SimpleGuardHome instance was aborted. Please check your configuration.');
|
||||
},
|
||||
ontimeout: function() {
|
||||
console.error('SimpleGuardHome API request timed out');
|
||||
showNotification(domain, null, 'Request to SimpleGuardHome instance timed out. Please check your configuration.');
|
||||
}
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('SimpleGuardHome check error:', error);
|
||||
}
|
||||
}
|
||||
|
||||
// Show a notification when a blocked domain is detected
|
||||
function showNotification(domain, data, error = null) {
|
||||
const notification = document.createElement('div');
|
||||
const config = getConfig();
|
||||
|
||||
notification.style.cssText = `
|
||||
position: fixed;
|
||||
top: 20px;
|
||||
right: 20px;
|
||||
padding: 15px;
|
||||
background: ${error ? '#fff3cd' : '#f8d7d9'};
|
||||
border-left: 4px solid ${error ? '#ffc107' : '#dc3545'};
|
||||
border-radius: 4px;
|
||||
box-shadow: 0 2px 5px rgba(0,0,0,0.2);
|
||||
z-index: 9999;
|
||||
max-width: 400px;
|
||||
font-family: system-ui, -apple-system, sans-serif;
|
||||
`;
|
||||
|
||||
if (error) {
|
||||
notification.innerHTML = `
|
||||
<div style="font-weight: bold; margin-bottom: 5px;">SimpleGuardHome Error</div>
|
||||
<div style="font-size: 14px;">${error}</div>
|
||||
<button style="margin-top: 10px; background: #ffc107; color: black; border: none; padding: 5px 10px; border-radius: 3px; cursor: pointer;">Configure Instance</button>
|
||||
`;
|
||||
|
||||
const configButton = notification.querySelector('button');
|
||||
configButton.addEventListener('click', () => {
|
||||
showConfigDialog();
|
||||
notification.remove();
|
||||
});
|
||||
} else {
|
||||
notification.innerHTML = `
|
||||
<div style="font-weight: bold; margin-bottom: 5px;">404 Domain is Blocked</div>
|
||||
<div style="font-size: 14px;"><strong>${domain}</strong></div>
|
||||
<div style="font-size: 12px; margin-top: 5px;">Reason: ${data.reason}</div>
|
||||
${data.rules?.length ? `<div style="font-size: 12px; margin-top: 5px; background: rgba(0,0,0,0.05); padding: 5px; border-radius: 3px;">Rule: ${data.rules[0].text}</div>` : ''}
|
||||
<button style="margin-top: 10px; background: #0d6efd; color: white; border: none; padding: 5px 10px; border-radius: 3px; cursor: pointer;">Unblock Domain</button>
|
||||
`;
|
||||
|
||||
const unblockButton = notification.querySelector('button');
|
||||
unblockButton.addEventListener('click', () => {
|
||||
window.open(`${config.host}:${config.port}/?domain=${encodeURIComponent(domain)}`, '_blank');
|
||||
notification.remove();
|
||||
});
|
||||
}
|
||||
|
||||
// Auto-remove after 10 seconds
|
||||
setTimeout(() => notification.remove(), 10000);
|
||||
|
||||
document.body.appendChild(notification);
|
||||
}
|
||||
})();
|
||||
Reference in New Issue
Block a user