mirror of
https://github.com/billz/raspap-webgui.git
synced 2023-10-10 13:37:24 +02:00
Merge pull request #543 from billz/feature/notracking
Enable ad / tracker blocking with host blocklists
This commit is contained in:
commit
67746601a4
24
ajax/adblock/update_blocklist.php
Normal file
24
ajax/adblock/update_blocklist.php
Normal file
@ -0,0 +1,24 @@
|
||||
<?php
|
||||
|
||||
require '../../includes/csrf.php';
|
||||
require_once '../../includes/config.php';
|
||||
|
||||
if (isset($_POST['blocklist_id'])) {
|
||||
$blocklist_id = $_POST['blocklist_id'];
|
||||
$notracking_url = "https://raw.githubusercontent.com/notracking/hosts-blocklists/master/";
|
||||
|
||||
switch ($blocklist_id) {
|
||||
case "notracking-hostnames":
|
||||
$file = "hostnames.txt";
|
||||
break;
|
||||
case "notracking-domains":
|
||||
$file = "domains.txt";
|
||||
break;
|
||||
}
|
||||
$blocklist = $notracking_url . $file;
|
||||
|
||||
exec("sudo /etc/raspap/adblock/update_blocklist.sh $blocklist $file " .RASPI_ADBLOCK_LISTPATH, $return);
|
||||
$jsonData = ['return'=>$return];
|
||||
echo json_encode($jsonData);
|
||||
}
|
||||
|
@ -221,3 +221,17 @@ canvas#divDBChartBandwidthhourly {
|
||||
.table {
|
||||
margin-bottom: 0rem;
|
||||
}
|
||||
|
||||
.check-hidden {
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
.check-updated {
|
||||
opacity: 0;
|
||||
color: #1cc88a;
|
||||
}
|
||||
|
||||
.check-progress {
|
||||
color: #999;
|
||||
}
|
||||
|
||||
|
@ -245,3 +245,17 @@ canvas#divDBChartBandwidthhourly {
|
||||
.table {
|
||||
margin-bottom: 0rem;
|
||||
}
|
||||
|
||||
.check-hidden {
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
.check-updated {
|
||||
opacity: 0;
|
||||
color: #1cc88a;
|
||||
}
|
||||
|
||||
.check-progress {
|
||||
color: #999;
|
||||
}
|
||||
|
||||
|
@ -434,3 +434,17 @@ canvas#divDBChartBandwidthhourly {
|
||||
.figure, .authors {
|
||||
filter: brightness(70%) !important;
|
||||
}
|
||||
|
||||
.check-hidden {
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
.check-updated {
|
||||
opacity: 0;
|
||||
color: #1cc88a;
|
||||
}
|
||||
|
||||
.check-progress {
|
||||
color: #999;
|
||||
}
|
||||
|
||||
|
@ -291,6 +291,28 @@ function loadChannelSelect(selected) {
|
||||
});
|
||||
}
|
||||
|
||||
/* Updates the selected blocklist
|
||||
* Request is passed to an ajax handler to download the associated list.
|
||||
* Interface elements are updated to indicate current progress, status.
|
||||
*/
|
||||
function updateBlocklist() {
|
||||
var blocklist_id = $('#cbxblocklist').val();
|
||||
if (blocklist_id == '') { return; }
|
||||
$('#cbxblocklist-status').find('i').removeClass('fas fa-check').addClass('fas fa-cog fa-spin');
|
||||
$('#cbxblocklist-status').removeClass('check-hidden').addClass('check-progress');
|
||||
$.post('ajax/adblock/update_blocklist.php',{ 'blocklist_id':blocklist_id },function(data){
|
||||
var jsonData = JSON.parse(data);
|
||||
if (jsonData['return'] == '0') {
|
||||
$('#cbxblocklist-status').find('i').removeClass('fas fa-cog fa-spin').addClass('fas fa-check');
|
||||
$('#cbxblocklist-status').removeClass('check-progress').addClass('check-updated').delay(500).animate({ opacity: 1 }, 700);
|
||||
$('#'+blocklist_id).text("Just now");
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
function clearBlocklistStatus() {
|
||||
$('#cbxblocklist-status').removeClass('check-updated').addClass('check-hidden');
|
||||
}
|
||||
// Static Array method
|
||||
Array.range = (start, end) => Array.from({length: (end - start)}, (v, k) => k + start);
|
||||
|
||||
|
6
config/blocklists.json
Normal file
6
config/blocklists.json
Normal file
@ -0,0 +1,6 @@
|
||||
{
|
||||
"notracking/hosts-blocklist": [
|
||||
"notracking-hostnames",
|
||||
"notracking-domains"
|
||||
]
|
||||
}
|
@ -11,6 +11,8 @@ define('RASPI_CACHE_PATH', sys_get_temp_dir() . '/raspap');
|
||||
// These are typical for default RPi installs. Modify if needed.
|
||||
define('RASPI_DNSMASQ_CONFIG', '/etc/dnsmasq.d/090_raspap.conf');
|
||||
define('RASPI_DNSMASQ_LEASES', '/var/lib/misc/dnsmasq.leases');
|
||||
define('RASPI_ADBLOCK_LISTPATH', '/etc/raspap/adblock/');
|
||||
define('RASPI_ADBLOCK_CONFIG', '/etc/dnsmasq.d/090_adblock.conf');
|
||||
define('RASPI_HOSTAPD_CONFIG', '/etc/hostapd/hostapd.conf');
|
||||
define('RASPI_DHCPCD_CONFIG', '/etc/dhcpcd.conf');
|
||||
define('RASPI_WPA_SUPPLICANT_CONFIG', '/etc/wpa_supplicant/wpa_supplicant.conf');
|
||||
|
60
includes/adblock.php
Normal file
60
includes/adblock.php
Normal file
@ -0,0 +1,60 @@
|
||||
<?php
|
||||
|
||||
require_once 'includes/status_messages.php';
|
||||
require_once 'config.php';
|
||||
|
||||
/**
|
||||
* Manages ad blocking (dnsmasq) configuration
|
||||
*
|
||||
*/
|
||||
function DisplayAdBlockConfig()
|
||||
{
|
||||
$status = new StatusMessages();
|
||||
$enabled = false;
|
||||
|
||||
if (!RASPI_MONITOR_ENABLED) {
|
||||
if (isset($_POST['saveadblocksettings'])) {
|
||||
if ($_POST['adblock-enable'] == "1") {
|
||||
$config = 'conf-file=' .RASPI_ADBLOCK_LISTPATH .'domains.txt'.PHP_EOL;
|
||||
$config.= 'addn-hosts=' .RASPI_ADBLOCK_LISTPATH .'hostnames.txt'.PHP_EOL;
|
||||
} elseif ($_POST['adblock-enable'] == "0") {
|
||||
$config = null;
|
||||
}
|
||||
file_put_contents("/tmp/dnsmasqdata", $config);
|
||||
system('sudo cp /tmp/dnsmasqdata '.RASPI_ADBLOCK_CONFIG, $return);
|
||||
|
||||
if ($return == 0) {
|
||||
$status->addMessage('Adblock configuration updated successfully', 'success');
|
||||
} else {
|
||||
$status->addMessage('Adblock configuration failed to be updated.', 'danger');
|
||||
}
|
||||
} elseif (isset($_POST['restartadblock']) || isset($_POST['startadblock'])) {
|
||||
exec('sudo /bin/systemctl restart dnsmasq.service', $dnsmasq, $return);
|
||||
if ($return == 0) {
|
||||
$status->addMessage('Adblock restart successful', 'success');
|
||||
} else {
|
||||
$status->addMessage('Adblock failed to restart.', 'danger');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
exec('cat '. RASPI_ADBLOCK_CONFIG, $return);
|
||||
$arrConf = ParseConfig($return);
|
||||
if (sizeof($arrConf) > 0) {
|
||||
$enabled = true;
|
||||
}
|
||||
|
||||
exec('pidof dnsmasq | wc -l', $dnsmasq);
|
||||
$dnsmasq_state = ($dnsmasq[0] > 0);
|
||||
$serviceStatus = $dnsmasq_state && $enabled ? "up" : "down";
|
||||
|
||||
echo renderTemplate(
|
||||
"adblock", compact(
|
||||
"status",
|
||||
"serviceStatus",
|
||||
"dnsmasq_state",
|
||||
"enabled"
|
||||
)
|
||||
);
|
||||
}
|
||||
|
@ -15,6 +15,8 @@ $defaults = [
|
||||
// These are typical for default RPi installs. Modify if needed.
|
||||
'RASPI_DNSMASQ_CONFIG' => '/etc/dnsmasq.d/090_raspap.conf',
|
||||
'RASPI_DNSMASQ_LEASES' => '/var/lib/misc/dnsmasq.leases',
|
||||
'RASPI_ADBLOCK_LISTPATH' => '/etc/raspap/adblock/',
|
||||
'RASPI_ADBLOCK_CONFIG' => '/etc/dnsmasq.d/090_adblock.conf',
|
||||
'RASPI_HOSTAPD_CONFIG' => '/etc/hostapd/hostapd.conf',
|
||||
'RASPI_DHCPCD_CONFIG' => '/etc/dhcpcd.conf',
|
||||
'RASPI_WPA_SUPPLICANT_CONFIG' => '/etc/wpa_supplicant/wpa_supplicant.conf',
|
||||
|
@ -352,6 +352,12 @@ function dnsServers()
|
||||
return (array) $data;
|
||||
}
|
||||
|
||||
function blocklistProviders()
|
||||
{
|
||||
$data = json_decode(file_get_contents("./config/blocklists.json"));
|
||||
return (array) $data;
|
||||
}
|
||||
|
||||
function optionsForSelect($options)
|
||||
{
|
||||
$html = "";
|
||||
@ -370,3 +376,44 @@ function optionsForSelect($options)
|
||||
}
|
||||
return $html;
|
||||
}
|
||||
|
||||
function blocklistUpdated($file)
|
||||
{
|
||||
$blocklist = RASPI_CONFIG.'/adblock/'.$file;
|
||||
if (file_exists($blocklist)) {
|
||||
$lastModified = date ("F d Y H:i:s.", filemtime($blocklist));
|
||||
$lastModified = formatDateAgo($lastModified);
|
||||
return $lastModified;
|
||||
} else {
|
||||
return 'Never';
|
||||
}
|
||||
}
|
||||
|
||||
function formatDateAgo($datetime, $full = false)
|
||||
{
|
||||
$now = new DateTime;
|
||||
$ago = new DateTime($datetime);
|
||||
$diff = $now->diff($ago);
|
||||
|
||||
$diff->w = floor($diff->d / 7);
|
||||
$diff->d -= $diff->w * 7;
|
||||
|
||||
$string = array(
|
||||
'y' => 'year',
|
||||
'm' => 'month',
|
||||
'w' => 'week',
|
||||
'd' => 'day',
|
||||
'h' => 'hour',
|
||||
'i' => 'minute',
|
||||
's' => 'second',
|
||||
);
|
||||
foreach ($string as $k => &$v) {
|
||||
if ($diff->$k) {
|
||||
$v = $diff->$k . ' ' . $v . ($diff->$k > 1 ? 's' : '');
|
||||
} else {
|
||||
unset($string[$k]);
|
||||
}
|
||||
}
|
||||
if (!$full) $string = array_slice($string, 0, 1);
|
||||
return $string ? implode(', ', $string) . ' ago' : 'just now';
|
||||
}
|
||||
|
@ -31,6 +31,7 @@ require_once 'includes/authenticate.php';
|
||||
require_once 'includes/admin.php';
|
||||
require_once 'includes/dhcp.php';
|
||||
require_once 'includes/hostapd.php';
|
||||
require_once 'includes/adblock.php';
|
||||
require_once 'includes/system.php';
|
||||
require_once 'includes/sysstats.php';
|
||||
require_once 'includes/configure_client.php';
|
||||
@ -137,6 +138,11 @@ $bridgedEnabled = $arrHostapdConf['BridgedEnable'];
|
||||
<?php if (RASPI_DHCP_ENABLED && !$bridgedEnabled) : ?>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="index.php?page=dhcpd_conf"><i class="fas fa-exchange-alt fa-fw mr-2"></i><span class="nav-label"><?php echo _("DHCP Server"); ?></a>
|
||||
</li>
|
||||
<?php endif; ?>
|
||||
<?php if (RASPI_ADBLOCK_ENABLED) : ?>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="index.php?page=adblock_conf"><i class="far fa-hand-paper fa-fw mr-2"></i><span class="nav-label"><?php echo _("Ad Blocking"); ?></a>
|
||||
</li>
|
||||
<?php endif; ?>
|
||||
<?php if (RASPI_NETWORK_ENABLED) : ?>
|
||||
@ -239,6 +245,9 @@ $bridgedEnabled = $arrHostapdConf['BridgedEnable'];
|
||||
case "hostapd_conf":
|
||||
DisplayHostAPDConfig();
|
||||
break;
|
||||
case "adblock_conf":
|
||||
DisplayAdBlockConfig();
|
||||
break;
|
||||
case "openvpn_conf":
|
||||
DisplayOpenVPNConfig();
|
||||
break;
|
||||
|
21
installers/update_blocklist.sh
Executable file
21
installers/update_blocklist.sh
Executable file
@ -0,0 +1,21 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
#
|
||||
# @author billz
|
||||
# license: GNU General Public License v3.0
|
||||
|
||||
# Exit on error
|
||||
set -o errexit
|
||||
# Exit on error inside functions
|
||||
set -o errtrace
|
||||
# Turn on traces, disabled by default
|
||||
#set -o xtrace
|
||||
|
||||
update_url=$1
|
||||
file=$2
|
||||
destination=$3
|
||||
|
||||
wget -q ${update_url} -O ${destination}${file} &> /dev/null
|
||||
|
||||
echo "$?"
|
||||
|
Binary file not shown.
@ -10,7 +10,7 @@ msgstr ""
|
||||
"Project-Id-Version: 1.2.1\n"
|
||||
"Report-Msgid-Bugs-To: Bill Zimmerman <billzimmerman@gmail.com>\n"
|
||||
"POT-Creation-Date: 2017-10-19 08:56+0000\n"
|
||||
"PO-Revision-Date: 2018-05-17 17:15+0000\n"
|
||||
"PO-Revision-Date: 2020-03-29 00:05+0000\n"
|
||||
"Last-Translator: Bill Zimmerman <billzimmerman@gmail.com>\n"
|
||||
"Language-Team: \n"
|
||||
"Language: en_US\n"
|
||||
@ -318,7 +318,7 @@ msgid "Dnsmasq is running"
|
||||
msgstr "Dnsmasq is running"
|
||||
|
||||
msgid "Dnsmasq is not running"
|
||||
msgstr "Dnsmasq is not running
|
||||
msgstr "Dnsmasq is not running"
|
||||
|
||||
msgid "Upstream DNS servers"
|
||||
msgstr "Upstream DNS servers"
|
||||
@ -688,3 +688,42 @@ msgstr "up"
|
||||
|
||||
msgid "down"
|
||||
msgstr "down"
|
||||
|
||||
#: includes/adblock.php
|
||||
|
||||
msgid "adblock"
|
||||
msgstr "adblock"
|
||||
|
||||
msgid "Ad Blocking"
|
||||
msgstr "Ad Blocking"
|
||||
|
||||
msgid "Start Ad Blocking"
|
||||
msgstr "Start Ad Blocking"
|
||||
|
||||
msgid "Restart Ad Blocking"
|
||||
msgstr "Restart Ad Blocking"
|
||||
|
||||
msgid "Blocklist settings"
|
||||
msgstr "Blocklist settings"
|
||||
|
||||
msgid "Enable blocklists"
|
||||
msgstr "Enable blocklists"
|
||||
|
||||
msgid "Enable this option if you want RaspAP to <b>block DNS requests for ads, tracking and other virtual garbage</b>. Blocklists are gathered from multiple, actively maintained sources and automatically updated, cleaned, optimized and moderated on a daily basis."
|
||||
msgstr "Enable this option if you want RaspAP to <b>block DNS requests for ads, tracking and other virtual garbage</b>. Blocklists are gathered from multiple, actively maintained sources and automatically updated, cleaned, optimized and moderated on a daily basis."
|
||||
|
||||
msgid "This option adds <code>conf-file</code> and <code>addn-hosts</code> to the dnsmasq configuration."
|
||||
msgstr "This option adds <code>conf-file</code> and <code>addn-hosts</code> to the dnsmasq configuration."
|
||||
|
||||
msgid "Choose a blocklist provider"
|
||||
msgstr "Choose a blocklist provider"
|
||||
|
||||
msgid "Update now"
|
||||
msgstr "Update now"
|
||||
|
||||
msgid "Statistics"
|
||||
msgstr "Statistics"
|
||||
|
||||
msgid "Information provided by adblock"
|
||||
msgstr "Information provided by adblock"
|
||||
|
||||
|
52
templates/adblock.php
Executable file
52
templates/adblock.php
Executable file
@ -0,0 +1,52 @@
|
||||
<?php ob_start() ?>
|
||||
<?php if (!RASPI_MONITOR_ENABLED) : ?>
|
||||
<input type="submit" class="btn btn-outline btn-primary" name="saveadblocksettings" value="<?php echo _("Save settings"); ?>">
|
||||
<?php if ($dnsmasq_state) : ?>
|
||||
<input type="submit" class="btn btn-warning" name="restartadblock" value="<?php echo _("Restart Ad Blocking"); ?>">
|
||||
<?php else : ?>
|
||||
<input type="submit" class="btn btn-success" name="startadblock" value="<?php echo _("Start Ad Blocking"); ?>">
|
||||
<?php endif ?>
|
||||
<?php endif ?>
|
||||
<?php $buttons = ob_get_clean(); ob_end_clean() ?>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-lg-12">
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<i class="far fa-hand-paper mr-2"></i><?php echo _("Ad Blocking"); ?>
|
||||
</div>
|
||||
<div class="col">
|
||||
<button class="btn btn-light btn-icon-split btn-sm service-status float-right">
|
||||
<span class="icon text-gray-600"><i class="fas fa-circle service-status-<?php echo $serviceStatus ?>"></i></span>
|
||||
<span class="text service-status">adblock <?php echo _($serviceStatus) ?></span>
|
||||
</button>
|
||||
</div>
|
||||
</div><!-- /.row -->
|
||||
</div><!-- /.card-header -->
|
||||
<div class="card-body">
|
||||
<?php $status->showMessages(); ?>
|
||||
<form role="form" action="?page=adblock_conf" enctype="multipart/form-data" method="POST">
|
||||
<?php echo CSRFTokenFieldTag() ?>
|
||||
<!-- Nav tabs -->
|
||||
<ul class="nav nav-tabs">
|
||||
<li class="nav-item"><a class="nav-link active" id="clienttab" href="#adblocklistsettings" data-toggle="tab"><?php echo _("Blocklist settings"); ?></a></li>
|
||||
<li class="nav-item"><a class="nav-link" id="logoutputtab" href="#adblocklogfileoutput" data-toggle="tab"><?php echo _("Logging"); ?></a></li>
|
||||
</ul>
|
||||
|
||||
<!-- Tab panes -->
|
||||
<div class="tab-content">
|
||||
<?php echo renderTemplate("adblock/general", $__template_data) ?>
|
||||
<?php echo renderTemplate("adblock/stats", $__template_data) ?>
|
||||
<?php echo renderTemplate("adblock/logging", $__template_data) ?>
|
||||
</div><!-- /.tab-content -->
|
||||
|
||||
<?php echo $buttons ?>
|
||||
</form>
|
||||
</div><!-- /.card-body -->
|
||||
<div class="card-footer"><?php echo _("Information provided by adblock"); ?></div>
|
||||
</div><!-- /.card -->
|
||||
</div><!-- /.col-lg-12 -->
|
||||
</div><!-- /.row -->
|
||||
|
43
templates/adblock/general.php
Normal file
43
templates/adblock/general.php
Normal file
@ -0,0 +1,43 @@
|
||||
<!-- blocklist settings tab -->
|
||||
<div class="tab-pane active" id="adblocklistsettings">
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
<h4 class="mt-3"><?php echo _("Blocklist settings"); ?></h4>
|
||||
<div class="input-group">
|
||||
<input type="hidden" name="adblock-enable" value="0">
|
||||
<div class="custom-control custom-switch">
|
||||
<input class="custom-control-input" id="adblock-enable" type="checkbox" name="adblock-enable" value="1" <?php echo $enabled ? ' checked="checked"' : "" ?> aria-describedby="adblock-description">
|
||||
<label class="custom-control-label" for="adblock-enable"><?php echo _("Enable blocklists") ?></label>
|
||||
</div>
|
||||
<p id="adblock-description">
|
||||
<small><?php echo _("Enable this option if you want RaspAP to <b>block DNS requests for ads, tracking and other virtual garbage</b>. Blocklists are gathered from multiple, actively maintained sources and automatically updated, cleaned, optimized and moderated on a daily basis.") ?></small>
|
||||
<div>
|
||||
<small class="text-muted"><?php echo _("This option adds <code>conf-file</code> and <code>addn-hosts</code> to the dnsmasq configuration.") ?></small>
|
||||
</div>
|
||||
</p>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<p id="blocklist-updated">
|
||||
<div><small><?php echo _("Hostnames blocklist last updated") ?>: <span class="font-weight-bold" id="notracking-hostnames">
|
||||
<?php echo blocklistUpdated('hostnames.txt') ?></span></small></div>
|
||||
<div><small><?php echo _("Domains blocklist last updated") ?>: <span class="font-weight-bold" id="notracking-domains">
|
||||
<?php echo blocklistUpdated('domains.txt') ?></b></small></div>
|
||||
</p>
|
||||
<div class="input-group col-md-12 mb-4">
|
||||
<select class="custom-select custom-select-sm" id="cbxblocklist" onchange="clearBlocklistStatus()">
|
||||
<option value=""><?php echo _("Choose a blocklist provider") ?></option>
|
||||
<option disabled="disabled"></option>
|
||||
<?php echo optionsForSelect(blocklistProviders()) ?>
|
||||
</select>
|
||||
<div class="input-group-append">
|
||||
<button class="btn btn-sm btn-outline-secondary rounded-right" type="button" onclick="updateBlocklist()"><?php echo _("Update now"); ?></button>
|
||||
<span id="cbxblocklist-status" class="input-group-addon check-hidden ml-2 mt-1"><i class="fas fa-check"></i></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div><!-- /.row -->
|
||||
</div><!-- /.tab-pane | advanded tab -->
|
||||
|
25
templates/adblock/logging.php
Normal file
25
templates/adblock/logging.php
Normal file
@ -0,0 +1,25 @@
|
||||
<!-- logging tab -->
|
||||
<div class="tab-pane fade" id="adblocklogfileoutput">
|
||||
<h4 class="mt-3"><?php echo _("Logging"); ?></h4>
|
||||
<div class="row">
|
||||
<div class="form-group col-md-8">
|
||||
<?php
|
||||
$log = '';
|
||||
exec('sudo chmod o+r /tmp/dnsmasq.log');
|
||||
$handle = fopen("/tmp/dnsmasq.log", "r");
|
||||
if ($handle) {
|
||||
while (($line = fgets($handle)) !== false) {
|
||||
if (preg_match('/(0.0.0.0)/', $line)){
|
||||
$log.=$line;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$log = "Unable to open log file";
|
||||
}
|
||||
fclose($handle);
|
||||
echo '<textarea class="logoutput">'.htmlspecialchars($log, ENT_QUOTES).'</textarea>';
|
||||
?>
|
||||
</div>
|
||||
</div>
|
||||
</div><!-- /.tab-pane -->
|
||||
|
15
templates/adblock/stats.php
Normal file
15
templates/adblock/stats.php
Normal file
@ -0,0 +1,15 @@
|
||||
<!-- statistics tab -->
|
||||
<div class="tab-pane fade" id="adblockstats">
|
||||
<h4 class="mt-3"><?php echo _("Statistics"); ?></h4>
|
||||
<div class="row">
|
||||
<div class="form-group col-md-8">
|
||||
<?php
|
||||
/*
|
||||
* BZ todo: implement basic stats
|
||||
*
|
||||
*/
|
||||
?>
|
||||
</div>
|
||||
</div>
|
||||
</div><!-- /.tab-pane -->
|
||||
|
Loading…
Reference in New Issue
Block a user