Merge branch 'release/v5.0' into devel

Signed-off-by: DL6ER <dl6er@dl6er.de>
This commit is contained in:
DL6ER
2020-04-08 12:19:09 +02:00
45 changed files with 1476 additions and 1416 deletions

View File

@@ -16,22 +16,38 @@ if (empty($api)) {
list_verify($list);
}
// Split individual domains into array
$domains = preg_split('/\s+/', trim($_POST['domain']));
// Get comment if available
$comment = null;
if(isset($_POST['comment'])) {
$comment = trim($_POST['comment']);
}
// Convert domain name to IDNA ASCII form for international domains
// Do this only for exact domains, not for regex filters
// Only do it when the php-intl extension is available
if (extension_loaded("intl") && ($list === "white" || $list === "black")) {
foreach($domains as &$domain)
{
$domain = idn_to_ascii($domain);
}
}
// Only check domains we add to the exact lists.
// Regex are validated by FTL during import
$check_lists = ["white","black","audit"];
if(in_array($list, $check_lists)) {
check_domain();
check_domain($domains);
}
// Split individual domains into array
$domains = preg_split('/\s+/', trim($_POST['domain']));
$comment = trim($_POST['comment']);
require_once("func.php");
require_once("database.php");
$GRAVITYDB = getGravityDBFilename();
$db = SQLite3_connect($GRAVITYDB, SQLITE3_OPEN_READWRITE);
$reload = true;
switch($list) {
case "white":
$domains = array_map('strtolower', $domains);
@@ -60,7 +76,8 @@ switch($list) {
break;
case "audit":
echo add_to_table($db, "domain_audit", $domains, $comment);
$reload = false;
echo add_to_table($db, "domain_audit", $domains);
break;
default:
@@ -68,5 +85,8 @@ switch($list) {
}
// Reload lists in pihole-FTL after having added something
echo shell_exec("sudo pihole restartdns reload");
if ($reload) {
echo shell_exec("sudo pihole restartdns reload-lists");
}
?>

View File

@@ -113,15 +113,12 @@ function check_csrf($token) {
}
}
function check_domain() {
if(isset($_POST['domain'])){
$domains = preg_split('/\s+/', $_POST['domain']);
foreach($domains as $domain)
{
$validDomain = is_valid_domain_name($domain);
if(!$validDomain){
log_and_die(htmlspecialchars($domain. ' is not a valid domain'));
}
function check_domain(&$domains) {
foreach($domains as &$domain)
{
$validDomain = is_valid_domain_name($domain);
if(!$validDomain){
log_and_die(htmlspecialchars($domain. ' is not a valid domain'));
}
}
}

View File

@@ -91,7 +91,7 @@ function SQLite3_connect($filename, $mode=SQLITE3_OPEN_READONLY)
* @param $type integer The target type (0 = exact whitelist, 1 = exact blacklist, 2 = regex whitelist, 3 = regex blacklist)
* @return string Success/error and number of processed domains
*/
function add_to_table($db, $table, $domains, $comment, $wildcardstyle=false, $returnnum=false, $type=-1)
function add_to_table($db, $table, $domains, $comment=null, $wildcardstyle=false, $returnnum=false, $type=-1)
{
if(!is_int($type))
{
@@ -107,6 +107,16 @@ function add_to_table($db, $table, $domains, $comment, $wildcardstyle=false, $re
return "Error: Unable to begin transaction for $table table.";
}
// To which column should the record be added to?
if ($table === "adlist")
{
$field = "address";
}
else
{
$field = "domain";
}
// Get initial count of domains in this table
if($type === -1)
{
@@ -119,13 +129,15 @@ function add_to_table($db, $table, $domains, $comment, $wildcardstyle=false, $re
$initialcount = intval($db->querySingle($countquery));
// Prepare INSERT SQLite statememt
if($type === -1)
{
$querystr = "INSERT OR IGNORE INTO $table (domain,comment) VALUES (:domain, :comment);";
}
else
{
$querystr = "INSERT OR IGNORE INTO $table (domain,comment,type) VALUES (:domain, :comment, $type);";
$bindcomment = false;
if($table === "domain_audit") {
$querystr = "INSERT OR IGNORE INTO $table ($field) VALUES (:$field);";
} elseif($type === -1) {
$querystr = "INSERT OR IGNORE INTO $table ($field,comment) VALUES (:$field, :comment);";
$bindcomment = true;
} else {
$querystr = "INSERT OR IGNORE INTO $table ($field,comment,type) VALUES (:$field, :comment, $type);";
$bindcomment = true;
}
$stmt = $db->prepare($querystr);
@@ -135,7 +147,7 @@ function add_to_table($db, $table, $domains, $comment, $wildcardstyle=false, $re
if($returnnum)
return 0;
else
return "Error: Failed to prepare statement for $table table (type = $type).";
return "Error: Failed to prepare statement for $table table (type = $type, field = $field).";
}
// Loop over domains and inject the lines into the database
@@ -149,8 +161,10 @@ function add_to_table($db, $table, $domains, $comment, $wildcardstyle=false, $re
if($wildcardstyle)
$domain = "(\\.|^)".str_replace(".","\\.",$domain)."$";
$stmt->bindValue(":domain", $domain, SQLITE3_TEXT);
$stmt->bindValue(":comment", $comment, SQLITE3_TEXT);
$stmt->bindValue(":$field", $domain, SQLITE3_TEXT);
if($bindcomment) {
$stmt->bindValue(":comment", $comment, SQLITE3_TEXT);
}
if($stmt->execute() && $stmt->reset())
$num++;

View File

@@ -1,78 +0,0 @@
<?php
/* Pi-hole: A black hole for Internet advertisements
* (c) 2017 Pi-hole, LLC (https://pi-hole.net)
* Network-wide ad blocking via your own hardware.
*
* This file is copyright under the latest version of the EUPL.
* Please see LICENSE file for your rights under this license. */
if(!isset($_GET['list']))
die("Missing parameter");
$listtype = $_GET['list'];
require_once("func.php");
require("database.php");
$GRAVITYDB = getGravityDBFilename();
$db = SQLite3_connect($GRAVITYDB);
function getTableContent($type) {
global $db;
$entries = array();
$querystr = implode(" ",array("SELECT domainlist.*,\"group\".enabled as group_enabled",
"FROM domainlist",
"LEFT JOIN domainlist_by_group ON domainlist_by_group.domainlist_id = domainlist.id",
"LEFT JOIN \"group\" ON \"group\".id = domainlist_by_group.group_id",
"WHERE type = $type",
"GROUP BY domain;"));
$results = $db->query($querystr);
while($results !== false && $res = $results->fetchArray(SQLITE3_ASSOC))
{
array_push($entries, $res);
}
return $entries;
}
function filterArray(&$inArray) {
$outArray = array();
foreach ($inArray as $key => $value)
{
if (is_array($value))
{
$outArray[htmlspecialchars($key)] = filterArray($value);
}
else
{
$outArray[htmlspecialchars($key)] = htmlspecialchars($value);
}
}
return $outArray;
}
switch ($listtype)
{
case "white":
$exact = array("whitelist" => getTableContent(ListType::whitelist));
$regex = array("regex_whitelist" => getTableContent(ListType::regex_whitelist));
$list = array_merge($exact, $regex);
break;
case "black":
$exact = array("blacklist" => getTableContent(ListType::blacklist));
$regex = array("regex_blacklist" => getTableContent(ListType::regex_blacklist));
$list = array_merge($exact, $regex);
break;
default:
die("Invalid list parameter");
break;
}
// Protect against XSS attacks
$output = filterArray($list);
// Return results
header('Content-type: application/json');
echo json_encode($output);

View File

@@ -49,32 +49,35 @@ if ($_POST['action'] == 'get_groups') {
}
echo json_encode(array('data' => $data));
} catch (\Exception $ex) {
return JSON_error($ex->getMessage());
JSON_error($ex->getMessage());
}
} elseif ($_POST['action'] == 'add_group') {
// Add new group
try {
$names = explode(' ', $_POST['name']);
$stmt = $db->prepare('INSERT INTO "group" (name,description) VALUES (:name,:desc)');
if (!$stmt) {
throw new Exception('While preparing statement: ' . $db->lastErrorMsg());
}
if (!$stmt->bindValue(':name', $_POST['name'], SQLITE3_TEXT)) {
throw new Exception('While binding name: ' . $db->lastErrorMsg());
}
if (!$stmt->bindValue(':desc', $_POST['desc'], SQLITE3_TEXT)) {
throw new Exception('While binding desc: ' . $db->lastErrorMsg());
}
if (!$stmt->execute()) {
throw new Exception('While executing: ' . $db->lastErrorMsg());
foreach ($names as $name) {
if (!$stmt->bindValue(':name', $name, SQLITE3_TEXT)) {
throw new Exception('While binding name: ' . $db->lastErrorMsg());
}
if (!$stmt->execute()) {
throw new Exception('While executing: ' . $db->lastErrorMsg());
}
}
$reload = true;
return JSON_success();
JSON_success();
} catch (\Exception $ex) {
return JSON_error($ex->getMessage());
JSON_error($ex->getMessage());
}
} elseif ($_POST['action'] == 'edit_group') {
// Edit group identified by ID
@@ -111,9 +114,9 @@ if ($_POST['action'] == 'get_groups') {
}
$reload = true;
return JSON_success();
JSON_success();
} catch (\Exception $ex) {
return JSON_error($ex->getMessage());
JSON_error($ex->getMessage());
}
} elseif ($_POST['action'] == 'delete_group') {
// Delete group identified by ID
@@ -142,9 +145,9 @@ if ($_POST['action'] == 'get_groups') {
}
}
$reload = true;
return JSON_success();
JSON_success();
} catch (\Exception $ex) {
return JSON_error($ex->getMessage());
JSON_error($ex->getMessage());
}
} elseif ($_POST['action'] == 'get_clients') {
// List all available groups
@@ -157,7 +160,6 @@ if ($_POST['action'] == 'get_groups') {
throw new Exception('Error while querying gravity\'s client table: ' . $db->lastErrorMsg());
}
$data = array();
while (($res = $query->fetchArray(SQLITE3_ASSOC)) !== false) {
$group_query = $db->query('SELECT group_id FROM client_by_group WHERE client_id = ' . $res['id'] . ';');
@@ -182,7 +184,7 @@ if ($_POST['action'] == 'get_groups') {
// There will always be a result. Unknown host names are NULL
$name_result = $result->fetchArray(SQLITE3_ASSOC);
$res['name'] = $name_result['name'];
$groups = array();
while ($gres = $group_query->fetchArray(SQLITE3_ASSOC)) {
array_push($groups, $gres['group_id']);
@@ -193,7 +195,7 @@ if ($_POST['action'] == 'get_groups') {
echo json_encode(array('data' => $data));
} catch (\Exception $ex) {
return JSON_error($ex->getMessage());
JSON_error($ex->getMessage());
}
} elseif ($_POST['action'] == 'get_unconfigured_clients') {
// List all available clients WITHOUT already configured clients
@@ -209,7 +211,7 @@ if ($_POST['action'] == 'get_groups') {
// Loop over results
$ips = array();
while ($res = $query->fetchArray(SQLITE3_ASSOC)) {
$ips[$res['ip']] = $res['name'];
$ips[$res['ip']] = $res['name'] !== null ? $res['name'] : '';
}
$FTLdb->close();
@@ -227,32 +229,66 @@ if ($_POST['action'] == 'get_groups') {
echo json_encode($ips);
} catch (\Exception $ex) {
return JSON_error($ex->getMessage());
JSON_error($ex->getMessage());
}
} elseif ($_POST['action'] == 'add_client') {
// Add new client
try {
$stmt = $db->prepare('INSERT INTO client (ip) VALUES (:ip)');
$ips = explode(' ', $_POST['ip']);
$stmt = $db->prepare('INSERT INTO client (ip,comment) VALUES (:ip,:comment)');
if (!$stmt) {
throw new Exception('While preparing statement: ' . $db->lastErrorMsg());
}
if (!$stmt->bindValue(':ip', $_POST['ip'], SQLITE3_TEXT)) {
throw new Exception('While binding ip: ' . $db->lastErrorMsg());
foreach ($ips as $ip) {
if (!$stmt->bindValue(':ip', $ip, SQLITE3_TEXT)) {
throw new Exception('While binding ip: ' . $db->lastErrorMsg());
}
$comment = $_POST['comment'];
if (strlen($comment) == 0) {
// Store NULL in database for empty comments
$comment = null;
}
if (!$stmt->bindValue(':comment', $comment, SQLITE3_TEXT)) {
throw new Exception('While binding comment: ' . $db->lastErrorMsg());
}
if (!$stmt->execute()) {
throw new Exception('While executing: ' . $db->lastErrorMsg());
}
}
$reload = true;
JSON_success();
} catch (\Exception $ex) {
JSON_error($ex->getMessage());
}
} elseif ($_POST['action'] == 'edit_client') {
// Edit client identified by ID
try {
$stmt = $db->prepare('UPDATE client SET comment=:comment WHERE id = :id');
if (!$stmt) {
throw new Exception('While preparing statement: ' . $db->lastErrorMsg());
}
$comment = $_POST['comment'];
if (strlen($comment) == 0) {
// Store NULL in database for empty comments
$comment = null;
}
if (!$stmt->bindValue(':comment', $comment, SQLITE3_TEXT)) {
throw new Exception('While binding comment: ' . $db->lastErrorMsg());
}
if (!$stmt->bindValue(':id', intval($_POST['id']), SQLITE3_INTEGER)) {
throw new Exception('While binding id: ' . $db->lastErrorMsg());
}
if (!$stmt->execute()) {
throw new Exception('While executing: ' . $db->lastErrorMsg());
}
$reload = true;
return JSON_success();
} catch (\Exception $ex) {
return JSON_error($ex->getMessage());
}
} elseif ($_POST['action'] == 'edit_client') {
// Edit client identified by ID
try {
$stmt = $db->prepare('DELETE FROM client_by_group WHERE client_id = :id');
if (!$stmt) {
throw new Exception('While preparing DELETE statement: ' . $db->lastErrorMsg());
@@ -265,22 +301,22 @@ if ($_POST['action'] == 'get_groups') {
if (!$stmt->execute()) {
throw new Exception('While executing DELETE statement: ' . $db->lastErrorMsg());
}
$db->query('BEGIN TRANSACTION;');
foreach ($_POST['groups'] as $gid) {
$stmt = $db->prepare('INSERT INTO client_by_group (client_id,group_id) VALUES(:id,:gid);');
if (!$stmt) {
throw new Exception('While preparing INSERT INTO statement: ' . $db->lastErrorMsg());
}
if (!$stmt->bindValue(':id', intval($_POST['id']), SQLITE3_INTEGER)) {
throw new Exception('While binding id: ' . $db->lastErrorMsg());
}
if (!$stmt->bindValue(':gid', intval($gid), SQLITE3_INTEGER)) {
throw new Exception('While binding gid: ' . $db->lastErrorMsg());
}
if (!$stmt->execute()) {
throw new Exception('While executing INSERT INTO statement: ' . $db->lastErrorMsg());
}
@@ -288,9 +324,9 @@ if ($_POST['action'] == 'get_groups') {
$db->query('COMMIT;');
$reload = true;
return JSON_success();
JSON_success();
} catch (\Exception $ex) {
return JSON_error($ex->getMessage());
JSON_error($ex->getMessage());
}
} elseif ($_POST['action'] == 'delete_client') {
// Delete client identified by ID
@@ -322,14 +358,20 @@ if ($_POST['action'] == 'get_groups') {
}
$reload = true;
return JSON_success();
JSON_success();
} catch (\Exception $ex) {
return JSON_error($ex->getMessage());
JSON_error($ex->getMessage());
}
} elseif ($_POST['action'] == 'get_domains') {
// List all available groups
try {
$query = $db->query('SELECT * FROM domainlist;');
$limit = "";
if (isset($_POST["showtype"]) && $_POST["showtype"] === "white"){
$limit = " WHERE type = 0 OR type = 2";
} elseif (isset($_POST["showtype"]) && $_POST["showtype"] === "black"){
$limit = " WHERE type = 1 OR type = 3";
}
$query = $db->query('SELECT * FROM domainlist'.$limit);
if (!$query) {
throw new Exception('Error while querying gravity\'s domainlist table: ' . $db->lastErrorMsg());
}
@@ -340,23 +382,35 @@ if ($_POST['action'] == 'get_groups') {
if (!$group_query) {
throw new Exception('Error while querying gravity\'s domainlist_by_group table: ' . $db->lastErrorMsg());
}
$groups = array();
while ($gres = $group_query->fetchArray(SQLITE3_ASSOC)) {
array_push($groups, $gres['group_id']);
}
$res['groups'] = $groups;
if (extension_loaded("intl") &&
($res['type'] === ListType::whitelist ||
$res['type'] === ListType::blacklist) ) {
$utf8_domain = idn_to_utf8($res['domain']);
// Convert domain name to international form
// if applicable and extension is available
if($res['domain'] !== $utf8_domain)
{
$res['domain'] = $utf8_domain.' ('.$res['domain'].')';
}
}
array_push($data, $res);
}
echo json_encode(array('data' => $data));
} catch (\Exception $ex) {
return JSON_error($ex->getMessage());
JSON_error($ex->getMessage());
}
} elseif ($_POST['action'] == 'add_domain') {
// Add new domain
try {
$domains = explode(' ', $_POST['domain']);
$stmt = $db->prepare('INSERT INTO domainlist (domain,type,comment) VALUES (:domain,:type,:comment)');
if (!$stmt) {
throw new Exception('While preparing statement: ' . $db->lastErrorMsg());
@@ -364,21 +418,6 @@ if ($_POST['action'] == 'get_groups') {
$type = intval($_POST['type']);
$domain = $_POST['domain'];
if($type === ListType::whitelist || $type === ListType::blacklist)
{
// If adding to the exact lists, we convert the domain lower case and check whether it is valid
$domain = strtolower($domain);
if(filter_var($domain, FILTER_VALIDATE_DOMAIN, FILTER_FLAG_HOSTNAME) === false)
{
throw new Exception('Domain ' . htmlentities(utf8_encode($domain)) . 'is not a valid domain.');
}
}
if (!$stmt->bindValue(':domain', $domain, SQLITE3_TEXT)) {
throw new Exception('While binding domain: ' . $db->lastErrorMsg());
}
if (!$stmt->bindValue(':type', $type, SQLITE3_TEXT)) {
throw new Exception('While binding type: ' . $db->lastErrorMsg());
}
@@ -387,14 +426,39 @@ if ($_POST['action'] == 'get_groups') {
throw new Exception('While binding comment: ' . $db->lastErrorMsg());
}
if (!$stmt->execute()) {
throw new Exception('While executing: ' . $db->lastErrorMsg());
foreach ($domains as $domain) {
// Convert domain name to IDNA ASCII form for international domains
$domain = idn_to_ascii($domain);
if(strlen($_POST['type']) === 2 && $_POST['type'][1] === 'W')
{
// Apply wildcard-style formatting
$domain = "(\\.|^)".str_replace(".","\\.",$domain)."$";
}
if($type === ListType::whitelist || $type === ListType::blacklist)
{
// If adding to the exact lists, we convert the domain lower case and check whether it is valid
$domain = strtolower($domain);
if(filter_var($domain, FILTER_VALIDATE_DOMAIN, FILTER_FLAG_HOSTNAME) === false)
{
throw new Exception('Domain ' . htmlentities(utf8_encode($domain)) . 'is not a valid domain.');
}
}
if (!$stmt->bindValue(':domain', $domain, SQLITE3_TEXT)) {
throw new Exception('While binding domain: ' . $db->lastErrorMsg());
}
if (!$stmt->execute()) {
throw new Exception('While executing: ' . $db->lastErrorMsg());
}
}
$reload = true;
return JSON_success();
JSON_success();
} catch (\Exception $ex) {
return JSON_error($ex->getMessage());
JSON_error($ex->getMessage());
}
} elseif ($_POST['action'] == 'edit_domain') {
// Edit domain identified by ID
@@ -434,44 +498,46 @@ if ($_POST['action'] == 'get_groups') {
throw new Exception('While executing: ' . $db->lastErrorMsg());
}
$stmt = $db->prepare('DELETE FROM domainlist_by_group WHERE domainlist_id = :id');
if (!$stmt) {
throw new Exception('While preparing DELETE statement: ' . $db->lastErrorMsg());
}
if (!$stmt->bindValue(':id', intval($_POST['id']), SQLITE3_INTEGER)) {
throw new Exception('While binding id: ' . $db->lastErrorMsg());
}
if (!$stmt->execute()) {
throw new Exception('While executing DELETE statement: ' . $db->lastErrorMsg());
}
$db->query('BEGIN TRANSACTION;');
foreach ($_POST['groups'] as $gid) {
$stmt = $db->prepare('INSERT INTO domainlist_by_group (domainlist_id,group_id) VALUES(:id,:gid);');
if (isset($_POST['groups'])) {
$stmt = $db->prepare('DELETE FROM domainlist_by_group WHERE domainlist_id = :id');
if (!$stmt) {
throw new Exception('While preparing INSERT INTO statement: ' . $db->lastErrorMsg());
throw new Exception('While preparing DELETE statement: ' . $db->lastErrorMsg());
}
if (!$stmt->bindValue(':id', intval($_POST['id']), SQLITE3_INTEGER)) {
throw new Exception('While binding id: ' . $db->lastErrorMsg());
}
if (!$stmt->bindValue(':gid', intval($gid), SQLITE3_INTEGER)) {
throw new Exception('While binding gid: ' . $db->lastErrorMsg());
}
if (!$stmt->execute()) {
throw new Exception('While executing INSERT INTO statement: ' . $db->lastErrorMsg());
throw new Exception('While executing DELETE statement: ' . $db->lastErrorMsg());
}
$db->query('BEGIN TRANSACTION;');
foreach ($_POST['groups'] as $gid) {
$stmt = $db->prepare('INSERT INTO domainlist_by_group (domainlist_id,group_id) VALUES(:id,:gid);');
if (!$stmt) {
throw new Exception('While preparing INSERT INTO statement: ' . $db->lastErrorMsg());
}
if (!$stmt->bindValue(':id', intval($_POST['id']), SQLITE3_INTEGER)) {
throw new Exception('While binding id: ' . $db->lastErrorMsg());
}
if (!$stmt->bindValue(':gid', intval($gid), SQLITE3_INTEGER)) {
throw new Exception('While binding gid: ' . $db->lastErrorMsg());
}
if (!$stmt->execute()) {
throw new Exception('While executing INSERT INTO statement: ' . $db->lastErrorMsg());
}
}
$db->query('COMMIT;');
}
$db->query('COMMIT;');
$reload = true;
return JSON_success();
JSON_success();
} catch (\Exception $ex) {
return JSON_error($ex->getMessage());
JSON_error($ex->getMessage());
}
} elseif ($_POST['action'] == 'delete_domain') {
// Delete domain identified by ID
@@ -503,9 +569,9 @@ if ($_POST['action'] == 'get_groups') {
}
$reload = true;
return JSON_success();
JSON_success();
} catch (\Exception $ex) {
return JSON_error($ex->getMessage());
JSON_error($ex->getMessage());
}
} elseif ($_POST['action'] == 'get_adlists') {
// List all available groups
@@ -521,7 +587,7 @@ if ($_POST['action'] == 'get_groups') {
if (!$group_query) {
throw new Exception('Error while querying gravity\'s adlist_by_group table: ' . $db->lastErrorMsg());
}
$groups = array();
while ($gres = $group_query->fetchArray(SQLITE3_ASSOC)) {
array_push($groups, $gres['group_id']);
@@ -533,32 +599,40 @@ if ($_POST['action'] == 'get_groups') {
echo json_encode(array('data' => $data));
} catch (\Exception $ex) {
return JSON_error($ex->getMessage());
JSON_error($ex->getMessage());
}
} elseif ($_POST['action'] == 'add_adlist') {
// Add new adlist
try {
$addresses = explode(' ', $_POST['address']);
$stmt = $db->prepare('INSERT INTO adlist (address,comment) VALUES (:address,:comment)');
if (!$stmt) {
throw new Exception('While preparing statement: ' . $db->lastErrorMsg());
}
if (!$stmt->bindValue(':address', $_POST['address'], SQLITE3_TEXT)) {
throw new Exception('While binding address: ' . $db->lastErrorMsg());
}
if (!$stmt->bindValue(':comment', $_POST['comment'], SQLITE3_TEXT)) {
throw new Exception('While binding comment: ' . $db->lastErrorMsg());
}
if (!$stmt->execute()) {
throw new Exception('While executing: ' . $db->lastErrorMsg());
foreach ($addresses as $address) {
if(preg_match("/[^a-zA-Z0-9:\/?&%=~._-]/", $address) !== 0) {
throw new Exception('Invalid adlist URL');
}
if (!$stmt->bindValue(':address', $address, SQLITE3_TEXT)) {
throw new Exception('While binding address: ' . $db->lastErrorMsg());
}
if (!$stmt->execute()) {
throw new Exception('While executing: ' . $db->lastErrorMsg());
}
}
$reload = true;
return JSON_success();
JSON_success();
} catch (\Exception $ex) {
return JSON_error($ex->getMessage());
JSON_error($ex->getMessage());
}
} elseif ($_POST['action'] == 'edit_adlist') {
// Edit adlist identified by ID
@@ -572,7 +646,7 @@ if ($_POST['action'] == 'get_groups') {
if ($status !== 0) {
$status = 1;
}
if (!$stmt->bindValue(':enabled', $status, SQLITE3_INTEGER)) {
throw new Exception('While binding enabled: ' . $db->lastErrorMsg());
}
@@ -606,22 +680,22 @@ if ($_POST['action'] == 'get_groups') {
if (!$stmt->execute()) {
throw new Exception('While executing DELETE statement: ' . $db->lastErrorMsg());
}
$db->query('BEGIN TRANSACTION;');
foreach ($_POST['groups'] as $gid) {
$stmt = $db->prepare('INSERT INTO adlist_by_group (adlist_id,group_id) VALUES(:id,:gid);');
if (!$stmt) {
throw new Exception('While preparing INSERT INTO statement: ' . $db->lastErrorMsg());
}
if (!$stmt->bindValue(':id', intval($_POST['id']), SQLITE3_INTEGER)) {
throw new Exception('While binding id: ' . $db->lastErrorMsg());
}
if (!$stmt->bindValue(':gid', intval($gid), SQLITE3_INTEGER)) {
throw new Exception('While binding gid: ' . $db->lastErrorMsg());
}
if (!$stmt->execute()) {
throw new Exception('While executing INSERT INTO statement: ' . $db->lastErrorMsg());
}
@@ -629,9 +703,9 @@ if ($_POST['action'] == 'get_groups') {
$db->query('COMMIT;');
$reload = true;
return JSON_success();
JSON_success();
} catch (\Exception $ex) {
return JSON_error($ex->getMessage());
JSON_error($ex->getMessage());
}
} elseif ($_POST['action'] == 'delete_adlist') {
// Delete adlist identified by ID
@@ -663,9 +737,9 @@ if ($_POST['action'] == 'get_groups') {
}
$reload = true;
return JSON_success();
JSON_success();
} catch (\Exception $ex) {
return JSON_error($ex->getMessage());
JSON_error($ex->getMessage());
}
} else {
log_and_die('Requested action not supported!');

View File

@@ -183,15 +183,15 @@
<!-- Tell the browser to be responsive to screen width -->
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="shortcut icon" href="img/favicon.png" type="image/x-icon">
<link rel="apple-touch-icon" sizes="180x180" href="img/favicon.png">
<link rel="icon" href="img/logo.svg" type="image/png" sizes="192x192">
<link rel="icon" href="img/logo.svg" type="image/png" sizes="160x160">
<link rel="icon" href="img/logo.svg" type="image/png" sizes="96x96">
<meta name="theme-color" content="#367fa9">
<link rel="apple-touch-icon" href="img/favicons/apple-touch-icon.png" sizes="180x180">
<link rel="icon" href="img/favicons/favicon-32x32.png" sizes="32x32" type="image/png">
<link rel="icon" href="img/favicons/favicon-16x16.png" sizes="16x16" type="image/png">
<link rel="manifest" href="img/favicons/manifest.json">
<link rel="mask-icon" href="img/favicons/safari-pinned-tab.svg" color="#367fa9">
<link rel="shortcut icon" href="img/favicons/favicon.ico">
<meta name="msapplication-TileColor" content="#367fa9">
<meta name="msapplication-TileImage" content="img/logo.svg">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="msapplication-TileImage" content="img/favicons/mstile-150x150.png">
<meta name="theme-color" content="#367fa9">
<link rel="stylesheet" href="style/vendor/SourceSansPro/SourceSansPro.css">
<link rel="stylesheet" href="style/vendor/bootstrap/css/bootstrap.min.css">
@@ -420,13 +420,13 @@ if($auth) {
</div>
<!-- sidebar menu: : style can be found in sidebar.less -->
<?php
if($scriptname === "list.php")
if($scriptname === "groups-domains.php" && isset($_GET['type']))
{
if($_GET["l"] === "white")
if($_GET["type"] === "white")
{
$scriptname = "whitelist";
}
elseif($_GET["l"] === "black")
elseif($_GET["type"] === "black")
{
$scriptname = "blacklist";
}
@@ -478,13 +478,13 @@ if($auth) {
</li>
<!-- Whitelist -->
<li<?php if($scriptname === "whitelist"){ ?> class="active"<?php } ?>>
<a href="list.php?l=white">
<a href="groups-domains.php?type=white">
<i class="fa fa-check-circle "></i> <span>Whitelist</span>
</a>
</li>
<!-- Blacklist -->
<li<?php if($scriptname === "blacklist"){ ?> class="active"<?php } ?>>
<a href="list.php?l=black">
<a href="groups-domains.php?type=black">
<i class="fa fa-ban"></i> <span>Blacklist</span>
</a>
</li>

View File

@@ -35,7 +35,7 @@ function istrue(&$argument) {
// Credit: http://stackoverflow.com/a/4694816/2087442
function validDomain($domain_name)
{
$validChars = preg_match("/^([_a-z\d](-*[_a-z\d])*)(\.([_a-z\d](-*[a-z\d])*))*(\.([a-z\d])*)*$/i", $domain_name);
$validChars = preg_match("/^([_a-z\d](-*[_a-z\d])*)(\.([_a-z\d](-*[a-z\d])*))*(\.([_a-z\d])*)*$/i", $domain_name);
$lengthCheck = preg_match("/^.{1,253}$/", $domain_name);
$labelLengthCheck = preg_match("/^[^\.]{1,63}(\.[^\.]{1,63})*$/", $domain_name);
return ( $validChars && $lengthCheck && $labelLengthCheck ); //length of each label
@@ -44,7 +44,7 @@ function validDomain($domain_name)
function validDomainWildcard($domain_name)
{
// There has to be either no or at most one "*" at the beginning of a line
$validChars = preg_match("/^((\*.)?[_a-z\d](-*[_a-z\d])*)(\.([_a-z\d](-*[a-z\d])*))*(\.([a-z\d])*)*$/i", $domain_name);
$validChars = preg_match("/^((\*.)?[_a-z\d](-*[_a-z\d])*)(\.([_a-z\d](-*[a-z\d])*))*(\.([_a-z\d])*)*$/i", $domain_name);
$lengthCheck = preg_match("/^.{1,253}$/", $domain_name);
$labelLengthCheck = preg_match("/^[^\.]{1,63}(\.[^\.]{1,63})*$/", $domain_name);
return ( $validChars && $lengthCheck && $labelLengthCheck ); //length of each label
@@ -174,24 +174,6 @@ function readDNSserversList()
}
require_once("database.php");
$adlist = [];
function readAdlists()
{
// Reset list
$list = [];
$db = SQLite3_connect(getGravityDBFilename());
if ($db)
{
$results = $db->query("SELECT * FROM adlist");
while($results !== false && $res = $results->fetchArray(SQLITE3_ASSOC))
{
array_push($list, $res);
}
$db->close();
}
return $list;
}
function addStaticDHCPLease($mac, $ip, $hostname) {
global $error, $success, $dhcp_static_leases;
@@ -251,8 +233,6 @@ function addStaticDHCPLease($mac, $ip, $hostname) {
}
}
// Read available adlists
$adlist = readAdlists();
// Read available DNS server list
$DNSserverslist = readDNSserversList();
@@ -555,9 +535,9 @@ function addStaticDHCPLease($mac, $ip, $hostname) {
$adminemail = trim($_POST["adminemail"]);
if(strlen($adminemail) == 0 || !isset($adminemail))
{
$adminemail = 'noadminemail';
$adminemail = '';
}
elseif(!validEmail($adminemail))
if(strlen($adminemail) > 0 && !validEmail($adminemail))
{
$error .= "Administrator email address (".htmlspecialchars($adminemail).") is invalid!<br>";
}
@@ -698,41 +678,6 @@ function addStaticDHCPLease($mac, $ip, $hostname) {
break;
case "adlists":
foreach ($adlist as $key => $value)
{
if(isset($_POST["adlist-del-".$key]))
{
// Delete list
exec("sudo pihole -a adlist del ".escapeshellcmd($value["address"]));
}
elseif(isset($_POST["adlist-enable-".$key]) && $value["enabled"] !== 1)
{
// Is not enabled, but should be
exec("sudo pihole -a adlist enable ".escapeshellcmd($value["address"]));
}
elseif(!isset($_POST["adlist-enable-".$key]) && $value["enabled"] === 1)
{
// Is enabled, but shouldn't be
exec("sudo pihole -a adlist disable ".escapeshellcmd($value["address"]));
}
}
if(strlen($_POST["newuserlists"]) > 1)
{
$domains = array_filter(preg_split('/\r\n|[\r\n]/', $_POST["newuserlists"]));
$comment = "'".$_POST["newusercomment"]."'";
foreach($domains as $domain)
{
exec("sudo pihole -a adlist add ".escapeshellcmd($domain)." ".escapeshellcmd($comment));
}
}
// Reread available adlists
$adlist = readAdlists();
break;
case "privacyLevel":
$level = intval($_POST["privacylevel"]);
if($level >= 0 && $level <= 4)

View File

@@ -1,51 +0,0 @@
<?php
/* Pi-hole: A black hole for Internet advertisements
* (c) 2017 Pi-hole, LLC (https://pi-hole.net)
* Network-wide ad blocking via your own hardware.
*
* This file is copyright under the latest version of the EUPL.
* Please see LICENSE file for your rights under this license. */
require_once('auth.php');
$type = $_POST['list'];
// Perform all of the authentication for list editing
// when NOT invoked and authenticated from API
if (empty($api)) {
list_verify($type);
}
// Split individual domains into array
$domains = preg_split('/\s+/', trim($_POST['domain']));
require_once("func.php");
require("database.php");
$GRAVITYDB = getGravityDBFilename();
$db = SQLite3_connect($GRAVITYDB, SQLITE3_OPEN_READWRITE);
switch($type) {
case "white":
echo remove_from_table($db, "domainlist", $domains, false, ListType::whitelist);
break;
case "black":
echo remove_from_table($db, "domainlist", $domains, false, ListType::blacklist);
break;
case "white_regex":
echo remove_from_table($db, "domainlist", $domains, false, ListType::regex_whitelist);
break;
case "black_regex":
echo remove_from_table($db, "domainlist", $domains, false, ListType::regex_blacklist);
break;
default:
die("Invalid list!");
}
// Reload lists in pihole-FTL after having removed something
echo shell_exec("sudo pihole restartdns reload");
?>

View File

@@ -185,7 +185,7 @@ function archive_restore_table($file, $table, $flush=false)
/**
* Create table rows from an uploaded archive file
*
* @param $file object The file of the file in the archive to import
* @param $file object The file in the archive to import
* @param $table string The target table
* @param $flush boolean Whether to flush the table before importing the archived data
* @param $wildcardstyle boolean Whether to format the input domains in legacy wildcard notation
@@ -193,22 +193,69 @@ function archive_restore_table($file, $table, $flush=false)
*/
function archive_insert_into_table($file, $table, $flush=false, $wildcardstyle=false)
{
global $db, $flushed_tables;
global $db;
$domains = array_filter(explode("\n",file_get_contents($file)));
// Return early if we cannot extract the lines in the file
if(is_null($domains))
return 0;
// Flush table if requested, only flush each table once
if($flush && !in_array($table, $flushed_tables))
{
$db->exec("DELETE FROM ".$table);
array_push($flushed_tables, $table);
// Generate comment
$prefix = "phar:///tmp/";
if (substr($file, 0, strlen($prefix)) == $prefix) {
$file = substr($file, strlen($prefix));
}
$comment = "Imported from ".$file;
// Determine table and type to import to
$type = null;
if($table === "whitelist") {
$table = "domainlist";
$type = ListType::whitelist;
} else if($table === "blacklist") {
$table = "domainlist";
$type = ListType::blacklist;
} else if($table === "regex_blacklist") {
$table = "domainlist";
$type = ListType::regex_blacklist;
} else if($table === "domain_audit") {
$table = "domain_audit";
$type = -1; // -1 -> not used inside add_to_table()
} else if($table === "adlist") {
$table = "adlist";
$type = -1; // -1 -> not used inside add_to_table()
}
// Flush table if requested
if($flush) {
flush_table($table, $type);
}
// Add domains to requested table
return add_to_table($db, $table, $domains, $wildcardstyle, true);
return add_to_table($db, $table, $domains, $comment, $wildcardstyle, true, $type);
}
/**
* Flush table if requested. This subroutine flushes each table only once
*
* @param $table string The target table
* @param $type integer Type of item to flush in table (applies only to domainlist table)
*/
function flush_table($table, $type=null)
{
global $db, $flushed_tables;
if(!in_array($table, $flushed_tables))
{
if($type !== null) {
$sql = "DELETE FROM ".$table." WHERE type = ".$type;
array_push($flushed_tables, $table.$type);
} else {
$sql = "DELETE FROM ".$table;
array_push($flushed_tables, $table);
}
$db->exec($sql);
}
}
function archive_add_directory($path,$subdir="")
@@ -311,7 +358,14 @@ if(isset($_POST["action"]))
if(isset($_POST["auditlog"]) && $file->getFilename() === "auditlog.list")
{
$num = archive_insert_into_table($file, "domain_audit", $flushtables);
echo "Processed blacklist (regex) (".$num." entries)<br>\n";
echo "Processed audit log (".$num." entries)<br>\n";
$importedsomething = true;
}
if(isset($_POST["adlist"]) && $file->getFilename() === "adlists.list")
{
$num = archive_insert_into_table($file, "adlist", $flushtables);
echo "Processed adlists (".$num." entries)<br>\n";
$importedsomething = true;
}