Add new config option webserver.api.session.restore defaulting to true and move existing config option webserver.api.sessionTimeout -> webserver.api.session.timeout

Signed-off-by: DL6ER <dl6er@dl6er.de>
This commit is contained in:
DL6ER 2023-10-22 08:51:11 +02:00
parent 85b5c94858
commit a2a8787239
No known key found for this signature in database
GPG Key ID: 00135ACBD90B28DD
8 changed files with 70 additions and 25 deletions

View File

@ -208,7 +208,7 @@ int check_client_auth(struct ftl_conn *api, const bool is_api)
// Update timestamp of this client to extend
// the validity of their API authentication
auth_data[user_id].valid_until = now + config.webserver.sessionTimeout.v.ui;
auth_data[user_id].valid_until = now + config.webserver.session.timeout.v.ui;
// Set strict_tls permanently to false if the client connected via HTTP
auth_data[user_id].tls.mixed |= api->request->is_ssl != auth_data[user_id].tls.login;
@ -216,7 +216,7 @@ int check_client_auth(struct ftl_conn *api, const bool is_api)
// Update user cookie
if(snprintf(pi_hole_extra_headers, sizeof(pi_hole_extra_headers),
FTL_SET_COOKIE,
auth_data[user_id].sid, config.webserver.sessionTimeout.v.ui) < 0)
auth_data[user_id].sid, config.webserver.session.timeout.v.ui) < 0)
{
return send_json_error(api, 500, "internal_error", "Internal server error", NULL);
}
@ -264,7 +264,7 @@ static int get_all_sessions(struct ftl_conn *api, cJSON *json)
JSON_ADD_BOOL_TO_OBJECT(tls, "mixed", auth_data[i].tls.mixed);
JSON_ADD_ITEM_TO_OBJECT(session, "tls", tls);
JSON_ADD_NUMBER_TO_OBJECT(session, "login_at", auth_data[i].login_at);
JSON_ADD_NUMBER_TO_OBJECT(session, "last_active", auth_data[i].valid_until - config.webserver.sessionTimeout.v.ui);
JSON_ADD_NUMBER_TO_OBJECT(session, "last_active", auth_data[i].valid_until - config.webserver.session.timeout.v.ui);
JSON_ADD_NUMBER_TO_OBJECT(session, "valid_until", auth_data[i].valid_until);
JSON_REF_STR_IN_OBJECT(session, "remote_addr", auth_data[i].remote_addr);
JSON_REF_STR_IN_OBJECT(session, "user_agent", auth_data[i].user_agent);
@ -326,7 +326,7 @@ static void delete_session(const int user_id)
void delete_all_sessions(void)
{
// Delete all sessions from database
delete_all_sessions();
del_all_db_sessions();
// Zero out all sessions without looping
memset(auth_data, 0, sizeof(auth_data));
@ -359,7 +359,7 @@ static int send_api_auth_status(struct ftl_conn *api, const int user_id, const t
// Ten minutes validity
if(snprintf(pi_hole_extra_headers, sizeof(pi_hole_extra_headers),
FTL_SET_COOKIE,
auth_data[user_id].sid, config.webserver.sessionTimeout.d.ui) < 0)
auth_data[user_id].sid, config.webserver.session.timeout.d.ui) < 0)
{
return send_json_error(api, 500, "internal_error", "Internal server error", NULL);
}
@ -540,7 +540,7 @@ int api_auth(struct ftl_conn *api)
auth_data[i].used = true;
// Set validitiy to now + timeout
auth_data[i].login_at = now;
auth_data[i].valid_until = now + config.webserver.sessionTimeout.v.ui;
auth_data[i].valid_until = now + config.webserver.session.timeout.v.ui;
// Set remote address
strncpy(auth_data[i].remote_addr, api->request->remote_addr, sizeof(auth_data[i].remote_addr));
auth_data[i].remote_addr[sizeof(auth_data[i].remote_addr)-1] = '\0';

View File

@ -351,8 +351,13 @@ components:
type: string
port:
type: string
sessionTimeout:
type: integer
session:
type: object
properties:
timeout:
type: integer
restore:
type: boolean
tls:
type: object
properties:
@ -644,7 +649,9 @@ components:
domain: pi.hole
acl: "+0.0.0.0/0,::/0"
port: 80,[::]:80
sessionTimeout: 300
session:
timeout: 300
restore: true
tls:
rev_proxy: false
cert: "/etc/pihole/tls.pem"

View File

@ -847,10 +847,15 @@ void initConfig(struct config *conf)
conf->webserver.tls.cert.t = CONF_STRING;
conf->webserver.tls.cert.d.s = (char*)"/etc/pihole/tls.pem";
conf->webserver.sessionTimeout.k = "webserver.sessionTimeout";
conf->webserver.sessionTimeout.h = "Session timeout in seconds. If a session is inactive for more than this time, it will be terminated. Sessions are continuously refreshed by the web interface, preventing sessions from timing out while the web interface is open.\n This option may also be used to make logins persistent for long times, e.g. 86400 seconds (24 hours), 604800 seconds (7 days) or 2592000 seconds (30 days). Note that the total number of concurrent sessions is limited so setting this value too high may result in users being rejected and unable to log in if there are already too many sessions active.";
conf->webserver.sessionTimeout.t = CONF_UINT;
conf->webserver.sessionTimeout.d.ui = 300u;
conf->webserver.session.timeout.k = "webserver.session.timeout";
conf->webserver.session.timeout.h = "Session timeout in seconds. If a session is inactive for more than this time, it will be terminated. Sessions are continuously refreshed by the web interface, preventing sessions from timing out while the web interface is open.\n This option may also be used to make logins persistent for long times, e.g. 86400 seconds (24 hours), 604800 seconds (7 days) or 2592000 seconds (30 days). Note that the total number of concurrent sessions is limited so setting this value too high may result in users being rejected and unable to log in if there are already too many sessions active.";
conf->webserver.session.timeout.t = CONF_UINT;
conf->webserver.session.timeout.d.ui = 300u;
conf->webserver.session.restore.k = "webserver.session.restore";
conf->webserver.session.restore.h = "Should Pi-hole backup and restore sessions from the database? This is useful if you want to keep your sessions after a restart of the web interface.";
conf->webserver.session.restore.t = CONF_BOOL;
conf->webserver.session.restore.d.b = true;
// sub-struct paths
conf->webserver.paths.webroot.k = "webserver.paths.webroot";

View File

@ -108,6 +108,7 @@ struct enum_options {
// When new config items are added, the following places need to be updated:
// - src/config/config.c: New default item
// - test/pihole.toml: Add the new item to the test config file
// - api/docs/content/specs/config.yml: Add the new item to the API documentation
struct config {
struct {
struct conf_item upstreams;
@ -205,7 +206,10 @@ struct config {
struct conf_item domain;
struct conf_item acl;
struct conf_item port;
struct conf_item sessionTimeout;
struct {
struct conf_item timeout;
struct conf_item restore;
} session;
struct {
struct conf_item rev_proxy;
struct conf_item cert;

View File

@ -314,7 +314,7 @@ const char *readFTLlegacy(struct config *conf)
value = 0;
if(buffer != NULL && sscanf(buffer, "%i", &value) && value > 0)
conf->webserver.sessionTimeout.v.ui = value;
conf->webserver.session.timeout.v.ui = value;
// API_PRETTY_JSON
// defaults to: false

View File

@ -11,6 +11,7 @@
#include "FTL.h"
#include "database/session-table.h"
#include "database/common.h"
#include "config/config.h"
bool create_session_table(sqlite3 *db)
{
@ -44,6 +45,12 @@ bool create_session_table(sqlite3 *db)
// Add session to database
bool add_db_session(struct session *sess)
{
if(!config.webserver.session.restore.v.b)
{
log_debug(DEBUG_API, "Session restore is disabled, not adding session to database");
return true;
}
sqlite3 *db = dbopen(false, false);
if(db == NULL)
{
@ -143,6 +150,9 @@ bool add_db_session(struct session *sess)
// Update valid_until of session in database (by sid)
bool update_db_session(struct session *sess)
{
if(!config.webserver.session.restore.v.b)
return true;
sqlite3 *db = dbopen(false, false);
if(db == NULL)
{
@ -207,6 +217,12 @@ bool update_db_session(struct session *sess)
// Restore all sessions found in the database
bool restore_db_sessions(struct session *sessions)
{
if(!config.webserver.session.restore.v.b)
{
log_debug(DEBUG_API, "Session restore is disabled, not restoring sessions from database");
return true;
}
sqlite3 *db = dbopen(false, false);
if(db == NULL)
{
@ -302,6 +318,9 @@ bool restore_db_sessions(struct session *sessions)
// Delete session from database (by sid)
bool del_db_session(struct session *sess)
{
if(!config.webserver.session.restore.v.b)
return true;
sqlite3 *db = dbopen(false, false);
if(db == NULL)
{
@ -351,6 +370,9 @@ bool del_db_session(struct session *sess)
bool del_all_db_sessions(void)
{
if(!config.webserver.session.restore.v.b)
return true;
sqlite3 *db = dbopen(false, false);
if(db == NULL)
{

View File

@ -522,15 +522,20 @@
# comma-separated list of <[ip_address:]port>
port = "80,[::]:80,443s"
# Session timeout in seconds. If a session is inactive for more than this time, it will
# be terminated. Sessions are continuously refreshed by the web interface, preventing
# sessions from timing out while the web interface is open.
# This option may also be used to make logins persistent for long times, e.g. 86400
# seconds (24 hours), 604800 seconds (7 days) or 2592000 seconds (30 days). Note that
# the total number of concurrent sessions is limited so setting this value too high
# may result in users being rejected and unable to log in if there are already too
# many sessions active.
sessionTimeout = 300
[webserver.session]
# Session timeout in seconds. If a session is inactive for more than this time, it will
# be terminated. Sessions are continuously refreshed by the web interface, preventing
# sessions from timing out while the web interface is open.
# This option may also be used to make logins persistent for long times, e.g. 86400
# seconds (24 hours), 604800 seconds (7 days) or 2592000 seconds (30 days). Note that
# the total number of concurrent sessions is limited so setting this value too high
# may result in users being rejected and unable to log in if there are already too
# many sessions active.
timeout = 300
# Should Pi-hole backup and restore sessions from the database? This is useful if you
# want to keep your sessions after a restart of the web interface.
restore = true
[webserver.tls]
# Is Pi-hole running behind a reverse proxy? If yes, Pi-hole will not consider

View File

@ -453,7 +453,7 @@
[[ "${lines[@]}" == *"CREATE TABLE IF NOT EXISTS \"network\" (id INTEGER PRIMARY KEY NOT NULL, hwaddr TEXT UNIQUE NOT NULL, interface TEXT NOT NULL, firstSeen INTEGER NOT NULL, lastQuery INTEGER NOT NULL, numQueries INTEGER NOT NULL, macVendor TEXT, aliasclient_id INTEGER);"* ]]
[[ "${lines[@]}" == *"CREATE TABLE IF NOT EXISTS \"network_addresses\" (network_id INTEGER NOT NULL, ip TEXT UNIQUE NOT NULL, lastSeen INTEGER NOT NULL DEFAULT (cast(strftime('%s', 'now') as int)), name TEXT, nameUpdated INTEGER, FOREIGN KEY(network_id) REFERENCES network(id));"* ]]
[[ "${lines[@]}" == *"CREATE TABLE aliasclient (id INTEGER PRIMARY KEY NOT NULL, name TEXT NOT NULL, comment TEXT);"* ]]
[[ "${lines[@]}" == *"INSERT INTO ftl VALUES(0,14,'Database version');"* ]] # Expecting FTL database version 14
[[ "${lines[@]}" == *"INSERT INTO ftl VALUES(0,15,'Database version');"* ]] # Expecting FTL database version 14
# vvv This has been added in version 10 vvv
[[ "${lines[@]}" == *"CREATE VIEW queries AS SELECT id, timestamp, type, status, CASE typeof(domain) WHEN 'integer' THEN (SELECT domain FROM domain_by_id d WHERE d.id = q.domain) ELSE domain END domain,CASE typeof(client) WHEN 'integer' THEN (SELECT ip FROM client_by_id c WHERE c.id = q.client) ELSE client END client,CASE typeof(forward) WHEN 'integer' THEN (SELECT forward FROM forward_by_id f WHERE f.id = q.forward) ELSE forward END forward,CASE typeof(additional_info) WHEN 'integer' THEN (SELECT content FROM addinfo_by_id a WHERE a.id = q.additional_info) ELSE additional_info END additional_info, reply_type, reply_time, dnssec, regex_id FROM query_storage q;"* ]]
[[ "${lines[@]}" == *"CREATE TABLE domain_by_id (id INTEGER PRIMARY KEY, domain TEXT NOT NULL);"* ]]
@ -464,6 +464,8 @@
# vvv This has been added in version 11 vvv
[[ "${lines[@]}" == *"CREATE TABLE addinfo_by_id (id INTEGER PRIMARY KEY, type INTEGER NOT NULL, content NOT NULL);"* ]]
[[ "${lines[@]}" == *"CREATE UNIQUE INDEX addinfo_by_id_idx ON addinfo_by_id(type,content);"* ]]
# vvv This has been added in version 15 vvv
[[ "${lines[@]}" == *"CREATE TABLE session (id INTEGER PRIMARY KEY, login_at TIMESTAMP NOT NULL, valid_until TIMESTAMP NOT NULL, remote_addr TEXT NOT NULL, user_agent TEXT, sid TEXT NOT NULL, csrf TEXT NOT NULL, tls_login BOOL, tls_mixed BOOL);"* ]]
}
@test "Ownership, permissions and type of pihole-FTL.db correct" {