Allow narrowing down the (ad)list type using the (optional) query parameter ?type={allow,block}
Signed-off-by: DL6ER <dl6er@dl6er.de>
This commit is contained in:
parent
9e3ccd917d
commit
7a919cbf59
|
@ -5,6 +5,7 @@ components:
|
|||
summary: Modify list
|
||||
parameters:
|
||||
- $ref: 'lists.yaml#/components/parameters/list'
|
||||
- $ref: 'lists.yaml#/components/parameters/listtype'
|
||||
get:
|
||||
summary: Get lists
|
||||
tags:
|
||||
|
@ -449,3 +450,14 @@ components:
|
|||
required: true
|
||||
description: Address of the list
|
||||
example: https://hosts-file.net/ad_servers.txt
|
||||
listtype:
|
||||
in: query
|
||||
name: type
|
||||
schema:
|
||||
type: string
|
||||
enum:
|
||||
- "allow"
|
||||
- "block"
|
||||
required: false
|
||||
description: Type of list, optional
|
||||
example: block
|
||||
|
|
|
@ -36,7 +36,7 @@ static int api_list_read(struct ftl_conn *api,
|
|||
sql_msg);
|
||||
}
|
||||
|
||||
tablerow table;
|
||||
tablerow table = { 0 };
|
||||
cJSON *rows = JSON_NEW_ARRAY();
|
||||
while(gravityDB_readTableGetRow(listtype, &table, &sql_msg))
|
||||
{
|
||||
|
@ -48,7 +48,9 @@ static int api_list_read(struct ftl_conn *api,
|
|||
JSON_COPY_STR_TO_OBJECT(row, "name", table.name);
|
||||
JSON_COPY_STR_TO_OBJECT(row, "comment", table.comment);
|
||||
}
|
||||
else if(listtype == GRAVITY_ADLISTS)
|
||||
else if(listtype == GRAVITY_ADLISTS ||
|
||||
listtype == GRAVITY_ADLISTS_BLOCK ||
|
||||
listtype == GRAVITY_ADLISTS_ALLOW)
|
||||
{
|
||||
JSON_COPY_STR_TO_OBJECT(row, "address", table.address);
|
||||
JSON_COPY_STR_TO_OBJECT(row, "comment", table.comment);
|
||||
|
@ -126,7 +128,9 @@ static int api_list_read(struct ftl_conn *api,
|
|||
JSON_ADD_NUMBER_TO_OBJECT(row, "date_modified", table.date_modified);
|
||||
|
||||
// Properties added in https://github.com/pi-hole/pi-hole/pull/3951
|
||||
if(listtype == GRAVITY_ADLISTS)
|
||||
if(listtype == GRAVITY_ADLISTS ||
|
||||
listtype == GRAVITY_ADLISTS_BLOCK ||
|
||||
listtype == GRAVITY_ADLISTS_ALLOW)
|
||||
{
|
||||
JSON_REF_STR_IN_OBJECT(row, "type", table.type);
|
||||
JSON_ADD_NUMBER_TO_OBJECT(row, "date_updated", table.date_updated);
|
||||
|
@ -147,7 +151,9 @@ static int api_list_read(struct ftl_conn *api,
|
|||
cJSON *json = JSON_NEW_OBJECT();
|
||||
if(listtype == GRAVITY_GROUPS)
|
||||
objname = "groups";
|
||||
else if(listtype == GRAVITY_ADLISTS)
|
||||
else if(listtype == GRAVITY_ADLISTS ||
|
||||
listtype == GRAVITY_ADLISTS_BLOCK ||
|
||||
listtype == GRAVITY_ADLISTS_ALLOW)
|
||||
objname = "lists";
|
||||
else if(listtype == GRAVITY_CLIENTS)
|
||||
objname = "clients";
|
||||
|
@ -268,6 +274,8 @@ static int api_list_write(struct ftl_conn *api,
|
|||
}
|
||||
|
||||
case GRAVITY_ADLISTS:
|
||||
case GRAVITY_ADLISTS_BLOCK:
|
||||
case GRAVITY_ADLISTS_ALLOW:
|
||||
{
|
||||
cJSON *json_address = cJSON_GetObjectItemCaseSensitive(api->payload.json, "address");
|
||||
if(cJSON_IsString(json_address) && strlen(json_address->valuestring) > 0)
|
||||
|
@ -331,6 +339,10 @@ static int api_list_write(struct ftl_conn *api,
|
|||
NULL);
|
||||
}
|
||||
}
|
||||
else if(listtype == GRAVITY_ADLISTS_BLOCK)
|
||||
row.type_int = ADLIST_BLOCK;
|
||||
else if(listtype == GRAVITY_ADLISTS_ALLOW)
|
||||
row.type_int = ADLIST_ALLOW;
|
||||
else
|
||||
{
|
||||
cJSON *json_type = cJSON_GetObjectItemCaseSensitive(api->payload.json, "type");
|
||||
|
@ -552,7 +564,9 @@ static int api_list_remove(struct ftl_conn *api,
|
|||
if(listtype == GRAVITY_DOMAINLIST_ALLOW_EXACT ||
|
||||
listtype == GRAVITY_DOMAINLIST_DENY_EXACT ||
|
||||
listtype == GRAVITY_DOMAINLIST_ALLOW_REGEX ||
|
||||
listtype == GRAVITY_DOMAINLIST_DENY_REGEX)
|
||||
listtype == GRAVITY_DOMAINLIST_DENY_REGEX ||
|
||||
listtype == GRAVITY_ADLISTS_BLOCK ||
|
||||
listtype == GRAVITY_ADLISTS_ALLOW)
|
||||
{
|
||||
int type = -1;
|
||||
switch (listtype)
|
||||
|
@ -568,12 +582,17 @@ static int api_list_remove(struct ftl_conn *api,
|
|||
break;
|
||||
case GRAVITY_DOMAINLIST_DENY_REGEX:
|
||||
type = 3;
|
||||
break;
|
||||
case GRAVITY_ADLISTS_BLOCK:
|
||||
type = ADLIST_BLOCK;
|
||||
break;
|
||||
case GRAVITY_ADLISTS_ALLOW:
|
||||
type = ADLIST_ALLOW;
|
||||
break;
|
||||
// Not handled herein
|
||||
case GRAVITY_GROUPS:
|
||||
case GRAVITY_ADLISTS:
|
||||
case GRAVITY_CLIENTS:
|
||||
// No type required for these tables
|
||||
break;
|
||||
// Aggregate types cannot be handled by this routine
|
||||
case GRAVITY_GRAVITY:
|
||||
case GRAVITY_ANTIGRAVITY:
|
||||
case GRAVITY_DOMAINLIST_ALLOW_ALL:
|
||||
|
@ -582,7 +601,7 @@ static int api_list_remove(struct ftl_conn *api,
|
|||
case GRAVITY_DOMAINLIST_ALL_REGEX:
|
||||
case GRAVITY_DOMAINLIST_ALL_ALL:
|
||||
default:
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
|
||||
// Create new JSON array with the item and type:
|
||||
|
@ -827,6 +846,30 @@ int api_list(struct ftl_conn *api)
|
|||
api->request->local_uri_raw);
|
||||
}
|
||||
|
||||
// If this is a request for a list, we check if there is a request
|
||||
// parameter narrowing down which kind of list. If so, we modify the
|
||||
// list type accordingly
|
||||
if(listtype == GRAVITY_ADLISTS && api->request->query_string != NULL)
|
||||
{
|
||||
// Check if there is a type parameter
|
||||
char typestr[16] = { 0 };
|
||||
if(get_string_var(api->request->query_string, "type", typestr, sizeof(typestr)) > 0)
|
||||
{
|
||||
if(strcasecmp(typestr, "allow") == 0)
|
||||
listtype = GRAVITY_ADLISTS_ALLOW;
|
||||
else if(strcasecmp(typestr, "block") == 0)
|
||||
listtype = GRAVITY_ADLISTS_BLOCK;
|
||||
else
|
||||
{
|
||||
// Invalid type parameter
|
||||
return send_json_error(api, 400,
|
||||
"bad_request",
|
||||
"Invalid request: Invalid type parameter (should be either \"allow\" or \"block\")",
|
||||
api->request->query_string);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(api->method == HTTP_GET)
|
||||
{
|
||||
// Read list item identified by URI (or read them all)
|
||||
|
|
|
@ -1575,6 +1575,8 @@ bool gravityDB_addToTable(const enum gravity_list_type listtype, tablerow *row,
|
|||
// Nothing to be done for these tables
|
||||
case GRAVITY_GROUPS:
|
||||
case GRAVITY_ADLISTS:
|
||||
case GRAVITY_ADLISTS_BLOCK:
|
||||
case GRAVITY_ADLISTS_ALLOW:
|
||||
case GRAVITY_CLIENTS:
|
||||
break;
|
||||
|
||||
|
@ -1597,7 +1599,9 @@ bool gravityDB_addToTable(const enum gravity_list_type listtype, tablerow *row,
|
|||
{
|
||||
querystr = "INSERT INTO \"group\" (name,enabled,description) VALUES (:item,:enabled,:comment);";
|
||||
}
|
||||
else if(listtype == GRAVITY_ADLISTS)
|
||||
else if(listtype == GRAVITY_ADLISTS ||
|
||||
listtype == GRAVITY_ADLISTS_BLOCK ||
|
||||
listtype == GRAVITY_ADLISTS_ALLOW)
|
||||
{
|
||||
querystr = "INSERT INTO adlist (address,enabled,comment,type) VALUES (:item,:enabled,:comment,:type);";
|
||||
}
|
||||
|
@ -1605,7 +1609,7 @@ bool gravityDB_addToTable(const enum gravity_list_type listtype, tablerow *row,
|
|||
{
|
||||
querystr = "INSERT INTO client (ip,comment) VALUES (:item,:comment);";
|
||||
}
|
||||
else // domainlis
|
||||
else // domainlist
|
||||
{
|
||||
querystr = "INSERT INTO domainlist (domain,type,enabled,comment) VALUES (:item,:type,:enabled,:comment);";
|
||||
}
|
||||
|
@ -1625,9 +1629,11 @@ bool gravityDB_addToTable(const enum gravity_list_type listtype, tablerow *row,
|
|||
querystr = "UPDATE \"group\" SET name = :name, enabled = :enabled, description = :comment "
|
||||
"WHERE name = :item";
|
||||
}
|
||||
else if(listtype == GRAVITY_ADLISTS)
|
||||
else if(listtype == GRAVITY_ADLISTS ||
|
||||
listtype == GRAVITY_ADLISTS_BLOCK ||
|
||||
listtype == GRAVITY_ADLISTS_ALLOW)
|
||||
querystr = "INSERT INTO adlist (address,enabled,comment,type) VALUES (:item,:enabled,:comment,:type) "\
|
||||
"ON CONFLICT(address) DO UPDATE SET enabled = :enabled, comment = :comment, type = :type;";
|
||||
"ON CONFLICT(address,type) DO UPDATE SET enabled = :enabled, comment = :comment, type = :type;";
|
||||
else if(listtype == GRAVITY_CLIENTS)
|
||||
querystr = "INSERT INTO client (ip,comment) VALUES (:item,:comment) "\
|
||||
"ON CONFLICT(ip) DO UPDATE SET comment = :comment;";
|
||||
|
@ -1825,11 +1831,14 @@ bool gravityDB_delFromTable(const enum gravity_list_type listtype, const cJSON*
|
|||
return false;
|
||||
}
|
||||
|
||||
const bool isDomain = listtype == GRAVITY_DOMAINLIST_ALLOW_EXACT ||
|
||||
listtype == GRAVITY_DOMAINLIST_DENY_EXACT ||
|
||||
listtype == GRAVITY_DOMAINLIST_ALLOW_REGEX ||
|
||||
listtype == GRAVITY_DOMAINLIST_DENY_REGEX ||
|
||||
listtype == GRAVITY_DOMAINLIST_ALL_ALL; // batch delete
|
||||
const bool hasType = listtype == GRAVITY_DOMAINLIST_ALLOW_EXACT ||
|
||||
listtype == GRAVITY_DOMAINLIST_DENY_EXACT ||
|
||||
listtype == GRAVITY_DOMAINLIST_ALLOW_REGEX ||
|
||||
listtype == GRAVITY_DOMAINLIST_DENY_REGEX ||
|
||||
listtype == GRAVITY_DOMAINLIST_ALL_ALL ||
|
||||
listtype == GRAVITY_ADLISTS ||
|
||||
listtype == GRAVITY_ADLISTS_BLOCK ||
|
||||
listtype == GRAVITY_ADLISTS_ALLOW;
|
||||
|
||||
// Begin transaction
|
||||
const char *querystr = "BEGIN TRANSACTION;";
|
||||
|
@ -1843,7 +1852,7 @@ bool gravityDB_delFromTable(const enum gravity_list_type listtype, const cJSON*
|
|||
}
|
||||
|
||||
// Create temporary table for JSON argument
|
||||
if(isDomain)
|
||||
if(hasType)
|
||||
// Create temporary table for domains to be deleted
|
||||
querystr = "CREATE TEMPORARY TABLE deltable (type INT, item TEXT);";
|
||||
else
|
||||
|
@ -1885,7 +1894,7 @@ bool gravityDB_delFromTable(const enum gravity_list_type listtype, const cJSON*
|
|||
sqlite3_finalize(stmt);
|
||||
|
||||
// Prepare statement for inserting items into virtual table
|
||||
if(isDomain)
|
||||
if(hasType)
|
||||
querystr = "INSERT INTO deltable (type, item) VALUES (:type, :item);";
|
||||
else
|
||||
querystr = "INSERT INTO deltable (item) VALUES (:item);";
|
||||
|
@ -1910,12 +1919,24 @@ bool gravityDB_delFromTable(const enum gravity_list_type listtype, const cJSON*
|
|||
{
|
||||
// Bind type to prepared statement
|
||||
cJSON *type = cJSON_GetObjectItemCaseSensitive(it, "type");
|
||||
int type_int = cJSON_IsNumber(type) ? type->valueint : -1;
|
||||
if(listtype == GRAVITY_ADLISTS_BLOCK)
|
||||
type_int = ADLIST_BLOCK;
|
||||
else if(listtype == GRAVITY_ADLISTS_ALLOW)
|
||||
type_int = ADLIST_ALLOW;
|
||||
else if(listtype == GRAVITY_ADLISTS && cJSON_IsString(type))
|
||||
{
|
||||
if(strcasecmp(type->valuestring, "block") == 0)
|
||||
type_int = ADLIST_BLOCK;
|
||||
else if(strcasecmp(type->valuestring, "allow") == 0)
|
||||
type_int = ADLIST_ALLOW;
|
||||
}
|
||||
const int type_idx = sqlite3_bind_parameter_index(stmt, ":type");
|
||||
if(type_idx > 0 && (!cJSON_IsNumber(type) || (rc = sqlite3_bind_int(stmt, type_idx, type->valueint)) != SQLITE_OK))
|
||||
if(type_idx > 0 && (rc = sqlite3_bind_int(stmt, type_idx, type_int)) != SQLITE_OK)
|
||||
{
|
||||
*message = sqlite3_errmsg(gravity_db);
|
||||
log_err("gravityDB_delFromTable(%d): Failed to bind type (error %d) - %s",
|
||||
type->valueint, rc, *message);
|
||||
type_int, rc, *message);
|
||||
sqlite3_reset(stmt);
|
||||
sqlite3_finalize(stmt);
|
||||
|
||||
|
@ -1981,12 +2002,15 @@ bool gravityDB_delFromTable(const enum gravity_list_type listtype, const cJSON*
|
|||
const char *querystrs[4] = {NULL, NULL, NULL, NULL};
|
||||
if(listtype == GRAVITY_GROUPS)
|
||||
querystrs[0] = "DELETE FROM \"group\" WHERE name IN (SELECT item FROM deltable);";
|
||||
else if(listtype == GRAVITY_ADLISTS)
|
||||
else if(listtype == GRAVITY_ADLISTS ||
|
||||
listtype == GRAVITY_ADLISTS_BLOCK ||
|
||||
listtype == GRAVITY_ADLISTS_ALLOW)
|
||||
{
|
||||
// This is actually a three-step deletion to satisfy foreign-key constraints
|
||||
querystrs[0] = "DELETE FROM gravity WHERE adlist_id IN (SELECT id FROM adlist WHERE address IN (SELECT item FROM deltable));";
|
||||
querystrs[1] = "DELETE FROM antigravity WHERE adlist_id IN (SELECT id FROM adlist WHERE address IN (SELECT item FROM deltable));";
|
||||
querystrs[2] = "DELETE FROM adlist WHERE address IN (SELECT item FROM deltable);";
|
||||
// This is actually a four-step deletion to satisfy foreign-key constraints
|
||||
querystrs[0] = "DELETE FROM gravity WHERE adlist_id IN (SELECT id FROM adlist WHERE address IN (SELECT item FROM deltable WHERE type = 0));";
|
||||
querystrs[1] = "DELETE FROM antigravity WHERE adlist_id IN (SELECT id FROM adlist WHERE address IN (SELECT item FROM deltable WHERE type = 1));";
|
||||
querystrs[2] = "DELETE FROM adlist WHERE address IN (SELECT item FROM deltable WHERE type = 0) AND type = 0;";
|
||||
querystrs[3] = "DELETE FROM adlist WHERE address IN (SELECT item FROM deltable WHERE type = 1) AND type = 1;";
|
||||
}
|
||||
else if(listtype == GRAVITY_CLIENTS)
|
||||
querystrs[0] = "DELETE FROM client WHERE ip IN (SELECT item FROM deltable);";
|
||||
|
@ -2096,12 +2120,16 @@ bool gravityDB_readTable(const enum gravity_list_type listtype,
|
|||
case GRAVITY_DOMAINLIST_ALL_ALL:
|
||||
type = "0,1,2,3";
|
||||
break;
|
||||
|
||||
// No type required for these tables
|
||||
case GRAVITY_GRAVITY:
|
||||
case GRAVITY_ANTIGRAVITY:
|
||||
case GRAVITY_GROUPS:
|
||||
case GRAVITY_ADLISTS:
|
||||
case GRAVITY_CLIENTS:
|
||||
// No type required for these tables
|
||||
case GRAVITY_ADLISTS:
|
||||
// Type is set in the SQL query directly
|
||||
case GRAVITY_ADLISTS_BLOCK:
|
||||
case GRAVITY_ADLISTS_ALLOW:
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -2133,19 +2161,29 @@ bool gravityDB_readTable(const enum gravity_list_type listtype,
|
|||
}
|
||||
snprintf(querystr, buflen, "SELECT id,name,enabled,date_added,date_modified,description AS comment FROM \"group\"%s;", filter);
|
||||
}
|
||||
else if(listtype == GRAVITY_ADLISTS)
|
||||
else if(listtype == GRAVITY_ADLISTS ||
|
||||
listtype == GRAVITY_ADLISTS_BLOCK ||
|
||||
listtype == GRAVITY_ADLISTS_ALLOW)
|
||||
{
|
||||
if(listtype == GRAVITY_ADLISTS_BLOCK)
|
||||
filter = "type = 0";
|
||||
else if(listtype == GRAVITY_ADLISTS_ALLOW)
|
||||
filter = "type = 1";
|
||||
else
|
||||
filter = "TRUE";
|
||||
|
||||
const char *filter2 = "";
|
||||
if(item != NULL && item[0] != '\0')
|
||||
{
|
||||
if(exact)
|
||||
filter = " WHERE address = :item";
|
||||
filter2 = " AND address = :item";
|
||||
else
|
||||
filter = " WHERE address LIKE :item";
|
||||
filter2 = " AND address LIKE :item";
|
||||
}
|
||||
snprintf(querystr, buflen, "SELECT id,type,address,enabled,date_added,date_modified,comment,"
|
||||
"(SELECT GROUP_CONCAT(group_id) FROM adlist_by_group g WHERE g.adlist_id = a.id) AS group_ids,"
|
||||
"date_updated,number,invalid_domains,status,abp_entries "
|
||||
"FROM adlist a%s;", filter);
|
||||
"FROM adlist a WHERE %s%s;", filter, filter2);
|
||||
}
|
||||
else if(listtype == GRAVITY_CLIENTS)
|
||||
{
|
||||
|
@ -2312,6 +2350,8 @@ bool gravityDB_readTableGetRow(const enum gravity_list_type listtype, tablerow *
|
|||
}
|
||||
}
|
||||
else if(listtype == GRAVITY_ADLISTS ||
|
||||
listtype == GRAVITY_ADLISTS_ALLOW ||
|
||||
listtype == GRAVITY_ADLISTS_BLOCK ||
|
||||
listtype == GRAVITY_GRAVITY ||
|
||||
listtype == GRAVITY_ANTIGRAVITY)
|
||||
{
|
||||
|
@ -2328,6 +2368,10 @@ bool gravityDB_readTableGetRow(const enum gravity_list_type listtype, tablerow *
|
|||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
row->type = "unknown";
|
||||
}
|
||||
}
|
||||
|
||||
else if(strcasecmp(cname, "domain") == 0)
|
||||
|
@ -2425,9 +2469,14 @@ bool gravityDB_edit_groups(const enum gravity_list_type listtype, cJSON *groups,
|
|||
del_querystr = "DELETE FROM client_by_group WHERE client_id = :id;";
|
||||
add_querystr = "INSERT INTO client_by_group (client_id,group_id) VALUES (:id,:gid);";
|
||||
}
|
||||
else if(listtype == GRAVITY_ADLISTS)
|
||||
else if(listtype == GRAVITY_ADLISTS ||
|
||||
listtype == GRAVITY_ADLISTS_BLOCK ||
|
||||
listtype == GRAVITY_ADLISTS_ALLOW)
|
||||
{
|
||||
get_querystr = "SELECT id FROM adlist WHERE address = :item";
|
||||
if(listtype == GRAVITY_ADLISTS)
|
||||
get_querystr = "SELECT id FROM adlist WHERE address = :item";
|
||||
else
|
||||
get_querystr = "SELECT id FROM adlist WHERE address = :item AND type = :type";
|
||||
del_querystr = "DELETE FROM adlist_by_group WHERE adlist_id = :id;";
|
||||
add_querystr = "INSERT INTO adlist_by_group (adlist_id,group_id) VALUES (:id,:gid);";
|
||||
}
|
||||
|
|
|
@ -189,7 +189,9 @@ enum gravity_list_type {
|
|||
GRAVITY_ADLISTS,
|
||||
GRAVITY_CLIENTS,
|
||||
GRAVITY_GRAVITY,
|
||||
GRAVITY_ANTIGRAVITY
|
||||
GRAVITY_ANTIGRAVITY,
|
||||
GRAVITY_ADLISTS_BLOCK,
|
||||
GRAVITY_ADLISTS_ALLOW
|
||||
} __attribute__ ((packed));
|
||||
|
||||
enum gravity_tables {
|
||||
|
|
|
@ -1420,6 +1420,28 @@
|
|||
[[ ${lines[0]} == "145" ]]
|
||||
}
|
||||
|
||||
@test "Check /api/lists?type=block returning only blocking lists" {
|
||||
run bash -c 'curl -s 127.0.0.1/api/lists?type=block | jq ".lists[].type"'
|
||||
printf "%s\n" "${lines[@]}"
|
||||
# Check no allow entries are present
|
||||
[[ ${lines[@]} != *"allow"* ]]
|
||||
}
|
||||
|
||||
@test "Check /api/lists?type=allow returning only allowing lists" {
|
||||
run bash -c 'curl -s 127.0.0.1/api/lists?type=allow | jq ".lists[].type"'
|
||||
printf "%s\n" "${lines[@]}"
|
||||
# Check no block entries are present
|
||||
[[ ${lines[@]} != *"block"* ]]
|
||||
}
|
||||
|
||||
@test "Check /api/lists without type parameter returning all lists" {
|
||||
run bash -c 'curl -s 127.0.0.1/api/lists | jq ".lists[].type"'
|
||||
printf "%s\n" "${lines[@]}"
|
||||
# Check both block and allow entries are present
|
||||
[[ ${lines[@]} == *"allow"* ]]
|
||||
[[ ${lines[@]} == *"block"* ]]
|
||||
}
|
||||
|
||||
@test "API authorization (without password): No login required" {
|
||||
run bash -c 'curl -s 127.0.0.1/api/auth'
|
||||
printf "%s\n" "${lines[@]}"
|
||||
|
|
Loading…
Reference in New Issue