Merge pull request #1653 from pi-hole/tweak/api_auth_https

Add /api/info/login
This commit is contained in:
DL6ER 2023-10-10 20:36:04 +02:00 committed by GitHub
commit 80d4a0efec
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 101 additions and 24 deletions

View File

@ -44,6 +44,7 @@ static struct {
{ "/api/groups", "/{name}", api_list, { false, true, 0 }, true, HTTP_GET | HTTP_POST | HTTP_PUT | HTTP_DELETE },
{ "/api/lists", "/{list}", api_list, { false, true, 0 }, true, HTTP_GET | HTTP_POST | HTTP_PUT | HTTP_DELETE },
{ "/api/info/client", "", api_info_client, { false, true, 0 }, false, HTTP_GET },
{ "/api/info/login", "", api_info_login, { false, true, 0 }, false, HTTP_GET },
{ "/api/info/system", "", api_info_system, { false, true, 0 }, true, HTTP_GET },
{ "/api/info/database", "", api_info_database, { false, true, 0 }, true, HTTP_GET },
{ "/api/info/sensors", "", api_info_sensors, { false, true, 0 }, true, HTTP_GET },

View File

@ -60,6 +60,7 @@ int api_info_version(struct ftl_conn *api);
int api_info_messages_count(struct ftl_conn *api);
int api_info_messages(struct ftl_conn *api);
int api_info_metrics(struct ftl_conn *api);
int api_info_login(struct ftl_conn *api);
// Config methods
int api_config(struct ftl_conn *api);

View File

@ -302,7 +302,6 @@ static int get_all_sessions(struct ftl_conn *api, cJSON *json)
static int get_session_object(struct ftl_conn *api, cJSON *json, const int user_id, const time_t now)
{
cJSON *session = JSON_NEW_OBJECT();
const bool dns = get_blockingstatus() != DNS_FAILED;
// Authentication not needed
if(user_id == API_AUTH_LOCALHOST || user_id == API_AUTH_EMPTYPASS)
@ -312,7 +311,6 @@ static int get_session_object(struct ftl_conn *api, cJSON *json, const int user_
JSON_ADD_NULL_TO_OBJECT(session, "sid");
JSON_ADD_NUMBER_TO_OBJECT(session, "validity", -1);
JSON_ADD_ITEM_TO_OBJECT(json, "session", session);
JSON_ADD_BOOL_TO_OBJECT(json, "dns", dns);
return 0;
}
@ -325,7 +323,6 @@ static int get_session_object(struct ftl_conn *api, cJSON *json, const int user_
JSON_REF_STR_IN_OBJECT(session, "csrf", auth_data[user_id].csrf);
JSON_ADD_NUMBER_TO_OBJECT(session, "validity", auth_data[user_id].valid_until - now);
JSON_ADD_ITEM_TO_OBJECT(json, "session", session);
JSON_ADD_BOOL_TO_OBJECT(json, "dns", dns);
return 0;
}
@ -335,7 +332,6 @@ static int get_session_object(struct ftl_conn *api, cJSON *json, const int user_
JSON_ADD_NULL_TO_OBJECT(session, "sid");
JSON_ADD_NUMBER_TO_OBJECT(session, "validity", -1);
JSON_ADD_ITEM_TO_OBJECT(json, "session", session);
JSON_ADD_BOOL_TO_OBJECT(json, "dns", dns);
return 0;
}

View File

@ -26,8 +26,6 @@ components:
$ref: 'auth.yaml#/components/examples/no_login_required'
login_required:
$ref: 'auth.yaml#/components/examples/login_required'
dns_failure:
$ref: 'auth.yaml#/components/examples/dns_failure'
post:
summary: Submit password for login
tags:
@ -157,6 +155,7 @@ components:
tags:
- Authentication
operationId: "get_auth_totp"
security: []
description: Suggest new TOTP credentials for two-factor authentication (2FA)
responses:
'200':
@ -245,9 +244,6 @@ components:
validity:
type: integer
description: Remaining lifetime of this session unless refreshed (seconds)
dns:
type: boolean
description: Whether the DNS server is up and running. False only in failed state
password:
type: object
@ -371,7 +367,6 @@ components:
sid: null
csrf: null
validity: 300
dns: true
no_login_required:
summary: No login required for this client
value:
@ -381,7 +376,6 @@ components:
sid: null
csrf: null
validity: -1
dns: true
login_required:
summary: Login required
value:
@ -391,7 +385,6 @@ components:
sid: null
csrf: null
validity: -1
dns: true
login_failed:
summary: Login failed
value:
@ -401,17 +394,6 @@ components:
sid: null
csrf: null
validity: -1
dns: true
dns_failure:
summary: DNS server failure
value:
session:
valid: false
totp: false
sid: null
csrf: null
validity: -1
dns: false
errors:
no_payload:
summary: Bad request (no valid JSON payload)

View File

@ -6,6 +6,7 @@ components:
summary: Get information about requesting client
tags:
- "FTL information"
security: []
operationId: "get_client"
description: |
The property `timer` may contain additional details concerning a temporary en-/disabling.
@ -278,6 +279,24 @@ components:
allOf:
- $ref: 'common.yaml#/components/errors/unauthorized'
- $ref: 'common.yaml#/components/schemas/took'
login:
get:
summary: Login page related information
tags:
- "FTL information"
operationId: "get_logininfo"
security: []
description: |
This API hook returns information used on the login page to possibly display messages/warnings.
responses:
'200':
description: OK
content:
application/json:
schema:
allOf:
- $ref: 'info.yaml#/components/schemas/login'
- $ref: 'common.yaml#/components/schemas/took'
schemas:
client:
@ -1068,6 +1087,15 @@ components:
type: integer
description: Number of items
example: 42
login:
type: object
properties:
https_port:
type: integer
description: HTTPS port of the Pi-hole webserver (0 if disabled)
dns:
type: boolean
description: Whether the DNS server is up and running. False only in failed state
examples:
errors:
messages:

View File

@ -190,6 +190,9 @@ paths:
/info/metrics:
$ref: 'info.yaml#/components/paths/metrics'
/info/login:
$ref: 'info.yaml#/components/paths/login'
/logs/dnsmasq:
$ref: 'logs.yaml#/components/paths/logs/dnsmasq'

View File

@ -49,6 +49,9 @@
#include <limits.h>
#include "metrics.h"
// get_https_port()
#include "webserver/webserver.h"
// DIR
#include <dirent.h>
@ -1032,3 +1035,15 @@ int api_info_metrics(struct ftl_conn *api)
JSON_ADD_ITEM_TO_OBJECT(json2, "metrics", json);
JSON_SEND_OBJECT(json2);
}
int api_info_login(struct ftl_conn *api)
{
cJSON *json = JSON_NEW_OBJECT();
const bool dns = get_blockingstatus() != DNS_FAILED;
JSON_ADD_BOOL_TO_OBJECT(json, "dns", dns);
JSON_ADD_NUMBER_TO_OBJECT(json, "https_port", get_https_port());
JSON_SEND_OBJECT(json);
}

View File

@ -177,6 +177,52 @@ void FTL_mbed_debug(void *user_param, int level, const char *file, int line, con
log_web("mbedTLS(%s:%d, %d): %.*s", file, line, level, (int)len, message);
}
#define MAXPORTS 8
static struct serverports
{
bool is_secure;
unsigned char protocol; // 1 = IPv4, 2 = IPv4+IPv6, 3 = IPv6
in_port_t port;
} server_ports[MAXPORTS] = { 0 };
static in_port_t https_port = 0;
static void get_server_ports(void)
{
if(ctx == NULL)
return;
// Loop over all listening ports
struct mg_server_port mgports[MAXPORTS] = { 0 };
if(mg_get_server_ports(ctx, MAXPORTS, mgports) > 0)
{
// Loop over all ports
for(unsigned int i = 0; i < MAXPORTS; i++)
{
// Stop if no more ports are configured
if(mgports[i].protocol == 0)
break;
// Store port information
server_ports[i].port = mgports[i].port;
server_ports[i].is_secure = mgports[i].is_ssl;
server_ports[i].protocol = mgports[i].protocol;
// Store HTTPS port if not already set
if(mgports[i].is_ssl && https_port == 0)
https_port = mgports[i].port;
// Print port information
log_debug(DEBUG_API, "Listening on port %d (HTTP%s, IPv%s)",
mgports[i].port, mgports[i].is_ssl ? "S" : "",
mgports[i].protocol == 1 ? "4" : (mgports[i].protocol == 3 ? "6" : "4+6"));
}
}
}
in_port_t __attribute__((pure)) get_https_port(void)
{
return https_port;
}
void http_init(void)
{
log_web("Initializing HTTP server on port %s", config.webserver.port.v.s);
@ -311,6 +357,9 @@ void http_init(void)
// Prepare prerequisites for Lua
allocate_lua();
// Get server ports
get_server_ports();
}
static char *append_to_path(char *path, const char *append)

View File

@ -13,4 +13,6 @@
void http_init(void);
void http_terminate(void);
in_port_t get_https_port(void) __attribute__((pure));
#endif // WEBSERVER_H

View File

@ -1266,7 +1266,7 @@
@test "API authorization (without password): No login required" {
run bash -c 'curl -s 127.0.0.1/api/auth'
printf "%s\n" "${lines[@]}"
[[ ${lines[0]} == '{"session":{"valid":true,"totp":false,"sid":null,"validity":-1},"dns":true,"took":'*'}' ]]
[[ ${lines[0]} == '{"session":{"valid":true,"totp":false,"sid":null,"validity":-1},"took":'*'}' ]]
}
@test "API authorization: Setting password" {