Remove obsolete API documentation. This is to be replaced by the OpenAPI documentation that ships with FTL

Signed-off-by: DL6ER <dl6er@dl6er.de>
This commit is contained in:
DL6ER
2023-07-08 13:52:56 +02:00
parent 64bbfe77c6
commit a7a5cb1f49
6 changed files with 0 additions and 979 deletions

View File

@@ -1,226 +0,0 @@
## Overview
The Pi-hole API uses **digest-access challenge-response authentication**. This method is one of the agreed-upon methods a web server can use to negotiate credentials with a client. Challenge-response authentication uses a cryptographic protocol that allows proving that the user knows the password *without revealing the password itself at any point in the process*.
## How it works
This method works as follows: The application first obtains a random challenge from the server. It then computes the response applying a cryptographic hash function to the server challenge combined with the user's password.
Upon receiving the response, the server applies the same hash function to the challenge combined with its own copy of the user's password. If the resulting value matches the response sent by the application, this indicates that the user has submitted the correct password.
Assume the following:
1. Bob is controlling access to the API.
2. Alice comes along seeking entry.
3. Bob issues a challenge, perhaps `52w72y`.
4. Alice must respond with *the one string* of characters which "fits" the challenge Bob issued. The "fit" is determined by a cryptographically secure algorithm "known" to Bob and Alice.
5. Only if this response is correct, Alice is granted access.
As a result, the password itself is never transmitted plain-text. Eavesdropping on the communication is of no use to an attacker:
1. The use of a hash function does not allow the access data (the password) to be reconstructed, and
2. Furthermore, as Bob issues a different challenge each time, a previous correct response cannot be reused.
Hence, replay attacks are prevented.
<!-- markdownlint-disable code-block-style -->
!!! info "A note about security"
By modern cryptography standards this authentication method may be considered relatively weak. However, for our purpose - protecting your password against evesdropping on an otherwise unprotected channel, is yet far superior to other plain methods, such as the still widely used HTTP Basic Authentication.
Our particular implementation was chosen to mitigate the most important threads, while still being very easy to implement (for third-party apps, etc.):
- **The plain password is never sent clear to the server, preventing [Phishing](https://en.wikipedia.org/wiki/Phishing).**
- The unique random nounce together with the self-salted password hashing effectively **prevents chosen-plaintext-attacks** using precomputed rainbow tables.
??? info "About the security of the SHA-256 algorithm"
**It is not feasible to reverse the SHA-256 algorithm using a brute-force attack as this would require a lot more energy than mankind has available for use.**
A good explanation about the Thermodynamic limits applying here is by Bruce Schneier in [`Applied Cryptography`](https://www.schneier.com/blog/archives/2009/09/the_doghouse_cr.html):
> One of the consequences of the second law of thermodynamics is that a certain amount of energy is necessary to represent information. To record a single bit by changing the state of a system requires an amount of energy no less than $kT$, where $T$ is the absolute temperature of the system and $k$ is the Boltzman constant. (Stick with me; the physics lesson is almost over.)
>
> Given that $k=1.38\cdot 10^{-16}$ erg/K, and that the ambient temperature of the universe is $3.2$ K, an ideal computer running at $3.2$ K would consume $4.4\cdot 10^{-16}$ ergs every time it set or cleared a bit. To run a computer any colder than the cosmic background radiation would require extra energy to run a heat pump.
>
> Now, the annual energy output of our sun is about $1.21\cdot 10^{41}$ ergs. This is enough to power about $2.7\cdot 10^{56}$ single bit changes on our ideal computer; enough state changes to put a 187-bit counter through all its values. If we built a Dyson sphere around the sun and captured all of its energy for 32 years, without any loss, we could power a computer to count up to $2^{192}$. Of course, it wouldnt have the energy left over to perform any useful calculations with this counter.
>
> But thats just one star, and a measly one at that. A typical supernova releases something like $10^{51}$ ergs. (About a hundred times as much energy would be released in the form of neutrinos, but let them go for now.) If all of this energy could be channeled into a single orgy of computation, a 219-bit counter could be cycled through all of its states.
>
> These numbers have nothing to do with the technology of the devices; they are the maximums that thermodynamics will allow. And they strongly imply that **brute-force attacks against 256-bit keys will be *infeasible* until computers are built from something other than matter and occupy something other than space**.
<!-- markdownlint-enable code-block-style -->
## Description of the algorithm
The algorithm itself is pretty simple:
1. The client requests a cryptographic nonce as the challenge to ensure that every challenge-response sequence is unique. Each challenge is valid for 8 seconds after its generation. The unique challenge can be requested at `GET /api/auth`
2. The client computes the correct response using the simple two-step algorithm
$$
\begin{align}
\textrm{pwhash} &= \textrm{SHA256}(\textrm{SHA256}(\textrm{password}))\\
\textrm{response} &= \textrm{SHA256}(\textrm{challenge} + ":" + \textrm{pwhash})
\end{align}
$$
where all intermediate steps are always done with an ASCII (hex) representation of the data.
3. The client sends the computed response back to the server at `POST /api/auth` using the `response` as `POST` parameter.
The server responds with either HTTP code `200` on success, `400` (bad request) or `401` (unauthorized) on failure, or `500` (on an internal error). If authentication succeeds, the API returns a session cookie as well as a session token. One of them needs to can be included with subsequent requests to the API.
<!-- markdownlint-disable code-block-style -->
??? info "The cryptographic nonce"
It is impractical to implement a true nonce as Pi-hole is supposed to run on various systems and architectures. Hence, we employ a non-linear additive-feedback pseudo-random number generator and a cryptographically secure hash function to generate challenges that are highly unlikely to occur more than once. The period of the used pseudo-random number generator is very large, approximately $16 \cdot ((2^{31}) - 1) = 34\,359\,738\,352$.
**When requesting 10 challenges per second, the uniqueness of the generated challenges would still be guaranteed for over 100 years.**
Random-number generation is a complex topic. *Numerical Recipes in C: The Art of Scientific Computing* (William H. Press, Brian P. Flannery, Saul A. Teukolsky, William T. Vetterling; New York: Cambridge University Press, 2007, 3rd ed.) provides an excellent discussion of practical random-number generation issues in Chapter 7 (Random Numbers).
For a more theoretical discussion which also covers many practical issues in depth, see Chapter 3 (Random Numbers) in Donald E. Knuth's *The Art of Computer Programming*, volume 2 (Seminumerical Algorithms), 2nd ed.; Reading, Massachusetts: Addison-Wesley Publishing Company, 1981.
<!-- markdownlint-enable code-block-style -->
Because of the "one-way" properties of the SHA-256 hash function, it is not possible to recover the password from the response sent by the client.
On successful authentication, the server returns both a session cookie (via its response headers) and a session ID (in the payload). Both can be used independently to authenticate. If both are supplied, the session cookie will be preferred by the server.
## Examples
Getting a challenge is simple and straightforward:
``` bash
curl -X GET http://pi.hole/api/auth
```
Result:
``` json
{
"challenge": "a2926b025bcc8618c632f81cd6cf7c37ee051c08aab74b565fd5126350fcd056",
"session":
{
"valid": false,
"sid": null,
"validity": null
}
}
```
Below, we provide concrete examples of how to authenticate with the Pi-hole API. These simplified examples are prrof-of-concept to aid your understanding. They do not deal with possible errors such as a failed connection. They do work both with succeeded and failed login attempts.
!!! info "Security hint"
You can always store the `pwhash` (the double-hashed password) instead of `password` (the plaintext password) if you are using this in a script.
### Bash
``` bash linenums="1"
computePWhash() {
local password hash1 hash2
password="${1}"
# Compute password hash twice to avoid rainbow table vulnerability
hash1=$(echo -n "$password" | sha256sum | sed 's/\s.*$//')
hash2=$(echo -n "$hash1" | sha256sum | sed 's/\s.*$//')
echo "${hash2}"
}
computeResponse() {
local pwhash challenge response
pwhash="${1}"
challenge="${2}"
response=$(echo -n "${challenge}:${pwhash}" | sha256sum | sed 's/\s.*$//')
echo "${response}"
}
```
``` bash linenums="1" hl_lines="4 5 6"
password="ABC"
pwhash="$(computePWhash "$password")"
challenge="$(curl -s -X GET http://pi.hole/api/auth | jq --raw-output .challenge)"
response="$(computeResponse "$pwhash" "$challenge")"
session="$(curl -s -X POST --data response="$response" http://pi.hole/api/auth)"
valid=$(jq .session.valid <<< "${session}")
sid="$(jq --raw-output .session.sid <<< "${session}")"
```
### Javascript
We recommend using [`geraintluff/sha256`](https://github.com/geraintluff/sha256) providing a small (less than 1 KB) SHA-256 implementation.
``` javascript linenums="1" hl_lines="4 8 16"
function getPWhash(password) {
// Compute password hash twice to mitigate rainbow
// table vulnerability
return sha256(sha256(password));
}
function sendResponse(pwhash, challenge) {
var response = sha256(challenge + ":" + pwhash);
$.ajax({
url: "http://pi.hole/api/auth",
method: "POST",
data: { response: response }
})
.done(function (data) {
console.log("Login successful");
session = data.session;
console.log(session);
})
.fail(function (data) {
console.log("Login failed");
});
}
function doLogin(pwhash) {
$.ajax({
url: "http://pi.hole/api/auth",
method: "GET"
}).done(function (data) {
if ("challenge" in data) {
console.log("Challenge received");
sendResponse(pwhash, data.challenge);
}
});
}
```
``` javascript linenums="1"
var password = "ABC";
var pwhash = getPWhash("ABC");
doLogin(pwhash);
```
### Python 3
``` python linenums="1" hl_lines="10 11 12"
import requests
from hashlib import sha256
url = "http://pi.hole/api/auth"
password = b"ABC"
pwhash_ = sha256(password).hexdigest().encode("ascii")
pwhash = sha256(pwhash_).hexdigest().encode("ascii")
challenge = requests.get(url).json()["challenge"].encode('ascii')
response = sha256(challenge + b":" + pwhash).hexdigest().encode("ascii")
session = requests.post(url, data = {"response": response}).json()
valid = session["session"]["valid"] # True / False
sid = session["session"]["sid"] # SID string if succesful, null otherwise
```
### Result of the authentication
The result of a successful authentication is
``` json
{
"session":
{
"valid": true,
"sid": "XwrWDU7EDg64dX0sxmURDA==",
"validity": 300
}
}
```
together with a session cookie

View File

@@ -1,138 +0,0 @@
# DNS - Status
## Obtain current blocking status
- `GET /api/dns/blocking`
<!-- markdownlint-disable code-block-style -->
???+ example "🔓 Request"
=== "cURL"
``` bash
curl -X GET http://pi.hole/api/dns/blocking
```
=== "Python 3"
``` python
import requests
url = 'http://pi.hole:8080/api/dns/blocking'
response = requests.get(url)
print(response.json())
```
**Parameters**
None
???+ success "Response"
Response code: `HTTP/1.1 200 OK`
``` json
{
"blocking": true,
"timer": null
}
```
If there is currently a timer running, the reply will be like
``` json
{
"blocking": false,
"timer": {
"delay": 5,
"blocking_target": true
}
}
```
**Reply type**
Object
**Fields**
??? info "Status (`"blocking": boolean`)"
Current blocking status.
??? info "Timer details (`"timer": [object|null]`)"
Additional information about a possibly temporary blocking mode. If no timer is running (the current blocking mode is permanent), `null` is returned instead of an object.
??? info "Remaining time (`"delay": number`)"
Seconds until the blocking status indicated by `"blocking_target"` is applied.
??? info "Remaining time (`"blocking_target": boolean`)"
Status applied after the timer elapsed.
<!-- markdownlint-enable code-block-style -->
## Change blocking status
- `POST /api/dns/blocking`
<!-- markdownlint-disable code-block-style -->
???+ example "🔒 Request"
=== "cURL"
``` bash
curl -X PUT http://pi.hole/api/dns/blocking \
-H "Content-Type: application/json" \
-d "{\"blocking\": false, \"delay\": 30, \"sid\": \"${sid}\"}"
```
=== "Python 3"
``` python
import requests
sid = '<valid session id>'
url = 'http://pi.hole:8080/api/dns/blocking'
data = {"blocking": False, "delay": 30, "sid": sid}
response = requests.put(url, json=data)
print(response.json())
```
**Required parameters**
??? info "Status (`"blocking": boolean`)"
Blocking status to be applied. When requesting the same status as is already set, a possibly running timer is disabled.
**Optional parameters**
??? info "Timer delay (`"delay": number`)"
Delay until the previous blocking status is re-applied. This can be used to disable Pi-hole's blocking temporarily. Subsequent requests overwrite previous timers. When omitting this value, a possibly running timer is disabled.
This setting has no effect when requesting the same blocking state that is already active.
???+ success "Response"
Response code: `HTTP/1.1 200 OK`
``` json
{
"blocking": false,
"timer": {
"delay": 30,
"blocking_target": true
}
}
```
**Reply type**
Object
**Fields**
See description of the `GET` request above. Remember that `timer` may be `null` if there is no active timer.
<!-- markdownlint-enable code-block-style -->
{!abbreviations.md!}

View File

@@ -1,107 +0,0 @@
`pihole-FTL` offers an efficient DNS cache that helps speed up your Internet experience. This DNS cache is part of the embedded `dnsmasq` server. Setting the cache size to zero disables caching. The DNS TTL value is used for determining the caching period. `pihole-FTL` clears its cache on receiving `SIGHUP`.
<!-- markdownlint-disable code-block-style -->
!!! warning Some warning about the DNS cache size
**There is no benefit in increasing this number *unless* the number of DNS cache evictions is greater than zero.**
A larger cache *will* consume more memory on your node, leaving less memory available for other caches of your Pi-hole. If you push this number to the extremes, it may even be that your Pi-hole gets short on memory and does not operate as expected.
You can not reduce the cache size below `150` when DNSSEC is enabled because the DNSSEC validation process uses the cache.
<!-- markdownlint-enable code-block-style -->
### Cache metrics
The Settings page (System panel, FTL table) gives live information about the cache usage.
#### DNS cache size
Size of the DNS domain cache, defaulting to 10,000 entries. It is the number of entries that can be actively cached at the same time.
This information may also be queried using `dig +short chaos txt cachesize.bind`
The cache size is set in `/etc/dnsmasq.d/01-pihole.conf`. However, note that this setting does not survive Pi-hole updates. If you want to change the cache size permanently, add a setting
``` plain
CACHE_SIZE=12345
```
in `/etc/pihole/setupVars.conf` and run `pihole -r` (Repair) to get the cache size changed for you automatically.
#### DNS cache insertions
Number of total insertions into the cache. This number can be substantially larger than DNS cache size as expiring cache entries naturally make room for new insertions over time. Each lookup with a non-zero TTL will be cached.
This information may also be queried using `dig +short chaos txt insertions.bind`
#### DNS cache evictions
The number of cache entries that had to be removed although the corresponding entries were **not** expired. Old cache entries get removed if the cache is full to make space for more recent domains. The cache size should be increased when this number is larger than zero.
This information may also be queried using `dig +short chaos txt evictions.bind`
## Obtain information about Pi-hole's DNS cache through the API
- `GET /api/dns/cache`
<!-- markdownlint-disable code-block-style -->
???+ example "🔒 Request"
=== "cURL"
``` bash
curl -X GET http://pi.hole/api/dns/cacheinfo \
-d sid="$sid"
```
=== "Python 3"
``` python
import requests
url = 'http://pi.hole:8080/api/dns/cacheinfo'
sid = '<valid session id>'
data = {"sid": sid}
response = requests.get(url, json=data)
print(response.json())
```
**Parameters**
None
??? success "Response"
Response code: `HTTP/1.1 200 OK`
``` json
{
"cache_size": 10000,
"cache_inserted": 2616,
"cache_evicted": 0
}
```
**Reply type**
Object
**Fields**
??? info "DNS cache size (`"cache_size": number`)"
See above.
??? info "DNS cache insertions (`"cache_inserted": number`)"
See above.
??? info "DNS cache evictions (`"cache_evicted": number`)"
See above.
<!-- markdownlint-enable code-block-style -->
This endpoint cannot fail.
{!abbreviations.md!}

View File

@@ -1,485 +0,0 @@
# DNS - Domain Lists
## List all domains/regex
- `GET /api/domains` (all domains + regex)
- `GET /api/domains/allow` (only allowed domains + regex)
- `GET /api/domains/allow/exact` (only allowed domains)
- `GET /api/domains/allow/regex` (only allowed regex)
- `GET /api/domains/deny` (only denied domains + regex)
- `GET /api/domains/deny/exact` (only denied domains)
- `GET /api/domains/deny/regex` (only denied regex)
- `GET /api/domains/exact` (allowed + denied domain)
- `GET /api/domains/regex` (allowed + denied regex)
<!-- markdownlint-disable code-block-style -->
???+ example "🔒 Request"
=== "cURL"
``` bash
curl -X GET http://pi.hole/api/domains \
-d sid="$sid"
```
=== "Python 3"
``` python
import requests
url = 'http://pi.hole:8080/api/domains'
sid = '<valid session id>'
data = {"sid": sid}
response = requests.get(url, json=data)
print(response.json())
```
**Parameters**
None
??? success "Success response"
Response code: `HTTP/1.1 200 OK`
``` json
{
"domains": [{
"id": 0,
"domain": "allowed.com",
"type": "allow/exact",
"comment": null,
"groups": [0],
"enabled": true,
"date_added": 1611239095,
"date_modified": 1611239095
}, {
"id": 1,
"domain": "allowed_disabled.com",
"type": "allow/exact",
"comment": null,
"groups": [0],
"enabled": false,
"date_added": 1611239100,
"date_modified": 1611239136
}, {
"id": 2,
"domain": "denied.com",
"type": "deny/exact",
"comment": null,
"groups": [0],
"enabled": true,
"date_added": 1611239144,
"date_modified": 1611239144
}, {
"id": 3,
"domain": "regex_deny_rule",
"type": "deny/regex",
"comment": null,
"groups": [0],
"enabled": true,
"date_added": 1611239170,
"date_modified": 1611239170
}]
}
```
**Reply type**
Array of objects (may be empty if no item of the requested flavor exist)
**Fields**
??? info "Database ID (`"id": number`)"
Database ID of this domain/regular expression
??? info "Domain/regex (`"domain": string`)"
Item depending on the list type.
??? info "Type of entry (`"type": string`)"
String specifying item type. Can be one of
- `allow/exact`
- `deny/exact`
- `allow/regex`
- `deny/regex`
??? info "Comment (`"comment": [null|string]`)"
User-provided free-text comment for this item. May be `null` if not specified.
??? info "Group associations (`"groups": array)"
Array of group IDs this item is associated with.
??? info "Enabled (`"enabled": boolean`)"
Whether this item is enabled or disabled.
??? info "Addition time (`"date_added": number`)"
Unix timestamp of addition of this item to Pi-hole's database.
Use `#!bash date -d @1589108911` to obtain a human-readable datetime string.
??? info "Modification time (`"date_modified": number`)"
Unix timestamp of modification of this item in Pi-hole's database.
Use `#!bash date -d @1589104951` to obtain a human-readable datetime string.
??? failure "Error response"
Response code: `HTTP/1.1 400 - Bad request`
``` json
{
"error": {
"key": "database_error",
"message": "Could not read domains from database table",
"data": {
"sql_msg": "Database not available"
}
}
}
```
<!-- markdownlint-enable code-block-style -->
## List specific domain/regex
- `GET /api/domains/allow/exact/<domain or regex>`
- `GET /api/domains/allow/regex/<domain or regex>`
- `GET /api/domains/allow/exact/<domain or regex>`
- `GET /api/domains/allow/regex/<domain or regex>`
<!-- markdownlint-disable code-block-style -->
???+ example "🔒 Request"
=== "cURL"
``` bash
domain="allowed.com"
curl -X GET http://pi.hole/api/domains/allow/exact/domains/${domain} \
-d sid=$sid
```
=== "Python 3"
``` python
import requests
domain = 'allowed.com'
url = 'http://pi.hole:8080/api/domains/allow/exact/' + domain
sid = '<valid session id>'
data = {"sid": sid}
response = requests.get(url, json=data)
print(response.json())
```
**Parameters**
Specify the requested item through the URL (`<domain>`)
??? success "Success response"
Response code: `HTTP/1.1 200 OK`
``` json
{
"domains": [{
"id": 0,
"domain": "allowed.com",
"type": "allow/exact",
"comment": null,
"groups": [0],
"enabled": true,
"date_added": 1611239095,
"date_modified": 1611239095
}]
}
```
**Fields**
See description of the `GET` request above.
??? failure "Error response"
Response code: `HTTP/1.1 400 - Bad request`
``` json
{
"error": {
"key": "database_error",
"message": "Could not read domains from database table",
"data": {
"sql_msg": "Database not available"
}
}
}
```
<!-- markdownlint-enable code-block-style -->
## Add domain/regex
**Create new entry (error on existing identical record)**
- `POST /api/domains/allow/exact`
- `POST /api/domains/allow/regex`
- `POST /api/domains/allow/exact`
- `POST /api/domains/allow/regex`
<!-- markdownlint-disable code-block-style -->
???+ example "🔒 Request"
=== "cURL"
``` bash
curl -X POST http://pi.hole/api/domains/allow/exact \
-d sid=$sid \
-H "Content-Type: application/json" \
-d '{"domain": "allowed2.com", "enabled": true, "comment": "Some text"}'
```
=== "Python 3"
``` python
import requests
url = 'http://pi.hole:8080/api/domains/allow/exact'
sid = '<valid session id>'
data = {
"item": "allowed2.com",
"enabled": True,
"comment": "Some text",
"sid": sid
}
response = requests.post(url, json=data)
print(response.json())
```
**Optional parameters**
??? info "Domain/regex (`"item": string`)"
Domain or regex to be added. When this is a regular expression, ensure it is properly JSON-escaped.
??? info "Enabled (`"enabled": boolean`)"
Whether this item should enabled or not.
??? info "Comment (`"comment": string`)"
User-provided free-text comment for this item.
??? success "Success response"
Response code: `HTTP/1.1 201 Created`
``` json
{
"domains": [{
"id": 4,
"domain": "allowed2.com",
"type": "allow/exact",
"comment": null,
"groups": [0],
"enabled": true,
"date_added": 1611239095,
"date_modified": 1611239095
}]
}
```
**Fields**
See description of the `GET` request above.
??? failure "Error response"
Response code: `HTTP/1.1 400 - Bad Request`
``` json
{
"error": {
"key": "database_error",
"message": "Could not add domain to gravity database",
"data": {
"argument": "allowed2.com",
"enabled": true,
"comment": "Some text",
"sql_msg": "UNIQUE constraint failed: domainlist.domain, domainlist.type"
}
}
}
```
!!! hint "Hint: Use `PUT` instead of `POST` to avoid unique constraints"
When using `PUT` instead of `POST`, duplicate domains are silently replaced without issuing an error.
<!-- markdownlint-enable code-block-style -->
## Update domain/regex
**Create new or update existing entry (no error on existing record)**
- `PUT /api/domains/allow/exact/<domain or regex>`
- `PUT /api/domains/allow/regex/<domain or regex>`
- `PUT /api/domains/allow/exact/<domain or regex>`
- `PUT /api/domains/allow/regex/<domain or regex>`
<!-- markdownlint-disable code-block-style -->
???+ example "🔒 Request"
=== "cURL"
``` bash
domain="allowed2.com"
curl -X PUT http://pi.hole/api/domains/allow/regex/${domain} \
-d sid=$sid \
-H "Content-Type: application/json" \
-d '{"oldtype": "allow/exact", "enabled": true, "comment": "Some text"}'
```
=== "Python 3"
``` python
import requests
domain = "allowed2.com"
url = 'http://pi.hole:8080/api/domains/allow/regex/' + domain
sid = '<valid session id>'
data = {
"oldtype": "allow/exact",
"enabled": True,
"comment": "Some text",
"sid": sid
}
response = requests.put(url, json=data)
print(response.json())
```
**Required parameters**
??? info "Previous type of domain/regex (`"oldtype": string`)"
Type this domain/regex had before. If not identical to the target, e.g., `oldtype=allow/exact` and `url=http://pi.hole/api/domains/allow/regex/`, the domain/regex will be changed in type.
**Optional parameters**
??? info "Enabled (`"enabled": boolean`)"
Whether this item should enabled or not.
??? info "Comment (`"comment": string`)"
User-provided free-text comment for this item.
??? success "Success response"
Response code: `HTTP/1.1 201 Created`
``` json
{
"domains": [{
"id": 4,
"domain": "allowed2.com",
"type": "allow/regex",
"comment": null,
"groups": [0],
"enabled": true,
"date_added": 1611239095,
"date_modified": 1611241276
}]
}
```
Note that the regex moved from `allow/exact` to `allow/regex`.
**Fields**
See description of the `GET` request above.
## Delete domain/regex
- `DELETE /api/domains/allow/exact/<domain or regex>`
- `DELETE /api/domains/allow/regex/<domain or regex>`
- `DELETE /api/domains/allow/exact/<domain or regex>`
- `DELETE /api/domains/allow/regex/<domain or regex>`
<!-- markdownlint-disable code-block-style -->
???+ example "🔒 Request"
=== "cURL"
**Domain**
``` bash
domain="allowed2.com"
curl -X DELETE http://pi.hole/api/domains/allow/exact/${domain} \
-d sid=$sid
```
**Regular expression need to be encoded**
``` bash
regex="$(echo -n "(^|\\.)facebook.com$" | jq -sRr '@uri')"
curl -X DELETE http://pi.hole/api/domains/allow/exact/${regex} \
-d sid=$sid
```
=== "Python"
**Domain**
``` python
import requests
domain = 'allowed2.com'
url = 'http://pi.hole:8080/api/domains/allow/exact/' + domain
sid = '<valid session id>'
data = {"sid": sid}
response = requests.delete(url, json=data)
print(response.json())
```
**Regular expression**
``` python
import requests
import urllib
regex = urllib.parse.quote("(^|\\.)facebook.com$")
url = 'http://pi.hole:8080/api/domains/allow/exact/' + regex
sid = '<valid session id>'
data = {"sid": sid}
response = requests.delete(url, json=data)
print(response.json())
```
**Parameters**
None.
??? success "Success response"
Response code: `HTTP/1.1 204 No Content`
??? failure "Error response"
Response code: `HTTP/1.1 400 - Bad Request`
```json
{
"error": {
"key": "database_error",
"message": "attempt to write a readonly databas",
"data": {
"argument": "allowed2.com",
"sql_msg": "Database not available"
}
}
}
```
<!-- markdownlint-enable code-block-style -->
{!abbreviations.md!}

View File

@@ -1,5 +0,0 @@
# API Documentation
This topic is still to be written...
{!abbreviations.md!}

View File

@@ -125,24 +125,8 @@ nav:
- 'Overview': database/gravity/index.md
- 'Group management': database/gravity/groups.md
- 'Database recovery': database/gravity/recovery.md
- 'Examples': database/gravity/example.md
- 'Pi-hole API':
- 'Overview': api/index.md
- 'Authentication': api/auth.md
- 'DNS':
- 'Blocking status': api/dns/blocking.md
- 'Cache information': api/dns/cache.md
- 'Domains': api/domains.md
- 'Network': api/tbd.md
- 'Logs': api/tbd.md
- 'Statistics':
- 'Summary': api/tbd.md
- 'Over time': api/tbd.md
- 'Upstreams': api/tbd.md
- 'Top Items': api/tbd.md
- 'History': api/tbd.md
- 'Version': api/tbd.md
- 'Settings': api/tbd.md
- 'FTLDNS':
- 'Overview': ftldns/index.md
- 'Configuration': ftldns/configfile.md
@@ -153,7 +137,6 @@ nav:
- 'dnsmasq warnings': ftldns/dnsmasq_warn.md
- 'Advanced':
- 'Install from source': ftldns/compile.md
- 'Telnet API': ftldns/telnet-api.md
- 'Signals': 'ftldns/signals.md'
- 'Cache dump': ftldns/cache_dump.md
- 'Packet dump': ftldns/package_dump.md
@@ -170,7 +153,6 @@ nav:
- "Tutorial": regex/tutorial.md
- "Pi-hole extensions": regex/pi-hole.md
- "Approximate matching": regex/approximate.md
- 'Compatibility': ftldns/compatibility.md
- 'Install from source': ftldns/compile.md
- 'Debugging FTLDNS': ftldns/debugging.md
- 'In-depth manual': ftldns/in-depth.md