mirror of
https://github.com/pi-hole/FTL.git
synced 2024-10-26 16:52:18 +02:00
Embed API documentation into FTL. This ensures it is (a) always available locally, and (b) always corresponds to the API you have available locally.
Signed-off-by: DL6ER <dl6er@dl6er.de>
This commit is contained in:
@@ -22,3 +22,6 @@ version~
|
||||
# MAC->Vendor database files
|
||||
tools/manuf.data
|
||||
tools/macvendor.db
|
||||
|
||||
# Documentation files generated by cmake
|
||||
src/api/docs/hex
|
||||
|
||||
@@ -18,6 +18,9 @@ if [[ "${1}" == "clean" ]]; then
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Remove possibly generated api/docs elements
|
||||
rm -rf src/api/docs/hex
|
||||
|
||||
# Configure build, pass CMake CACHE entries if present
|
||||
# Wrap multiple options in "" as first argument to ./build.sh:
|
||||
# ./build.sh "-DA=1 -DB=2" install
|
||||
@@ -29,13 +32,12 @@ else
|
||||
cmake ..
|
||||
fi
|
||||
|
||||
# Build the sources
|
||||
cmake --build . -- -j $(nproc)
|
||||
|
||||
# If we are asked to install, we do this here
|
||||
# Otherwise, we simply copy the binary one level up
|
||||
# Otherwise, we simply build the sources and copy the binary one level up
|
||||
if [[ "${1}" == "install" || "${2}" == "install" ]]; then
|
||||
sudo make install
|
||||
sudo make install -j $(nproc)
|
||||
else
|
||||
# Build the sources
|
||||
make -j $(nproc)
|
||||
cp pihole-FTL ../
|
||||
fi
|
||||
|
||||
@@ -170,6 +170,7 @@ add_dependencies(FTL gen_version)
|
||||
add_executable(pihole-FTL
|
||||
$<TARGET_OBJECTS:FTL>
|
||||
$<TARGET_OBJECTS:api>
|
||||
$<TARGET_OBJECTS:api_docs>
|
||||
$<TARGET_OBJECTS:webserver>
|
||||
$<TARGET_OBJECTS:ph7_ext>
|
||||
$<TARGET_OBJECTS:civetweb>
|
||||
|
||||
@@ -27,3 +27,4 @@ add_library(api OBJECT ${sources})
|
||||
add_dependencies(api gen_version)
|
||||
target_compile_options(api PRIVATE ${EXTRAWARN})
|
||||
target_include_directories(api PRIVATE ${PROJECT_SOURCE_DIR}/src)
|
||||
add_subdirectory(docs)
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
# Pi-hole: A black hole for Internet advertisements
|
||||
# (c) 2021 Pi-hole, LLC (https://pi-hole.net)
|
||||
# Network-wide ad blocking via your own hardware.
|
||||
#
|
||||
# FTL Engine
|
||||
# /src/api/docs/CMakeList.txt
|
||||
#
|
||||
# This file is copyright under the latest version of the EUPL.
|
||||
# Please see LICENSE file for your rights under this license.
|
||||
|
||||
set(sources
|
||||
hex/index.html
|
||||
hex/index.css
|
||||
hex/external/rapidoc-min.js
|
||||
hex/external/rapidoc-min.js.map
|
||||
hex/external/highlight.min.js
|
||||
hex/external/highlight-default.min.css
|
||||
hex/images/logo.svg
|
||||
hex/specs/main.yaml
|
||||
hex/specs/domains.yaml
|
||||
hex/specs/groups.yaml
|
||||
hex/specs/clients.yaml
|
||||
hex/specs/lists.yaml
|
||||
docs.c
|
||||
)
|
||||
|
||||
# Create relevant directories for processed content
|
||||
file(MAKE_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/hex)
|
||||
file(MAKE_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/hex/specs)
|
||||
file(MAKE_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/hex/images)
|
||||
file(MAKE_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/hex/external)
|
||||
|
||||
find_program(RESOURCE_COMPILER xxd)
|
||||
file(GLOB_RECURSE COMPILED_RESOURCES RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}/content" "content/*")
|
||||
foreach(INPUT_FILE ${COMPILED_RESOURCES})
|
||||
set(IN ${CMAKE_CURRENT_SOURCE_DIR}/content/${INPUT_FILE})
|
||||
set(OUTPUT_FILE ${CMAKE_CURRENT_SOURCE_DIR}/hex/${INPUT_FILE})
|
||||
add_custom_command(
|
||||
OUTPUT hex/${INPUT_FILE}
|
||||
COMMAND ${RESOURCE_COMPILER} -i < ${IN} > ${OUTPUT_FILE}
|
||||
COMMENT "Compiling ${INPUT_FILE} to binary"
|
||||
VERBATIM)
|
||||
list(APPEND COMPILED_RESOURCES ${OUTPUT_FILE})
|
||||
endforeach()
|
||||
|
||||
add_library(api_docs OBJECT ${sources})
|
||||
#target_compile_options(api_docs PRIVATE ${EXTRAWARN})
|
||||
target_include_directories(api_docs PRIVATE ${PROJECT_SOURCE_DIR}/src)
|
||||
@@ -0,0 +1 @@
|
||||
.hljs{display:block;overflow-x:auto;padding:.5em;background:#F0F0F0}.hljs,.hljs-subst{color:#444}.hljs-comment{color:#888888}.hljs-keyword,.hljs-attribute,.hljs-selector-tag,.hljs-meta-keyword,.hljs-doctag,.hljs-name{font-weight:bold}.hljs-type,.hljs-string,.hljs-number,.hljs-selector-id,.hljs-selector-class,.hljs-quote,.hljs-template-tag,.hljs-deletion{color:#880000}.hljs-title,.hljs-section{color:#880000;font-weight:bold}.hljs-regexp,.hljs-symbol,.hljs-variable,.hljs-template-variable,.hljs-link,.hljs-selector-attr,.hljs-selector-pseudo{color:#BC6060}.hljs-literal{color:#78A960}.hljs-built_in,.hljs-bullet,.hljs-code,.hljs-addition{color:#397300}.hljs-meta{color:#1f7199}.hljs-meta-string{color:#4d99bf}.hljs-emphasis{font-style:italic}.hljs-strong{font-weight:bold}
|
||||
File diff suppressed because one or more lines are too long
+220
File diff suppressed because one or more lines are too long
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"rapidoc-min.js","sources":["webpack:///rapidoc-min.js"],"mappings":";;;;;AAMA;;;;;;;;AAwvSA;;;;;;;AA2oBA;;;;;;;;;;;;;;;;;;;;;;;;;;;AAw3dA;;;;;;AAktBA;;;;;;;;;;;;;AA4ogBA;;;;;;;;;;;;;;AAmYA;;;;;;;;;;;;;;AAiGA;;;;;;;;;;;;;AAsIA;;;;;;;;;;;;;;AAsHA;;;;;;;;;;;;;AAqcA;;;;;;;;;;;;;AAgIA;;;;;;;;;;;;;;AAjCA;;;;;;;;;;;;;AAkFA;;;;;;;;;;;AA22CA;;;;;;;;;;;;;;AAmIA;;;;;;AA6zEA;;;;;;;;;;;;;AA49HA","sourceRoot":""}
|
||||
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 88.32 129.93"><defs><linearGradient id="New_Gradient_Swatch_1" x1="2.71" x2="69.77" y1="20.04" y2="20.04" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#12b212"/><stop offset="1" stop-color="#0f0"/></linearGradient><style>.cls-2{fill:#980200}.cls-3{fill:red}</style></defs><title>NewVortex</title><path fill="url(#New_Gradient_Swatch_1)" d="M36.56 39.93C20.34 38.2 4 25.94 2.71 0c25.17 0 38.63 14.9 39.93 38.51 4.76-28.32 27.07-25 27.07-25 1.06 16.05-12.12 25.78-27.07 26.59-4.2-8.85-29.36-30.56-29.36-30.56a.07.07 0 00-.11.08s24.28 21.15 23.39 30.31"/><path d="M44.16 129.93c-1.57-.09-16.22-.65-17.11-17.11-.72-10 7.18-17.37 7.18-27.08C32.44 61.53 0 64.53 0 85.74a19.94 19.94 0 005.83 14.14L30 124.06a19.94 19.94 0 0014.14 5.83" class="cls-2"/><path d="M88.32 85.75c-.09 1.57-.65 16.22-17.11 17.11-10 .72-17.38-7.18-27.08-7.18-24.21 1.79-21.21 34.22 0 34.22a19.94 19.94 0 0014.14-5.83L82.46 99.9a19.94 19.94 0 005.83-14.14" class="cls-3"/><path d="M44.16 41.59c1.57.09 16.22.65 17.11 17.11.72 10-7.18 17.37-7.18 27.08 1.79 24.21 34.22 21.21 34.22 0a19.94 19.94 0 00-5.83-14.14L58.3 47.45a19.94 19.94 0 00-14.14-5.83" class="cls-2"/><path d="M.08 85.75c.09-1.57.65-16.22 17.11-17.11 10-.72 17.38 7.18 27.08 7.18 24.21-1.82 21.21-34.22 0-34.22a19.94 19.94 0 00-14.14 5.83L5.94 71.61A19.94 19.94 0 00.11 85.75" class="cls-3"/></svg>
|
||||
|
After Width: | Height: | Size: 1.4 KiB |
@@ -0,0 +1,26 @@
|
||||
|
||||
.btn {
|
||||
width: 90px;
|
||||
height: 32px;
|
||||
padding:2px;
|
||||
font-size:13px;
|
||||
background-color: #47AFE8;
|
||||
color: #fff;
|
||||
border: none;
|
||||
margin: 0 2px;
|
||||
border-radius: 2px;
|
||||
cursor:pointer;
|
||||
outline:none;
|
||||
}
|
||||
.btn.large {
|
||||
width: 120px;
|
||||
height: 24px
|
||||
}
|
||||
.btn.medium {
|
||||
width: 75px;
|
||||
height: 24px
|
||||
}
|
||||
.btn.small {
|
||||
width: 60px;
|
||||
height: 24px
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width,minimum-scale=1,initial-scale=1,user-scalable=yes">
|
||||
<title>Pi-hole API documentation</title>
|
||||
<!--<link href="https://fonts.googleapis.com/css?family=Open+Sans:300,600&display=swap" rel="stylesheet">-->
|
||||
<link rel="stylesheet" href="external/highlight_default.min.css">
|
||||
<script src="external/highlight.min.js"></script>
|
||||
<script type='text/javascript' src='external/rapidoc-min.js'></script>
|
||||
<link href='index.css' rel='stylesheet'>
|
||||
</head>
|
||||
<body>
|
||||
<rapi-doc id = "thedoc"
|
||||
spec-url = "specs/main.yaml"
|
||||
allow-server-selection = "true"
|
||||
allow-authentication = "false"
|
||||
allow-spec-url-load = "false"
|
||||
allow-spec-file-load = "false"
|
||||
show-header = "true"
|
||||
show-info = "true"
|
||||
theme = "dark"
|
||||
allow-try = "true"
|
||||
sort-endpoints-by = "path"
|
||||
default-schema-tab = 'example'
|
||||
schema-style = "tree"
|
||||
render-style = "view"
|
||||
primary-color = "#2d87e2"
|
||||
header-color = "#2d87e2">
|
||||
<img slot="logo" style="padding-left: 10px;" src="images/logo.svg" width="20px" />
|
||||
<div slot="header" style="font-weight:700; font-size:32px">Pi-hole API Documentation</div>
|
||||
|
||||
<!-- content at the bottom -->
|
||||
<div slot="footer" style="margin:0; padding:16px 36px; background-color:#2d87e2; color:#fff; text-align:center;">
|
||||
<button class='btn large' onclick="document.getElementById('thedoc').setAttribute('render-style', 'view')" >Default</button>
|
||||
<button class='btn large' onclick="document.getElementById('thedoc').setAttribute('render-style', 'read')" >Reader</button>
|
||||
<button class='btn large' onclick="document.getElementById('thedoc').setAttribute('render-style', 'focused')" >Focused reader</button>
|
||||
</div>
|
||||
</rapi-doc>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,279 @@
|
||||
openapi: 3.0.2
|
||||
components:
|
||||
paths:
|
||||
client:
|
||||
summary: Modify client
|
||||
parameters:
|
||||
- $ref: '#/components/parameters/client'
|
||||
get:
|
||||
summary: Get clients
|
||||
description: |
|
||||
`{client}` is optional. Specifying it will result in only the requested client being returned.
|
||||
|
||||
Valid combinations are:
|
||||
- `/api/clients` (all clients)
|
||||
- `/api/clients/my_client` (client identical to `my_client`)
|
||||
responses:
|
||||
'200':
|
||||
description: Successful operation
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
allOf:
|
||||
- $ref: '#/components/schemas/client'
|
||||
- $ref: '#/components/schemas/name'
|
||||
- $ref: '#/components/schemas/comment'
|
||||
- $ref: '#/components/schemas/groups'
|
||||
- $ref: '#/components/schemas/readonly'
|
||||
put:
|
||||
summary: Replace client
|
||||
description: |
|
||||
Items may be updated by replacing them. `{type}`, `{kind}`, and `{item}` are required.
|
||||
|
||||
Ensure to send all the required parameters (such as `description`) to ensure these properties are retained.
|
||||
The read-only fields `id` and `date_added` are preserved, `date_modified` is automatically updated on success.
|
||||
|
||||
You can move existing items to another list type/kind by `PUT`ting the item to the new destination by specifying the optional fields `oldtype` and `oldkind`. Example:
|
||||
You can use `PUT allow/exact/abc.com` with `oldtype="deny", oldkind="exact"` to change `abc.com` from exact denied to exact allowed. Make sure to always specify *both* values.
|
||||
|
||||
When replacing a regular expression, ensure that `{item}` body is properly URI-escaped.
|
||||
requestBody:
|
||||
description: Callback payload
|
||||
content:
|
||||
'application/json':
|
||||
schema:
|
||||
allOf:
|
||||
- $ref: '#/components/schemas/comment'
|
||||
- $ref: '#/components/schemas/groups'
|
||||
responses:
|
||||
'201':
|
||||
description: Created item
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
allOf:
|
||||
- $ref: '#/components/schemas/client'
|
||||
- $ref: '#/components/schemas/name'
|
||||
- $ref: '#/components/schemas/comment'
|
||||
- $ref: '#/components/schemas/groups'
|
||||
- $ref: '#/components/schemas/readonly'
|
||||
'400':
|
||||
description: Bad request
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
oneOf:
|
||||
- $ref: '#/components/schemas/errors/no_payload'
|
||||
- $ref: '#/components/schemas/errors/item_missing'
|
||||
delete:
|
||||
summary: Delete client
|
||||
description: |
|
||||
*Note:* There will be no content on success.
|
||||
responses:
|
||||
'204':
|
||||
description: Item deleted
|
||||
'400':
|
||||
description: Bad request
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/errors/item_missing'
|
||||
direct:
|
||||
parameters:
|
||||
- $ref: '#/components/parameters/type'
|
||||
- $ref: '#/components/parameters/kind'
|
||||
post:
|
||||
summary: Add new client
|
||||
description: |
|
||||
Creates a new client in the `clients` object. The `{client}` itself is specified in the request body (POST JSON).
|
||||
|
||||
Clients may be described either by their IP addresses (IPv4 and IPv6 are supported),
|
||||
IP subnets (CIDR notation, like `192.168.2.0/24`), their MAC addresses (like `12:34:56:78:9A:BC`), by their hostnames (like `localhost`), or by the interface they are connected to (prefaced with a colon, like `:eth0`).</p>
|
||||
|
||||
Note that client recognition by IP addresses (incl. subnet ranges) is prefered over MAC address, host name or interface recognition as the two latter will only be available after some time.
|
||||
Furthermore, MAC address recognition only works for devices at most one networking hop away from your Pi-hole.
|
||||
|
||||
On success, a new ressource is created at `/clients/{client}`.
|
||||
|
||||
The `database_error` with message `UNIQUE contraint failed` error indicates that this client already exists.
|
||||
parameters:
|
||||
- $ref: '#/components/schemas/client'
|
||||
requestBody:
|
||||
description: Callback payload
|
||||
content:
|
||||
'application/json':
|
||||
schema:
|
||||
allOf:
|
||||
- $ref: '#/components/schemas/client'
|
||||
- $ref: '#/components/schemas/comment'
|
||||
- $ref: '#/components/schemas/groups'
|
||||
responses:
|
||||
'201':
|
||||
description: Created item
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
allOf:
|
||||
- $ref: '#/components/schemas/client'
|
||||
- $ref: '#/components/schemas/name'
|
||||
- $ref: '#/components/schemas/comment'
|
||||
- $ref: '#/components/schemas/groups'
|
||||
- $ref: '#/components/schemas/readonly'
|
||||
'400':
|
||||
description: Bad request
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
oneOf:
|
||||
- $ref: '#/components/schemas/errors/no_payload'
|
||||
- $ref: '#/components/schemas/errors/duplicate'
|
||||
schemas:
|
||||
client:
|
||||
type: object
|
||||
properties:
|
||||
client:
|
||||
description: client IP / MAC / hostname / interface
|
||||
type: string
|
||||
required: true
|
||||
example: 127.0.0.1
|
||||
comment:
|
||||
type: object
|
||||
properties:
|
||||
comment:
|
||||
description: User-provided free-text comment for this client (may be `null` if not specified)
|
||||
type: string
|
||||
required: false
|
||||
x-nullable: true
|
||||
default: null
|
||||
example: Some comment for this client
|
||||
name:
|
||||
type: object
|
||||
properties:
|
||||
name:
|
||||
description: hostname (only available when {client} is an IP address)
|
||||
type: string
|
||||
readOnly: true
|
||||
example: localhost
|
||||
groups:
|
||||
type: object
|
||||
properties:
|
||||
groups:
|
||||
description: Array of group IDs
|
||||
type: array
|
||||
default: [0]
|
||||
required: false
|
||||
items:
|
||||
type: integer
|
||||
enabled:
|
||||
type: object
|
||||
properties:
|
||||
enabled:
|
||||
description: Status of domain
|
||||
type: boolean
|
||||
required: false
|
||||
default: true
|
||||
example: true
|
||||
readonly:
|
||||
type: object
|
||||
summary: Readonly properties of a single client
|
||||
properties:
|
||||
id:
|
||||
description: Database ID
|
||||
type: integer
|
||||
readOnly: true
|
||||
example: 1
|
||||
date_added:
|
||||
description: Unix timestamp of item addition
|
||||
type: integer
|
||||
readOnly: true
|
||||
example: 1611239095
|
||||
date_modified:
|
||||
description: Unix timestamp of last item modification
|
||||
type: integer
|
||||
readOnly: true
|
||||
example: 1611239099
|
||||
errors:
|
||||
item_missing:
|
||||
type: object
|
||||
description: Item to be modified is missing
|
||||
properties:
|
||||
error:
|
||||
type: object
|
||||
properties:
|
||||
key:
|
||||
type: string
|
||||
description: "Machine-readable error type"
|
||||
example: "uri_error"
|
||||
message:
|
||||
type: string
|
||||
description: "Human-readable error message"
|
||||
example: "Invalid request: Specify item in URI"
|
||||
data:
|
||||
type: object
|
||||
properties:
|
||||
action:
|
||||
type: string
|
||||
description: Action as received by the API
|
||||
example: "/api/clients"
|
||||
item:
|
||||
type: string
|
||||
description: Item as received by the API
|
||||
example: ""
|
||||
no_payload:
|
||||
type: object
|
||||
description: No JSON payload found
|
||||
properties:
|
||||
error:
|
||||
type: object
|
||||
properties:
|
||||
key:
|
||||
type: string
|
||||
description: "Machine-readable error type"
|
||||
example: "bad_request"
|
||||
message:
|
||||
type: string
|
||||
description: "Human-readable error message"
|
||||
example: "Invalid request body data (no valid JSON)"
|
||||
data:
|
||||
type: null
|
||||
description: "Additional data (if available)"
|
||||
example: null
|
||||
duplicate:
|
||||
type: object
|
||||
description: Database error
|
||||
properties:
|
||||
error:
|
||||
type: object
|
||||
properties:
|
||||
key:
|
||||
type: string
|
||||
description: "Machine-readable error type"
|
||||
example: "database_error"
|
||||
message:
|
||||
type: string
|
||||
description: "Human-readable error message"
|
||||
example: "Could not add to gravity database"
|
||||
data:
|
||||
type: object
|
||||
properties:
|
||||
item:
|
||||
type: string
|
||||
description: Item as received by the API
|
||||
example: 127.0.0.1
|
||||
comment:
|
||||
type: string
|
||||
description: Comment property as received by the API
|
||||
example: Some comment for this client
|
||||
sql_msg:
|
||||
type: string
|
||||
description: Error returned by the database engine
|
||||
example: "UNIQUE constraint failed: clientlist.client"
|
||||
parameters:
|
||||
client:
|
||||
in: path
|
||||
name: client
|
||||
schema:
|
||||
type: string
|
||||
required: true
|
||||
description: client IP / MAC / hostname / interface
|
||||
example: 127.0.0.1
|
||||
@@ -0,0 +1,437 @@
|
||||
openapi: 3.0.2
|
||||
components:
|
||||
paths:
|
||||
type_kind_domain:
|
||||
summary: Modify domains and regular expressions
|
||||
parameters:
|
||||
- $ref: '#/components/parameters/type'
|
||||
- $ref: '#/components/parameters/kind'
|
||||
- $ref: '#/components/parameters/domain'
|
||||
get:
|
||||
summary: Get domain
|
||||
description: |
|
||||
`{type}`, `{kind}`, and `{domain}` are optional. Specifying any of these may result in only a subset of the available data being returned.
|
||||
|
||||
Valid combinations are:
|
||||
- `/api/domains` (all domains)
|
||||
- `/api/domains/abc.com` (all domains identical to `abc.com`)
|
||||
- `/api/domains/allow` (only allowed domains)
|
||||
- `/api/domains/allow/abc.com` (only allowed domains identical to `abc.com`)
|
||||
- `/api/domains/allow/exact` (only exactly allowed domains)
|
||||
- `/api/domains/allow/exact/abc.com` (only exactly allowed domain identical to `abc.com`)
|
||||
- `/api/domains/allow/regex` (only allowed regex domains)
|
||||
- `/api/domains/allow/regex/abc.com` (only allowed regex domains identical to `abc.com`)
|
||||
- `/api/domains/deny` (only denied domains)
|
||||
- `/api/domains/deny/abc.com` (only denied domains identical to `abc.com`)
|
||||
- `/api/domains/deny/exact` (only exactly denied domains)
|
||||
- `/api/domains/deny/exact/abc.com` (only exactly denied domain identical to `abc.com`)
|
||||
- `/api/domains/deny/regex` (only denied regex domains)
|
||||
- `/api/domains/deny/regex/abc.com` (only denied regex domains identical to `abc.com`)
|
||||
- `/api/domains/exact` (allowed and denied exact domains)
|
||||
- `/api/domains/exact/abc.com` (allowed and denied exact domains identical to `abc.com`)
|
||||
- `/api/domains/regex` (allowed and denied regex domains)
|
||||
- `/api/domains/regex/abc.com` (allowed and denied regex domains identical to `abc.com`)
|
||||
responses:
|
||||
'200':
|
||||
description: Successful operation
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
allOf:
|
||||
- $ref: '#/components/schemas/domain'
|
||||
- $ref: '#/components/schemas/oldtype'
|
||||
- $ref: '#/components/schemas/oldkind'
|
||||
- $ref: '#/components/schemas/comment'
|
||||
- $ref: '#/components/schemas/groups'
|
||||
- $ref: '#/components/schemas/enabled'
|
||||
- $ref: '#/components/schemas/readonly'
|
||||
put:
|
||||
summary: Replace domain
|
||||
description: |
|
||||
Items may be updated by replacing them. `{type}`, `{kind}`, and `{domain}` are required.
|
||||
|
||||
Ensure to send all the required parameters (such as `comment`) to ensure these properties are retained.
|
||||
The read-only fields `id` and `date_added` are preserved, `date_modified` is automatically updated on success.
|
||||
|
||||
You can move existing domains to another list type/kind by `PUT`ting the domain to the new destination by specifying the optional fields `oldtype` and `oldkind`. Example:
|
||||
You can use `PUT allow/exact/abc.com` with `oldtype="deny", oldkind="exact"` to change `abc.com` from exact denied to exact allowed. Make sure to always specify *both* values.
|
||||
|
||||
When adding/replacing a regular expression, ensure that `{domain}` is properly URI-escaped.
|
||||
requestBody:
|
||||
description: Callback payload
|
||||
content:
|
||||
'application/json':
|
||||
schema:
|
||||
allOf:
|
||||
- $ref: '#/components/schemas/oldtype'
|
||||
- $ref: '#/components/schemas/oldkind'
|
||||
- $ref: '#/components/schemas/comment'
|
||||
- $ref: '#/components/schemas/groups'
|
||||
- $ref: '#/components/schemas/enabled'
|
||||
responses:
|
||||
'201':
|
||||
description: Created domain
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
allOf:
|
||||
- $ref: '#/components/schemas/domain'
|
||||
- $ref: '#/components/schemas/oldtype'
|
||||
- $ref: '#/components/schemas/oldkind'
|
||||
- $ref: '#/components/schemas/comment'
|
||||
- $ref: '#/components/schemas/groups'
|
||||
- $ref: '#/components/schemas/enabled'
|
||||
- $ref: '#/components/schemas/readonly'
|
||||
'400':
|
||||
description: Bad request
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
oneOf:
|
||||
- $ref: '#/components/schemas/errors/list_imprecise'
|
||||
- $ref: '#/components/schemas/errors/no_payload'
|
||||
- $ref: '#/components/schemas/errors/item_missing'
|
||||
- $ref: '#/components/schemas/errors/invalid_regex'
|
||||
delete:
|
||||
summary: Delete domain
|
||||
description: |
|
||||
*Note:* There will be no content on success.
|
||||
responses:
|
||||
'204':
|
||||
description: Item deleted
|
||||
'400':
|
||||
description: Bad request
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
oneOf:
|
||||
- $ref: '#/components/schemas/errors/list_imprecise'
|
||||
- $ref: '#/components/schemas/errors/item_missing'
|
||||
type_kind:
|
||||
parameters:
|
||||
- $ref: '#/components/parameters/type'
|
||||
- $ref: '#/components/parameters/kind'
|
||||
post:
|
||||
summary: Add new domain
|
||||
description: |
|
||||
Creates a new domain in the `domains` object. This may be either an exact domain or a regex, depending on `{kind}`.
|
||||
Both `{type}` and `{kind}` are mandatory for this endpoint.
|
||||
The `{domain}` itself is specified in the request body (POST JSON).
|
||||
|
||||
On success, a new ressource is created at `/domains/{type}/{kind}/{domain}`.
|
||||
|
||||
The `database_error` with message `UNIQUE contraint failed` error indicates that the same entry (`domain`, `type`, `kind`) already exists.
|
||||
|
||||
When adding a regular expression, ensure the request body is properly JSON-escaped.
|
||||
parameters:
|
||||
- $ref: '#/components/schemas/domain'
|
||||
requestBody:
|
||||
description: Callback payload
|
||||
content:
|
||||
'application/json':
|
||||
schema:
|
||||
allOf:
|
||||
- $ref: '#/components/schemas/domain'
|
||||
- $ref: '#/components/schemas/type'
|
||||
- $ref: '#/components/schemas/kind'
|
||||
- $ref: '#/components/schemas/comment'
|
||||
- $ref: '#/components/schemas/groups'
|
||||
- $ref: '#/components/schemas/enabled'
|
||||
responses:
|
||||
'201':
|
||||
description: Created domain
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
allOf:
|
||||
- $ref: '#/components/schemas/domain'
|
||||
- $ref: '#/components/schemas/type'
|
||||
- $ref: '#/components/schemas/kind'
|
||||
- $ref: '#/components/schemas/comment'
|
||||
- $ref: '#/components/schemas/groups'
|
||||
- $ref: '#/components/schemas/enabled'
|
||||
- $ref: '#/components/schemas/readonly'
|
||||
'400':
|
||||
description: Bad request
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
oneOf:
|
||||
- $ref: '#/components/schemas/errors/list_imprecise'
|
||||
- $ref: '#/components/schemas/errors/no_payload'
|
||||
- $ref: '#/components/schemas/errors/duplicate'
|
||||
- $ref: '#/components/schemas/errors/invalid_regex'
|
||||
schemas:
|
||||
domain:
|
||||
type: object
|
||||
properties:
|
||||
domain:
|
||||
description: Domain
|
||||
type: string
|
||||
required: true
|
||||
example: testdomain.com
|
||||
type:
|
||||
type: object
|
||||
properties:
|
||||
type:
|
||||
description: String specifying domain type
|
||||
type: enum
|
||||
required: true
|
||||
enum:
|
||||
- allow
|
||||
- deny
|
||||
example: allow
|
||||
oldtype:
|
||||
type: object
|
||||
summary: Extra property needed when moving an domain between types and/or kinds
|
||||
properties:
|
||||
oldtype:
|
||||
description: Type of domain *before* moving
|
||||
type: enum
|
||||
required: false
|
||||
enum:
|
||||
- allow
|
||||
- deny
|
||||
example: allow
|
||||
kind:
|
||||
type: object
|
||||
properties:
|
||||
kind:
|
||||
description: String specifying domain kind
|
||||
type: enum
|
||||
required: true
|
||||
enum:
|
||||
- exact
|
||||
- regex
|
||||
example: exact
|
||||
oldkind:
|
||||
type: object
|
||||
summary: Extra property needed when moving an domain between types and/or kinds
|
||||
properties:
|
||||
oldkind:
|
||||
description: Kind of domain *before* moving
|
||||
type: enum
|
||||
required: false
|
||||
enum:
|
||||
- exact
|
||||
- regex
|
||||
example: exact
|
||||
comment:
|
||||
type: object
|
||||
properties:
|
||||
comment:
|
||||
description: User-provided free-text comment for this domain (may be `null` if not specified)
|
||||
type: string
|
||||
required: false
|
||||
x-nullable: true
|
||||
default: null
|
||||
example: Some comment describing this domain
|
||||
groups:
|
||||
type: object
|
||||
properties:
|
||||
groups:
|
||||
description: Array of group IDs
|
||||
type: array
|
||||
default: [0]
|
||||
required: false
|
||||
items:
|
||||
type: integer
|
||||
enabled:
|
||||
type: object
|
||||
properties:
|
||||
enabled:
|
||||
description: Status of domain
|
||||
type: boolean
|
||||
required: false
|
||||
default: true
|
||||
example: true
|
||||
readonly:
|
||||
type: object
|
||||
summary: Readonly properties of a domain
|
||||
properties:
|
||||
id:
|
||||
description: Database ID
|
||||
type: integer
|
||||
readOnly: true
|
||||
example: 1
|
||||
date_added:
|
||||
description: Unix timestamp of domain addition
|
||||
type: integer
|
||||
readOnly: true
|
||||
example: 1611239095
|
||||
date_modified:
|
||||
description: Unix timestamp of last domain modification
|
||||
type: integer
|
||||
readOnly: true
|
||||
example: 1611239099
|
||||
errors:
|
||||
list_imprecise:
|
||||
type: object
|
||||
description: List not specified precisely enough
|
||||
properties:
|
||||
error:
|
||||
type: object
|
||||
properties:
|
||||
key:
|
||||
type: string
|
||||
description: "Machine-readable error type"
|
||||
example: "bad_request"
|
||||
message:
|
||||
type: string
|
||||
description: "Human-readable error message"
|
||||
example: "Invalid request: Specify list to modify more precisely"
|
||||
data:
|
||||
type: object
|
||||
properties:
|
||||
action:
|
||||
type: string
|
||||
description: Action as received by the API
|
||||
example: "/api/domains/allow"
|
||||
item:
|
||||
type: string
|
||||
description: Item as received by the API
|
||||
example: "testdomain.com"
|
||||
item_missing:
|
||||
type: object
|
||||
description: Item to be modified is missing
|
||||
properties:
|
||||
error:
|
||||
type: object
|
||||
properties:
|
||||
key:
|
||||
type: string
|
||||
description: "Machine-readable error type"
|
||||
example: "uri_error"
|
||||
message:
|
||||
type: string
|
||||
description: "Human-readable error message"
|
||||
example: "Invalid request: Specify item in URI"
|
||||
data:
|
||||
type: object
|
||||
properties:
|
||||
action:
|
||||
type: string
|
||||
description: Action as received by the API
|
||||
example: "/api/domains/allow/exact"
|
||||
item:
|
||||
type: string
|
||||
description: Item as received by the API
|
||||
example: ""
|
||||
no_payload:
|
||||
type: object
|
||||
description: No JSON payload found
|
||||
properties:
|
||||
error:
|
||||
type: object
|
||||
properties:
|
||||
key:
|
||||
type: string
|
||||
description: "Machine-readable error type"
|
||||
example: "bad_request"
|
||||
message:
|
||||
type: string
|
||||
description: "Human-readable error message"
|
||||
example: "Invalid request body data (no valid JSON)"
|
||||
data:
|
||||
type: null
|
||||
description: "Additional data (if available)"
|
||||
example: null
|
||||
duplicate:
|
||||
type: object
|
||||
description: Database error
|
||||
properties:
|
||||
error:
|
||||
type: object
|
||||
properties:
|
||||
key:
|
||||
type: string
|
||||
description: "Machine-readable error type"
|
||||
example: "database_error"
|
||||
message:
|
||||
type: string
|
||||
description: "Human-readable error message"
|
||||
example: "Could not add to gravity database"
|
||||
data:
|
||||
type: object
|
||||
properties:
|
||||
domain:
|
||||
type: string
|
||||
description: Item as received by the API
|
||||
example: "testdomain.com"
|
||||
enabled:
|
||||
type: boolean
|
||||
description: Enabled property as received by the API
|
||||
example: true
|
||||
comment:
|
||||
type: string
|
||||
description: Comment property as received by the API
|
||||
example: Some comment describing this domain
|
||||
sql_msg:
|
||||
type: string
|
||||
description: Error returned by the database engine
|
||||
example: "UNIQUE constraint failed: domainlist.domain"
|
||||
invalid_regex:
|
||||
type: object
|
||||
description: Invalid regex rejected
|
||||
properties:
|
||||
error:
|
||||
type: object
|
||||
properties:
|
||||
key:
|
||||
type: string
|
||||
description: "Machine-readable error type"
|
||||
example: "regex_error"
|
||||
message:
|
||||
type: string
|
||||
description: "Human-readable error message"
|
||||
example: "Regex validation failed"
|
||||
data:
|
||||
type: object
|
||||
properties:
|
||||
domain:
|
||||
type: string
|
||||
description: Item as received by the API
|
||||
example: "[[[[^"
|
||||
enabled:
|
||||
type: boolean
|
||||
description: Enabled property as received by the API
|
||||
example: true
|
||||
comment:
|
||||
type: string
|
||||
description: Comment property as received by the API
|
||||
example: Some comment describing this domain
|
||||
regex_msg:
|
||||
type: string
|
||||
description: Error returned by the regex engine
|
||||
example: "Missing ']'"
|
||||
parameters:
|
||||
type:
|
||||
in: path
|
||||
description: Type (allowed or denied domain)
|
||||
name: type
|
||||
schema:
|
||||
type: string
|
||||
enum:
|
||||
- allow
|
||||
- deny
|
||||
required: true
|
||||
example: allow
|
||||
kind:
|
||||
in: path
|
||||
name: kind
|
||||
schema:
|
||||
type: string
|
||||
enum:
|
||||
- exact
|
||||
- regex
|
||||
required: true
|
||||
description: Kind (exact domain or regular expression)
|
||||
example: exact
|
||||
domain:
|
||||
in: path
|
||||
name: domain
|
||||
schema:
|
||||
type: string
|
||||
required: true
|
||||
description: Domain
|
||||
example: testdomain.com
|
||||
@@ -0,0 +1,257 @@
|
||||
openapi: 3.0.2
|
||||
components:
|
||||
paths:
|
||||
name:
|
||||
summary: Modify group
|
||||
parameters:
|
||||
- $ref: '#/components/parameters/name'
|
||||
get:
|
||||
summary: Get groups
|
||||
description: |
|
||||
`{name}` is optional. Specifying it will result in only the requested group being returned.
|
||||
|
||||
Valid combinations are:
|
||||
- `/api/groups` (all groups)
|
||||
- `/api/groups/my_group` (group identical to `my_group`)
|
||||
responses:
|
||||
'200':
|
||||
description: Successful operation
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
allOf:
|
||||
- $ref: '#/components/schemas/name'
|
||||
- $ref: '#/components/schemas/comment'
|
||||
- $ref: '#/components/schemas/enabled'
|
||||
- $ref: '#/components/schemas/readonly'
|
||||
put:
|
||||
summary: Replace group
|
||||
description: |
|
||||
Items may be updated by replacing them. `{type}`, `{kind}`, and `{item}` are required.
|
||||
|
||||
Ensure to send all the required parameters (such as `description`) to ensure these properties are retained.
|
||||
The read-only fields `id` and `date_added` are preserved, `date_modified` is automatically updated on success.
|
||||
|
||||
You can move existing items to another list type/kind by `PUT`ting the item to the new destination by specifying the optional fields `oldtype` and `oldkind`. Example:
|
||||
You can use `PUT allow/exact/abc.com` with `oldtype="deny", oldkind="exact"` to change `abc.com` from exact denied to exact allowed. Make sure to always specify *both* values.
|
||||
|
||||
When replacing a regular expression, ensure that `{item}` body is properly URI-escaped.
|
||||
requestBody:
|
||||
description: Callback payload
|
||||
content:
|
||||
'application/json':
|
||||
schema:
|
||||
allOf:
|
||||
- $ref: '#/components/schemas/comment'
|
||||
- $ref: '#/components/schemas/enabled'
|
||||
responses:
|
||||
'201':
|
||||
description: Created item
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
allOf:
|
||||
- $ref: '#/components/schemas/name'
|
||||
- $ref: '#/components/schemas/comment'
|
||||
- $ref: '#/components/schemas/enabled'
|
||||
- $ref: '#/components/schemas/readonly'
|
||||
'400':
|
||||
description: Bad request
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
oneOf:
|
||||
- $ref: '#/components/schemas/errors/no_payload'
|
||||
- $ref: '#/components/schemas/errors/item_missing'
|
||||
delete:
|
||||
summary: Delete group
|
||||
description: |
|
||||
*Note:* There will be no content on success.
|
||||
responses:
|
||||
'204':
|
||||
description: Item deleted
|
||||
'400':
|
||||
description: Bad request
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
oneOf:
|
||||
- $ref: '#/components/schemas/errors/item_missing'
|
||||
direct:
|
||||
parameters:
|
||||
- $ref: '#/components/parameters/type'
|
||||
- $ref: '#/components/parameters/kind'
|
||||
post:
|
||||
summary: Add new group
|
||||
description: |
|
||||
Creates a new group in the `groups` object. The `{group}` itself is specified in the request body (POST JSON).
|
||||
|
||||
On success, a new ressource is created at `/groups/{name}`.
|
||||
|
||||
The `database_error` with message `UNIQUE contraint failed` error indicates that a group with the same name already exists.
|
||||
parameters:
|
||||
- $ref: '#/components/schemas/name'
|
||||
requestBody:
|
||||
description: Callback payload
|
||||
content:
|
||||
'application/json':
|
||||
schema:
|
||||
allOf:
|
||||
- $ref: '#/components/schemas/name'
|
||||
- $ref: '#/components/schemas/comment'
|
||||
- $ref: '#/components/schemas/enabled'
|
||||
responses:
|
||||
'201':
|
||||
description: Created item
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
allOf:
|
||||
- $ref: '#/components/schemas/name'
|
||||
- $ref: '#/components/schemas/comment'
|
||||
- $ref: '#/components/schemas/enabled'
|
||||
- $ref: '#/components/schemas/readonly'
|
||||
'400':
|
||||
description: Bad request
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
oneOf:
|
||||
- $ref: '#/components/schemas/errors/no_payload'
|
||||
- $ref: '#/components/schemas/errors/duplicate'
|
||||
schemas:
|
||||
name:
|
||||
type: object
|
||||
properties:
|
||||
name:
|
||||
description: Group name
|
||||
type: string
|
||||
required: true
|
||||
example: test_group
|
||||
comment:
|
||||
type: object
|
||||
properties:
|
||||
comment:
|
||||
description: User-provided free-text comment for this group (may be `null` if not specified)
|
||||
type: string
|
||||
required: false
|
||||
x-nullable: true
|
||||
default: null
|
||||
example: Some comment for this group
|
||||
enabled:
|
||||
type: object
|
||||
properties:
|
||||
enabled:
|
||||
description: Status of item
|
||||
type: boolean
|
||||
required: false
|
||||
default: true
|
||||
example: true
|
||||
readonly:
|
||||
type: object
|
||||
summary: Readonly properties of a single group
|
||||
properties:
|
||||
id:
|
||||
description: Database ID
|
||||
type: integer
|
||||
readOnly: true
|
||||
example: 1
|
||||
date_added:
|
||||
description: Unix timestamp of item addition
|
||||
type: integer
|
||||
readOnly: true
|
||||
example: 1611239095
|
||||
date_modified:
|
||||
description: Unix timestamp of last item modification
|
||||
type: integer
|
||||
readOnly: true
|
||||
example: 1611239099
|
||||
errors:
|
||||
item_missing:
|
||||
type: object
|
||||
description: Item to be modified is missing
|
||||
properties:
|
||||
error:
|
||||
type: object
|
||||
properties:
|
||||
key:
|
||||
type: string
|
||||
description: "Machine-readable error type"
|
||||
example: "uri_error"
|
||||
message:
|
||||
type: string
|
||||
description: "Human-readable error message"
|
||||
example: "Invalid request: Specify item in URI"
|
||||
data:
|
||||
type: object
|
||||
properties:
|
||||
action:
|
||||
type: string
|
||||
description: Action as received by the API
|
||||
example: "/api/groups"
|
||||
item:
|
||||
type: string
|
||||
description: Item as received by the API
|
||||
example: ""
|
||||
no_payload:
|
||||
type: object
|
||||
description: No JSON payload found
|
||||
properties:
|
||||
error:
|
||||
type: object
|
||||
properties:
|
||||
key:
|
||||
type: string
|
||||
description: "Machine-readable error type"
|
||||
example: "bad_request"
|
||||
message:
|
||||
type: string
|
||||
description: "Human-readable error message"
|
||||
example: "Invalid request body data (no valid JSON)"
|
||||
data:
|
||||
type: null
|
||||
description: "Additional data (if available)"
|
||||
example: null
|
||||
duplicate:
|
||||
type: object
|
||||
description: Database error
|
||||
properties:
|
||||
error:
|
||||
type: object
|
||||
properties:
|
||||
key:
|
||||
type: string
|
||||
description: "Machine-readable error type"
|
||||
example: "database_error"
|
||||
message:
|
||||
type: string
|
||||
description: "Human-readable error message"
|
||||
example: "Could not add to gravity database"
|
||||
data:
|
||||
type: object
|
||||
properties:
|
||||
item:
|
||||
type: string
|
||||
description: Item as received by the API
|
||||
example: test_group
|
||||
enabled:
|
||||
type: boolean
|
||||
description: Enabled property as received by the API
|
||||
example: true
|
||||
comment:
|
||||
type: string
|
||||
description: Comment property as received by the API
|
||||
example: Some comment for this group
|
||||
sql_msg:
|
||||
type: string
|
||||
description: Error returned by the database engine
|
||||
example: "UNIQUE constraint failed: grouplist.group"
|
||||
parameters:
|
||||
name:
|
||||
in: path
|
||||
name: name
|
||||
schema:
|
||||
type: string
|
||||
required: true
|
||||
description: Group name
|
||||
example: test_group
|
||||
@@ -0,0 +1,280 @@
|
||||
openapi: 3.0.2
|
||||
components:
|
||||
paths:
|
||||
list:
|
||||
summary: Modify list
|
||||
parameters:
|
||||
- $ref: '#/components/parameters/list'
|
||||
get:
|
||||
summary: Get lists
|
||||
description: |
|
||||
`{list}` is optional. Specifying it will result in only the requested list being returned.
|
||||
|
||||
Valid combinations are:
|
||||
- `/api/lists` (all lists)
|
||||
- `/api/lists/my_list` (list identical to `my_list`)
|
||||
responses:
|
||||
'200':
|
||||
description: Successful operation
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
allOf:
|
||||
- $ref: '#/components/schemas/list'
|
||||
- $ref: '#/components/schemas/name'
|
||||
- $ref: '#/components/schemas/comment'
|
||||
- $ref: '#/components/schemas/groups'
|
||||
- $ref: '#/components/schemas/enabled'
|
||||
- $ref: '#/components/schemas/readonly'
|
||||
put:
|
||||
summary: Replace list
|
||||
description: |
|
||||
Items may be updated by replacing them. `{type}`, `{kind}`, and `{item}` are required.
|
||||
|
||||
Ensure to send all the required parameters (such as `description`) to ensure these properties are retained.
|
||||
The read-only fields `id` and `date_added` are preserved, `date_modified` is automatically updated on success.
|
||||
|
||||
You can move existing items to another list type/kind by `PUT`ting the item to the new destination by specifying the optional fields `oldtype` and `oldkind`. Example:
|
||||
You can use `PUT allow/exact/abc.com` with `oldtype="deny", oldkind="exact"` to change `abc.com` from exact denied to exact allowed. Make sure to always specify *both* values.
|
||||
|
||||
When replacing a regular expression, ensure that `{item}` body is properly URI-escaped.
|
||||
requestBody:
|
||||
description: Callback payload
|
||||
content:
|
||||
'application/json':
|
||||
schema:
|
||||
allOf:
|
||||
- $ref: '#/components/schemas/comment'
|
||||
- $ref: '#/components/schemas/groups'
|
||||
- $ref: '#/components/schemas/enabled'
|
||||
responses:
|
||||
'201':
|
||||
description: Created item
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
allOf:
|
||||
- $ref: '#/components/schemas/list'
|
||||
- $ref: '#/components/schemas/name'
|
||||
- $ref: '#/components/schemas/comment'
|
||||
- $ref: '#/components/schemas/groups'
|
||||
- $ref: '#/components/schemas/enabled'
|
||||
- $ref: '#/components/schemas/readonly'
|
||||
'400':
|
||||
description: Bad request
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
oneOf:
|
||||
- $ref: '#/components/schemas/errors/no_payload'
|
||||
- $ref: '#/components/schemas/errors/item_missing'
|
||||
delete:
|
||||
summary: Delete list
|
||||
description: |
|
||||
*Note:* There will be no content on success.
|
||||
responses:
|
||||
'204':
|
||||
description: Item deleted
|
||||
'400':
|
||||
description: Bad request
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/errors/item_missing'
|
||||
direct:
|
||||
parameters:
|
||||
- $ref: '#/components/parameters/type'
|
||||
- $ref: '#/components/parameters/kind'
|
||||
post:
|
||||
summary: Add new list
|
||||
description: |
|
||||
Creates a new list in the `lists` object. The `{list}` itself is specified in the request body (POST JSON).
|
||||
|
||||
lists may be described either by their IP addresses (IPv4 and IPv6 are supported),
|
||||
IP subnets (CIDR notation, like `192.168.2.0/24`), their MAC addresses (like `12:34:56:78:9A:BC`), by their hostnames (like `localhost`), or by the interface they are connected to (prefaced with a colon, like `:eth0`).</p>
|
||||
|
||||
Note that list recognition by IP addresses (incl. subnet ranges) is prefered over MAC address, host name or interface recognition as the two latter will only be available after some time.
|
||||
Furthermore, MAC address recognition only works for devices at most one networking hop away from your Pi-hole.
|
||||
|
||||
On success, a new ressource is created at `/lists/{list}`.
|
||||
|
||||
The `database_error` with message `UNIQUE contraint failed` error indicates that this list already exists.
|
||||
parameters:
|
||||
- $ref: '#/components/schemas/list'
|
||||
requestBody:
|
||||
description: Callback payload
|
||||
content:
|
||||
'application/json':
|
||||
schema:
|
||||
allOf:
|
||||
- $ref: '#/components/schemas/list'
|
||||
- $ref: '#/components/schemas/comment'
|
||||
- $ref: '#/components/schemas/groups'
|
||||
- $ref: '#/components/schemas/enabled'
|
||||
responses:
|
||||
'201':
|
||||
description: Created item
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
allOf:
|
||||
- $ref: '#/components/schemas/list'
|
||||
- $ref: '#/components/schemas/name'
|
||||
- $ref: '#/components/schemas/comment'
|
||||
- $ref: '#/components/schemas/groups'
|
||||
- $ref: '#/components/schemas/enabled'
|
||||
- $ref: '#/components/schemas/readonly'
|
||||
'400':
|
||||
description: Bad request
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
oneOf:
|
||||
- $ref: '#/components/schemas/errors/no_payload'
|
||||
- $ref: '#/components/schemas/errors/duplicate'
|
||||
schemas:
|
||||
list:
|
||||
type: object
|
||||
properties:
|
||||
address:
|
||||
description: Address of the list
|
||||
type: string
|
||||
required: true
|
||||
example: https://hosts-file.net/ad_servers.txt
|
||||
comment:
|
||||
type: object
|
||||
properties:
|
||||
comment:
|
||||
description: User-provided free-text comment for this list (may be `null` if not specified)
|
||||
type: string
|
||||
required: false
|
||||
x-nullable: true
|
||||
default: null
|
||||
example: Some comment for this list
|
||||
groups:
|
||||
type: object
|
||||
properties:
|
||||
groups:
|
||||
description: Array of group IDs
|
||||
type: array
|
||||
default: [0]
|
||||
required: false
|
||||
items:
|
||||
type: integer
|
||||
enabled:
|
||||
type: object
|
||||
properties:
|
||||
enabled:
|
||||
description: Status of domain
|
||||
type: boolean
|
||||
required: false
|
||||
default: true
|
||||
example: true
|
||||
readonly:
|
||||
type: object
|
||||
summary: Readonly properties of a single list
|
||||
properties:
|
||||
id:
|
||||
description: Database ID
|
||||
type: integer
|
||||
readOnly: true
|
||||
example: 1
|
||||
date_added:
|
||||
description: Unix timestamp of item addition
|
||||
type: integer
|
||||
readOnly: true
|
||||
example: 1611239095
|
||||
date_modified:
|
||||
description: Unix timestamp of last item modification
|
||||
type: integer
|
||||
readOnly: true
|
||||
example: 1611239099
|
||||
errors:
|
||||
item_missing:
|
||||
type: object
|
||||
description: Item to be modified is missing
|
||||
properties:
|
||||
error:
|
||||
type: object
|
||||
properties:
|
||||
key:
|
||||
type: string
|
||||
description: "Machine-readable error type"
|
||||
example: "uri_error"
|
||||
message:
|
||||
type: string
|
||||
description: "Human-readable error message"
|
||||
example: "Invalid request: Specify item in URI"
|
||||
data:
|
||||
type: object
|
||||
properties:
|
||||
action:
|
||||
type: string
|
||||
description: Action as received by the API
|
||||
example: "/api/lists"
|
||||
item:
|
||||
type: string
|
||||
description: Item as received by the API
|
||||
example: ""
|
||||
no_payload:
|
||||
type: object
|
||||
description: No JSON payload found
|
||||
properties:
|
||||
error:
|
||||
type: object
|
||||
properties:
|
||||
key:
|
||||
type: string
|
||||
description: "Machine-readable error type"
|
||||
example: "bad_request"
|
||||
message:
|
||||
type: string
|
||||
description: "Human-readable error message"
|
||||
example: "Invalid request body data (no valid JSON)"
|
||||
data:
|
||||
type: null
|
||||
description: "Additional data (if available)"
|
||||
example: null
|
||||
duplicate:
|
||||
type: object
|
||||
description: Database error
|
||||
properties:
|
||||
error:
|
||||
type: object
|
||||
properties:
|
||||
key:
|
||||
type: string
|
||||
description: "Machine-readable error type"
|
||||
example: "database_error"
|
||||
message:
|
||||
type: string
|
||||
description: "Human-readable error message"
|
||||
example: "Could not add to gravity database"
|
||||
data:
|
||||
type: object
|
||||
properties:
|
||||
item:
|
||||
type: string
|
||||
description: Item as received by the API
|
||||
example: "https://hosts-file.net/ad_servers.txt"
|
||||
enabled:
|
||||
type: boolean
|
||||
description: Enabled property as received by the API
|
||||
example: true
|
||||
comment:
|
||||
type: string
|
||||
description: Comment property as received by the API
|
||||
example: Some comment for this list
|
||||
sql_msg:
|
||||
type: string
|
||||
description: Error returned by the database engine
|
||||
example: "UNIQUE constraint failed: listlist.list"
|
||||
parameters:
|
||||
list:
|
||||
in: path
|
||||
name: list
|
||||
schema:
|
||||
type: string
|
||||
required: true
|
||||
description: Address of the list
|
||||
example: https://hosts-file.net/ad_servers.txt
|
||||
@@ -0,0 +1,42 @@
|
||||
openapi: 3.0.2
|
||||
info:
|
||||
title: Pi-hole API
|
||||
version: "6.0"
|
||||
description: >
|
||||
The Pi-hole API is organized around [REST](http://en.wikipedia.org/wiki/Representational_State_Transfer). Our API has predictable resource-oriented URLs, accepts and returns reliable UTF-8 [JavaScript Object Notation (JSON)-encoded](http://www.json.org/) data for all API responses, and uses standard HTTP response codes and verbs.
|
||||
Most (but not all) endpoints require authentication. API endpoints requiring authentication will fail with code `401 Unauthorized` if no key is supplied.
|
||||
servers:
|
||||
- url: http://127.0.0.1/api/
|
||||
- url: 'http://{url}:{port}/api/'
|
||||
variables:
|
||||
url:
|
||||
description: URL or address of your Pi-hole
|
||||
default: pi.hole
|
||||
port:
|
||||
description: Port of your Pi-hole's API
|
||||
default: 8080
|
||||
|
||||
paths:
|
||||
/domains/{type}/{kind}/{domain}:
|
||||
$ref: 'domains.yaml#/components/paths/type_kind_domain'
|
||||
|
||||
/domains/{type}/{kind}:
|
||||
$ref: 'domains.yaml#/components/paths/type_kind'
|
||||
|
||||
/groups/{name}:
|
||||
$ref: 'groups.yaml#/components/paths/name'
|
||||
|
||||
/groups:
|
||||
$ref: 'groups.yaml#/components/paths/direct'
|
||||
|
||||
/clients/{client}:
|
||||
$ref: 'clients.yaml#/components/paths/client'
|
||||
|
||||
/clients:
|
||||
$ref: 'clients.yaml#/components/paths/direct'
|
||||
|
||||
/lists/{list}:
|
||||
$ref: 'lists.yaml#/components/paths/list'
|
||||
|
||||
/lists:
|
||||
$ref: 'lists.yaml#/components/paths/direct'
|
||||
@@ -0,0 +1,43 @@
|
||||
/* Pi-hole: A black hole for Internet advertisements
|
||||
* (c) 2021 Pi-hole, LLC (https://pi-hole.net)
|
||||
* Network-wide ad blocking via your own hardware.
|
||||
*
|
||||
* FTL Engine
|
||||
* API Implementation /api/docs
|
||||
*
|
||||
* This file is copyright under the latest version of the EUPL.
|
||||
* Please see LICENSE file for your rights under this license. */
|
||||
|
||||
#include "docs.h"
|
||||
|
||||
int api_docs(struct ftl_conn *api)
|
||||
{
|
||||
// Handle ressource request by redirecting to "/"
|
||||
if(strcmp(api->request->request_uri, "/api/docs") == 0)
|
||||
{
|
||||
mg_send_http_redirect(api->conn, "/api/docs/", 301);
|
||||
}
|
||||
|
||||
// Handle root request by redirecting to "/"
|
||||
bool serve_index = false;
|
||||
if(strcmp(api->request->request_uri, "/api/docs/") == 0)
|
||||
{
|
||||
serve_index = true;
|
||||
}
|
||||
|
||||
// Loop over all available files and see if we can serve this request
|
||||
for(unsigned int i = 0; i < (sizeof(docs_files)/sizeof(docs_files[0])); i++)
|
||||
{
|
||||
// Check if this is the requested file
|
||||
if(strcmp(docs_files[i].path, api->item) == 0 ||
|
||||
(serve_index && strcmp(docs_files[i].path, "index.html") == 0))
|
||||
{
|
||||
// Send the file
|
||||
mg_send_http_ok(api->conn, docs_files[i].mime_type, NULL, docs_files[i].content_size);
|
||||
return mg_write(api->conn, docs_files[i].content, docs_files[i].content_size);
|
||||
}
|
||||
}
|
||||
|
||||
// Requested path was not found
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
/* Pi-hole: A black hole for Internet advertisements
|
||||
* (c) 2021 Pi-hole, LLC (https://pi-hole.net)
|
||||
* Network-wide ad blocking via your own hardware.
|
||||
*
|
||||
* FTL Engine
|
||||
* API Implementation /api/docs (helper)
|
||||
*
|
||||
* This file is copyright under the latest version of the EUPL.
|
||||
* Please see LICENSE file for your rights under this license. */
|
||||
#ifndef API_DOCS_H
|
||||
#define API_DOCS_H
|
||||
|
||||
#include "../../FTL.h"
|
||||
#include "../../civetweb/civetweb.h"
|
||||
#include "../../webserver/http-common.h"
|
||||
#include "../../webserver/json_macros.h"
|
||||
#include "../routes.h"
|
||||
|
||||
static const char index_html[] = {
|
||||
#include "hex/index.html"
|
||||
};
|
||||
|
||||
static const char index_css[] = {
|
||||
#include "hex/index.css"
|
||||
};
|
||||
|
||||
static const char rapidoc_min_js[] = {
|
||||
#include "hex/external/rapidoc-min.js"
|
||||
};
|
||||
|
||||
static const char rapidoc_min_map_js[] = {
|
||||
#include "hex/external/rapidoc-min.js.map"
|
||||
};
|
||||
|
||||
static const char highlight_default_min_css[] = {
|
||||
#include "hex/external/highlight-default.min.css"
|
||||
};
|
||||
|
||||
static const char highlight_min_js[] = {
|
||||
#include "hex/external/highlight.min.js"
|
||||
};
|
||||
|
||||
static const char images_logo_svg[] = {
|
||||
#include "hex/images/logo.svg"
|
||||
};
|
||||
|
||||
static const char specs_main_yaml[] = {
|
||||
#include "hex/specs/main.yaml"
|
||||
};
|
||||
|
||||
static const char specs_domains_yaml[] = {
|
||||
#include "hex/specs/domains.yaml"
|
||||
};
|
||||
|
||||
static const char specs_groups_yaml[] = {
|
||||
#include "hex/specs/groups.yaml"
|
||||
};
|
||||
|
||||
static const char specs_clients_yaml[] = {
|
||||
#include "hex/specs/clients.yaml"
|
||||
};
|
||||
|
||||
static const char specs_lists_yaml[] = {
|
||||
#include "hex/specs/lists.yaml"
|
||||
};
|
||||
|
||||
struct {
|
||||
const char *path;
|
||||
const char *mime_type;
|
||||
const char *content;
|
||||
const size_t content_size;
|
||||
} docs_files[] =
|
||||
{
|
||||
{"index.html", "text/html", index_html, sizeof(index_html)},
|
||||
{"index.css", "text/css", index_css, sizeof(index_css)},
|
||||
{"external/rapidoc-min.js", "application/javascript", rapidoc_min_js, sizeof(rapidoc_min_js)},
|
||||
{"external/rapidoc-min.map.js", "text/plain", rapidoc_min_map_js, sizeof(rapidoc_min_map_js)},
|
||||
{"external/highlight-default.min.css", "text/css", highlight_default_min_css, sizeof(highlight_default_min_css)},
|
||||
{"external/highlight.min.js", "text/css", highlight_min_js, sizeof(highlight_min_js)},
|
||||
{"images/logo.svg", "image/svg+xml", images_logo_svg, sizeof(images_logo_svg)},
|
||||
{"specs/main.yaml", "text/plain", specs_main_yaml, sizeof(specs_main_yaml)},
|
||||
{"specs/domains.yaml", "text/plain", specs_domains_yaml, sizeof(specs_domains_yaml)},
|
||||
{"specs/groups.yaml", "text/plain", specs_groups_yaml, sizeof(specs_groups_yaml)},
|
||||
{"specs/clients.yaml", "text/plain", specs_clients_yaml, sizeof(specs_clients_yaml)},
|
||||
{"specs/lists.yaml", "text/plain", specs_lists_yaml, sizeof(specs_lists_yaml)},
|
||||
};
|
||||
|
||||
|
||||
|
||||
#endif // API_DOCS_H
|
||||
+12
-13
@@ -62,21 +62,21 @@ static int api_list_read(struct ftl_conn *api,
|
||||
}
|
||||
else if(listtype == GRAVITY_CLIENTS)
|
||||
{
|
||||
char *name = NULL;
|
||||
if(table.client != NULL)
|
||||
{
|
||||
JSON_OBJ_COPY_STR(row, "client", table.client);
|
||||
char *name = getNameFromIP(table.client);
|
||||
JSON_OBJ_COPY_STR(row, "name", name);
|
||||
if(name != NULL)
|
||||
free(name);
|
||||
// Try to obtain hostname if this is a valid IP address
|
||||
if(isValidIPv4(table.client) || isValidIPv6(table.client))
|
||||
name = getNameFromIP(table.client);
|
||||
}
|
||||
else
|
||||
{
|
||||
JSON_OBJ_ADD_NULL(row, "ip");
|
||||
JSON_OBJ_ADD_NULL(row, "name");
|
||||
}
|
||||
|
||||
|
||||
JSON_OBJ_COPY_STR(row, "client", table.client);
|
||||
JSON_OBJ_COPY_STR(row, "name", name);
|
||||
JSON_OBJ_COPY_STR(row, "comment", table.comment);
|
||||
|
||||
// Free allocated memory (if applicable)
|
||||
if(name != NULL)
|
||||
free(name);
|
||||
}
|
||||
else // domainlists
|
||||
{
|
||||
@@ -94,7 +94,6 @@ static int api_list_read(struct ftl_conn *api,
|
||||
// the group_concat result delivered from the database,
|
||||
// parse it as valid array and append it as row to the
|
||||
// data
|
||||
logg("table.group_ids = %p \"%s\"", table.group_ids, table.group_ids);
|
||||
char group_ids_str[strlen(table.group_ids)+3u];
|
||||
group_ids_str[0] = '[';
|
||||
strcpy(group_ids_str+1u , table.group_ids);
|
||||
@@ -324,7 +323,7 @@ static int api_list_write(struct ftl_conn *api,
|
||||
{
|
||||
// Error adding item, prepare error object
|
||||
cJSON *json = JSON_NEW_OBJ();
|
||||
JSON_OBJ_REF_STR(json, "item", item);
|
||||
JSON_OBJ_REF_STR(json, "item", row.item);
|
||||
JSON_OBJ_ADD_BOOL(json, "enabled", row.enabled);
|
||||
if(row.comment != NULL)
|
||||
JSON_OBJ_REF_STR(json, "comment", row.comment);
|
||||
|
||||
@@ -178,6 +178,11 @@ int api_handler(struct mg_connection *conn, void *ignored)
|
||||
{
|
||||
ret = api_settings_web(&api);
|
||||
}
|
||||
/******************************** /api/settings ****************************/
|
||||
else if((api.item = startsWith("/api/docs", &api)) != NULL)
|
||||
{
|
||||
ret = api_docs(&api);
|
||||
}
|
||||
/******************************** not found or invalid request**************/
|
||||
if(ret == 0)
|
||||
{
|
||||
|
||||
@@ -68,4 +68,7 @@ int api_auth(struct ftl_conn *api);
|
||||
// Settings methods
|
||||
int api_settings_web(struct ftl_conn *api);
|
||||
|
||||
// Documentation methods
|
||||
int api_docs(struct ftl_conn *api);
|
||||
|
||||
#endif // ROUTES_H
|
||||
|
||||
Reference in New Issue
Block a user