mirror of
https://github.com/pacnpal/simpleguardhome.git
synced 2025-12-19 20:11:14 -05:00
feat(main.py): add endpoint to unblock a domain and improve error handling
fix(userscript): update default port and restore 404 response interception
This commit is contained in:
197
README.md
197
README.md
@@ -7,7 +7,7 @@
|
|||||||
<p align="center">
|
<p align="center">
|
||||||
<a href="https://github.com/pacnpal/simpleguardhome/releases"><img src="https://img.shields.io/badge/version-0.1.0-blue.svg" alt="Version 0.1.0"></a>
|
<a href="https://github.com/pacnpal/simpleguardhome/releases"><img src="https://img.shields.io/badge/version-0.1.0-blue.svg" alt="Version 0.1.0"></a>
|
||||||
<a href="LICENSE"><img src="https://img.shields.io/badge/license-MIT-green.svg" alt="MIT License"></a>
|
<a href="LICENSE"><img src="https://img.shields.io/badge/license-MIT-green.svg" alt="MIT License"></a>
|
||||||
<a href="#requirements"><img src="https://img.shields.io/badge/python-3.9+-blue.svg" alt="Python 3.9+"></a>
|
<a href="#requirements"><img src="https://img.shields.io/badge/python-3.7+-blue.svg" alt="Python 3.7+"></a>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
A modern web application for checking and managing domain filtering in AdGuard Home. Built with FastAPI and modern JavaScript, following the official AdGuard Home OpenAPI specification.
|
A modern web application for checking and managing domain filtering in AdGuard Home. Built with FastAPI and modern JavaScript, following the official AdGuard Home OpenAPI specification.
|
||||||
@@ -27,9 +27,11 @@ Then visit `http://localhost:8000` to start managing your AdGuard Home filtering
|
|||||||
|
|
||||||
## Features
|
## Features
|
||||||
|
|
||||||
|
### Core Features
|
||||||
- 🔍 Real-time domain filtering status checks
|
- 🔍 Real-time domain filtering status checks
|
||||||
- 🚫 One-click domain unblocking
|
- 🚫 One-click domain unblocking
|
||||||
- 💻 Modern, responsive web interface with Tailwind CSS
|
- 💻 Modern, responsive web interface with Tailwind CSS
|
||||||
|
- 🌓 Support for light and dark modes
|
||||||
- 🔄 Live feedback and error handling
|
- 🔄 Live feedback and error handling
|
||||||
- 📝 Comprehensive logging
|
- 📝 Comprehensive logging
|
||||||
- 🏥 Health monitoring endpoint
|
- 🏥 Health monitoring endpoint
|
||||||
@@ -38,10 +40,18 @@ Then visit `http://localhost:8000` to start managing your AdGuard Home filtering
|
|||||||
- ✅ Implements official AdGuard Home API spec
|
- ✅ Implements official AdGuard Home API spec
|
||||||
- 🐳 Docker support
|
- 🐳 Docker support
|
||||||
|
|
||||||
|
### Browser Integration
|
||||||
|
- 🔎 404 Page Checker Userscript
|
||||||
|
- Automatically detects 404 responses while browsing
|
||||||
|
- Checks if failed domains are blocked by AdGuard Home
|
||||||
|
- Shows unblock notifications with one-click actions
|
||||||
|
- Configurable settings and caching system
|
||||||
|
- Tampermonkey integration for all major browsers
|
||||||
|
|
||||||
## Requirements
|
## Requirements
|
||||||
|
|
||||||
### System Requirements
|
### System Requirements
|
||||||
- Python 3.9 or higher (for local installation)
|
- Python 3.7 or higher (for local installation)
|
||||||
- Running AdGuard Home instance
|
- Running AdGuard Home instance
|
||||||
- AdGuard Home API credentials
|
- AdGuard Home API credentials
|
||||||
- Docker (optional, for containerized deployment)
|
- Docker (optional, for containerized deployment)
|
||||||
@@ -148,13 +158,32 @@ python -m uvicorn src.simpleguardhome.main:app --reload
|
|||||||
|
|
||||||
The application will be available at `http://localhost:8000`
|
The application will be available at `http://localhost:8000`
|
||||||
|
|
||||||
|
## Browser Integration Setup
|
||||||
|
|
||||||
|
1. Install the [Tampermonkey](https://www.tampermonkey.net/) browser extension
|
||||||
|
2. Navigate to the `userscript` directory in this repository
|
||||||
|
3. Install the `simpleguardhome-404-checker.user.js` script
|
||||||
|
4. Configure the script with your AdGuard Home instance details
|
||||||
|
|
||||||
|
The userscript will automatically:
|
||||||
|
- Monitor web requests for 404 responses
|
||||||
|
- Check if failed domains are blocked
|
||||||
|
- Show notifications for blocked domains
|
||||||
|
- Provide quick unblock options
|
||||||
## API Documentation
|
## API Documentation
|
||||||
|
|
||||||
The API documentation is available at:
|
The API documentation is automatically generated by FastAPI using:
|
||||||
- Swagger UI: `http://localhost:8000/api/docs`
|
- Type hints in endpoint definitions
|
||||||
- ReDoc: `http://localhost:8000/api/redoc`
|
- Pydantic models for request/response validation
|
||||||
- OpenAPI Schema: `http://localhost:8000/api/openapi.json`
|
- Function docstrings for descriptions
|
||||||
|
- Response models and status codes
|
||||||
|
|
||||||
|
Documentation is available at:
|
||||||
|
- Swagger UI: `http://localhost:8000/api/docs` - Interactive API documentation
|
||||||
|
- ReDoc: `http://localhost:8000/api/redoc` - Alternative documentation UI
|
||||||
|
- OpenAPI Schema: `http://localhost:8000/api/openapi.json` - Raw OpenAPI specification
|
||||||
|
|
||||||
|
### API Endpoints
|
||||||
### API Endpoints
|
### API Endpoints
|
||||||
|
|
||||||
All endpoints follow the official AdGuard Home API specification:
|
All endpoints follow the official AdGuard Home API specification:
|
||||||
@@ -163,13 +192,19 @@ All endpoints follow the official AdGuard Home API specification:
|
|||||||
- `GET /` - Main web interface for domain checking and unblocking
|
- `GET /` - Main web interface for domain checking and unblocking
|
||||||
|
|
||||||
#### Filtering Endpoints
|
#### Filtering Endpoints
|
||||||
- `POST /control/filtering/check_host` - Check if a domain is blocked
|
- `GET /control/filtering/check_host` - Check if a domain is blocked
|
||||||
- Parameters: `name` (query parameter)
|
- Parameters: `name` (query parameter)
|
||||||
- Returns: Detailed filtering status and rules
|
- Returns: Detailed filtering status and rules
|
||||||
|
|
||||||
- `POST /control/filtering/whitelist/add` - Add a domain to the allowed list
|
- `GET /control/filtering/unblock_host` - Unblock a domain by adding it to whitelist
|
||||||
- Parameters: `name` (JSON body)
|
- Parameters: `name` (query parameter)
|
||||||
- Returns: Success status
|
- Returns: Success message with domain status
|
||||||
|
- Status: Returns whether domain was unblocked, already unblocked, or not blocked
|
||||||
|
|
||||||
|
- `POST /control/filtering/set_rules` - Add domains to the filtering rules
|
||||||
|
- Parameters: Array of rules in request body
|
||||||
|
- Returns: Success message on successful update
|
||||||
|
- Note: Used internally by unblock_host endpoint
|
||||||
|
|
||||||
- `GET /control/filtering/status` - Get current filtering configuration
|
- `GET /control/filtering/status` - Get current filtering configuration
|
||||||
- Returns: Complete filtering status including rules and filters
|
- Returns: Complete filtering status including rules and filters
|
||||||
@@ -178,6 +213,63 @@ All endpoints follow the official AdGuard Home API specification:
|
|||||||
- `GET /control/status` - Check application and AdGuard Home connection status
|
- `GET /control/status` - Check application and AdGuard Home connection status
|
||||||
- Returns: Health status with filtering state
|
- Returns: Health status with filtering state
|
||||||
|
|
||||||
|
## Project Structure
|
||||||
|
|
||||||
|
```
|
||||||
|
simpleguardhome/
|
||||||
|
├── src/
|
||||||
|
│ └── simpleguardhome/
|
||||||
|
│ ├── __init__.py
|
||||||
|
│ ├── main.py # FastAPI application
|
||||||
|
│ ├── config.py # Configuration management
|
||||||
|
│ ├── adguard.py # AdGuard Home API client
|
||||||
|
│ └── templates/
|
||||||
|
│ └── index.html # Web interface
|
||||||
|
├── static/
|
||||||
|
│ └── simpleguardhome.png # Project logo
|
||||||
|
├── userscript/
|
||||||
|
│ ├── README.md # Userscript documentation
|
||||||
|
│ └── simpleguardhome-404-checker.user.js
|
||||||
|
├── rules_backup/ # Backup storage location
|
||||||
|
├── requirements.txt
|
||||||
|
├── setup.py
|
||||||
|
├── pyproject.toml # Project metadata and dependencies
|
||||||
|
├── .env.example
|
||||||
|
├── Dockerfile
|
||||||
|
└── README.md
|
||||||
|
```
|
||||||
|
|
||||||
|
## Security Notes
|
||||||
|
|
||||||
|
- API credentials are handled via environment variables
|
||||||
|
- Connections use proper error handling and timeouts
|
||||||
|
- Input validation is performed on all endpoints
|
||||||
|
- CORS protection with proper headers
|
||||||
|
- Rate limiting on sensitive endpoints
|
||||||
|
- Session-based authentication with AdGuard Home
|
||||||
|
- Sensitive information is not exposed in responses
|
||||||
|
|
||||||
|
## Error Handling
|
||||||
|
|
||||||
|
The application implements comprehensive error handling for all endpoints:
|
||||||
|
|
||||||
|
- 400 Bad Request
|
||||||
|
- Invalid domain format
|
||||||
|
- Missing required parameters
|
||||||
|
- Invalid whitelist rule format
|
||||||
|
- 500 Internal Server Error
|
||||||
|
- Failed to add domain to whitelist
|
||||||
|
- Other internal processing errors
|
||||||
|
- 502 Bad Gateway
|
||||||
|
- AdGuard Home API errors
|
||||||
|
- Invalid API responses
|
||||||
|
- 503 Service Unavailable
|
||||||
|
- AdGuard Home service unreachable
|
||||||
|
- Connection timeouts
|
||||||
|
- Network errors
|
||||||
|
|
||||||
|
All errors return an ErrorResponse object with a descriptive message.
|
||||||
|
|
||||||
## Response Models
|
## Response Models
|
||||||
|
|
||||||
The application uses Pydantic models that match the AdGuard Home API specification:
|
The application uses Pydantic models that match the AdGuard Home API specification:
|
||||||
@@ -200,74 +292,37 @@ The application uses Pydantic models that match the AdGuard Home API specificati
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### DomainCheckResult
|
### FilterCheckHostResponse
|
||||||
```python
|
```python
|
||||||
{
|
{
|
||||||
"reason": str, # Filtering status (e.g., "FilteredBlackList")
|
"reason": str, # Filtering status (e.g., "FilteredBlackList", "NotFilteredNotFound")
|
||||||
"rule": str, # Applied filtering rule
|
"filter_id": int, # Optional: ID of the filter containing the rule (deprecated)
|
||||||
"filter_id": int, # ID of the filter containing the rule
|
"rule": str, # Optional: Applied filtering rule (deprecated)
|
||||||
"service_name": str, # For blocked services
|
"rules": [ # List of applied rules with details
|
||||||
"cname": str, # For CNAME rewrites
|
{
|
||||||
"ip_addrs": List[str] # For A/AAAA rewrites
|
"filter_list_id": int, # Filter list ID
|
||||||
|
"text": str # Rule text
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"service_name": str, # Optional: For blocked services
|
||||||
|
"cname": str, # Optional: For CNAME rewrites
|
||||||
|
"ip_addrs": List[str] # Optional: For A/AAAA rewrites
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
## Error Handling
|
### SetRulesRequest
|
||||||
|
```python
|
||||||
The application implements proper error handling according to the AdGuard Home API spec:
|
{
|
||||||
|
"rules": List[str] # List of filtering rules to set
|
||||||
- 400 Bad Request - Invalid input
|
}
|
||||||
- 401 Unauthorized - Authentication required
|
|
||||||
- 403 Forbidden - Authentication failed
|
|
||||||
- 502 Bad Gateway - AdGuard Home API error
|
|
||||||
- 503 Service Unavailable - AdGuard Home unreachable
|
|
||||||
|
|
||||||
## Development
|
|
||||||
|
|
||||||
### Project Structure
|
|
||||||
|
|
||||||
```
|
|
||||||
simpleguardhome/
|
|
||||||
├── src/
|
|
||||||
│ └── simpleguardhome/
|
|
||||||
│ ├── __init__.py
|
|
||||||
│ ├── main.py # FastAPI application
|
|
||||||
│ ├── config.py # Configuration management
|
|
||||||
│ ├── adguard.py # AdGuard Home API client
|
|
||||||
│ └── templates/
|
|
||||||
│ └── index.html # Web interface
|
|
||||||
├── static/
|
|
||||||
│ └── simpleguardhome.png # Project logo
|
|
||||||
├── requirements.txt
|
|
||||||
├── setup.py
|
|
||||||
├── .env.example
|
|
||||||
├── Dockerfile
|
|
||||||
├── docker-compose.yml
|
|
||||||
└── README.md
|
|
||||||
```
|
```
|
||||||
|
|
||||||
### Adding New Features
|
### ErrorResponse
|
||||||
|
```python
|
||||||
1. Backend Changes:
|
{
|
||||||
- Add routes in `main.py`
|
"message": str # Error description
|
||||||
- Extend AdGuard client in `adguard.py`
|
}
|
||||||
- Update configuration in `config.py`
|
```
|
||||||
- Follow AdGuard Home OpenAPI spec
|
|
||||||
|
|
||||||
2. Frontend Changes:
|
|
||||||
- Modify `templates/index.html`
|
|
||||||
- Use Tailwind CSS for styling
|
|
||||||
- Follow existing error handling patterns
|
|
||||||
|
|
||||||
## Security Notes
|
|
||||||
|
|
||||||
- API credentials are handled via environment variables
|
|
||||||
- Connections use proper error handling and timeouts
|
|
||||||
- Input validation is performed on all endpoints
|
|
||||||
- CORS protection with proper headers
|
|
||||||
- Rate limiting on sensitive endpoints
|
|
||||||
- Session-based authentication with AdGuard Home
|
|
||||||
- Sensitive information is not exposed in responses
|
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
|
|||||||
2
setup.py
2
setup.py
@@ -1,4 +1,4 @@
|
|||||||
from setuptools import setup, find_namespace_packages
|
from setuptools import setup, find_namespace_packages # type: ignore
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
try:
|
try:
|
||||||
|
|||||||
@@ -192,6 +192,59 @@ async def get_filtering_status() -> FilterStatus:
|
|||||||
raise
|
raise
|
||||||
|
|
||||||
|
|
||||||
|
@app.get(
|
||||||
|
"/control/filtering/unblock_host",
|
||||||
|
response_model=Dict,
|
||||||
|
responses={
|
||||||
|
200: {"description": "OK"},
|
||||||
|
400: {"description": "Bad Request", "model": ErrorResponse},
|
||||||
|
503: {"description": "AdGuard Home service unavailable", "model": ErrorResponse}
|
||||||
|
},
|
||||||
|
tags=["filtering"]
|
||||||
|
)
|
||||||
|
async def unblock_host(name: str) -> Dict:
|
||||||
|
"""Unblock a domain by adding it to the whitelist if it's blocked."""
|
||||||
|
if not name:
|
||||||
|
raise HTTPException(
|
||||||
|
status_code=status.HTTP_400_BAD_REQUEST,
|
||||||
|
detail="Domain name is required"
|
||||||
|
)
|
||||||
|
|
||||||
|
logger.info(f"Checking domain status: {name}")
|
||||||
|
try:
|
||||||
|
async with adguard.AdGuardClient() as client:
|
||||||
|
# First check if domain is blocked
|
||||||
|
check_result = await client.check_domain(name)
|
||||||
|
|
||||||
|
# If domain isn't blocked, no need to check whitelist or do anything else
|
||||||
|
if check_result.reason != "FilteredBlackList":
|
||||||
|
return {"message": f"Domain {name} is not blocked (Status: {check_result.reason})"}
|
||||||
|
|
||||||
|
# Domain is blocked, check if it's already in whitelist
|
||||||
|
status_rules = await client.get_filter_status()
|
||||||
|
whitelist_rule = f"@@||{name}^"
|
||||||
|
if status_rules.user_rules and whitelist_rule in status_rules.user_rules:
|
||||||
|
return {"message": f"Domain {name} is already unblocked"}
|
||||||
|
|
||||||
|
# Domain is blocked and not in whitelist, proceed with unblocking
|
||||||
|
success = await client.add_allowed_domain(name)
|
||||||
|
if success:
|
||||||
|
return {"message": f"Domain {name} has been unblocked"}
|
||||||
|
else:
|
||||||
|
raise HTTPException(
|
||||||
|
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
||||||
|
detail="Failed to unblock domain"
|
||||||
|
)
|
||||||
|
except AdGuardValidationError as e:
|
||||||
|
raise HTTPException(
|
||||||
|
status_code=status.HTTP_400_BAD_REQUEST,
|
||||||
|
detail=str(e)
|
||||||
|
) from e
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"Error unblocking domain: {str(e)}")
|
||||||
|
raise
|
||||||
|
|
||||||
|
|
||||||
@app.exception_handler(AdGuardError)
|
@app.exception_handler(AdGuardError)
|
||||||
async def adguard_exception_handler(_request: Request, exc: AdGuardError) -> JSONResponse:
|
async def adguard_exception_handler(_request: Request, exc: AdGuardError) -> JSONResponse:
|
||||||
"""Handle AdGuard-related exceptions according to spec."""
|
"""Handle AdGuard-related exceptions according to spec."""
|
||||||
|
|||||||
@@ -19,7 +19,7 @@
|
|||||||
// Default configuration
|
// Default configuration
|
||||||
const DEFAULT_CONFIG = {
|
const DEFAULT_CONFIG = {
|
||||||
host: 'http://localhost',
|
host: 'http://localhost',
|
||||||
port: 3000
|
port: 8000
|
||||||
};
|
};
|
||||||
|
|
||||||
// Get current configuration
|
// Get current configuration
|
||||||
@@ -51,6 +51,52 @@
|
|||||||
// Store check results to avoid repeated API calls
|
// Store check results to avoid repeated API calls
|
||||||
const checkedDomains = new Map();
|
const checkedDomains = new Map();
|
||||||
|
|
||||||
|
// 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,
|
||||||
|
timestamp: Date.now()
|
||||||
|
});
|
||||||
|
|
||||||
|
// If blocked, redirect to SimpleGuardHome interface
|
||||||
|
if (isBlocked) {
|
||||||
|
window.location.href = apiUrl;
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('SimpleGuardHome parsing error:', error);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onerror: function(error) {
|
||||||
|
console.error('SimpleGuardHome API error:', error);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
console.error('SimpleGuardHome check error:', error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Intercept 404 responses using a fetch handler
|
// Intercept 404 responses using a fetch handler
|
||||||
const originalFetch = window.fetch;
|
const originalFetch = window.fetch;
|
||||||
window.fetch = async function(...args) {
|
window.fetch = async function(...args) {
|
||||||
@@ -82,116 +128,4 @@
|
|||||||
};
|
};
|
||||||
originalXHROpen.apply(this, [method, url, ...rest]);
|
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