115 lines
3.3 KiB
PHP
115 lines
3.3 KiB
PHP
<?php
|
|
|
|
/**
|
|
* Persisted security settings (system_setting table in encrypted DB).
|
|
*/
|
|
|
|
function qdb_settings_defaults(): array
|
|
{
|
|
return [
|
|
'login_max_attempts' => 10,
|
|
'login_window_seconds' => 900,
|
|
'login_lockout_seconds' => 900,
|
|
'session_ttl_seconds' => 30 * 24 * 60 * 60,
|
|
'temp_session_ttl_seconds' => 10 * 60,
|
|
];
|
|
}
|
|
|
|
function qdb_settings_keys(): array
|
|
{
|
|
return array_keys(qdb_settings_defaults());
|
|
}
|
|
|
|
function qdb_ensure_system_setting_table(PDO $pdo): void
|
|
{
|
|
if (!qdb_table_exists($pdo, 'system_setting')) {
|
|
$pdo->exec("
|
|
CREATE TABLE system_setting (
|
|
settingKey TEXT NOT NULL PRIMARY KEY,
|
|
settingValue TEXT NOT NULL DEFAULT ''
|
|
)
|
|
");
|
|
}
|
|
}
|
|
|
|
function qdb_settings_get_on_pdo(PDO $pdo): array
|
|
{
|
|
qdb_ensure_system_setting_table($pdo);
|
|
$out = qdb_settings_defaults();
|
|
$rows = $pdo->query('SELECT settingKey, settingValue FROM system_setting')->fetchAll(PDO::FETCH_ASSOC);
|
|
foreach ($rows as $row) {
|
|
$key = (string)($row['settingKey'] ?? '');
|
|
if ($key === '' || !array_key_exists($key, $out)) {
|
|
continue;
|
|
}
|
|
$out[$key] = (int)$row['settingValue'];
|
|
}
|
|
return $out;
|
|
}
|
|
|
|
function qdb_settings_get(): array
|
|
{
|
|
require_once __DIR__ . '/../db_init.php';
|
|
[$pdo, $tmpDb, $lockFp] = qdb_open(false);
|
|
try {
|
|
return qdb_settings_get_on_pdo($pdo);
|
|
} finally {
|
|
qdb_discard($tmpDb, $lockFp);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @param array<string, int> $partial
|
|
* @param array<string, int>|null $base existing settings; defaults used when null
|
|
* @return array<string, int> saved settings
|
|
*/
|
|
function qdb_settings_validate_and_merge(array $partial, ?array $base = null): array
|
|
{
|
|
$merged = $base ?? qdb_settings_defaults();
|
|
$limits = [
|
|
'login_max_attempts' => [1, 100],
|
|
'login_window_seconds' => [60, 86400],
|
|
'login_lockout_seconds' => [60, 86400],
|
|
'session_ttl_seconds' => [3600, 365 * 24 * 60 * 60],
|
|
'temp_session_ttl_seconds' => [300, 24 * 60 * 60],
|
|
];
|
|
foreach (qdb_settings_keys() as $key) {
|
|
if (!array_key_exists($key, $partial)) {
|
|
continue;
|
|
}
|
|
$val = (int)$partial[$key];
|
|
[$min, $max] = $limits[$key];
|
|
if ($val < $min || $val > $max) {
|
|
throw new InvalidArgumentException(
|
|
"$key must be between $min and $max"
|
|
);
|
|
}
|
|
$merged[$key] = $val;
|
|
}
|
|
return $merged;
|
|
}
|
|
|
|
/**
|
|
* @param array<string, int> $settings full merged settings to persist
|
|
*/
|
|
function qdb_settings_save_on_pdo(PDO $pdo, array $settings): void
|
|
{
|
|
qdb_ensure_system_setting_table($pdo);
|
|
$stmt = $pdo->prepare(
|
|
'INSERT INTO system_setting (settingKey, settingValue)
|
|
VALUES (:k, :v)
|
|
ON CONFLICT(settingKey) DO UPDATE SET settingValue = excluded.settingValue'
|
|
);
|
|
foreach (qdb_settings_keys() as $key) {
|
|
$stmt->execute([':k' => $key, ':v' => (string)(int)($settings[$key] ?? 0)]);
|
|
}
|
|
}
|
|
|
|
function qdb_session_ttl_seconds(?array $settings = null, bool $temp = false): int
|
|
{
|
|
$settings ??= qdb_settings_get();
|
|
return $temp
|
|
? (int)$settings['temp_session_ttl_seconds']
|
|
: (int)$settings['session_ttl_seconds'];
|
|
}
|