mirror of
https://github.com/sorenpeter/timeline.git
synced 2025-12-15 10:57:01 +00:00
115 lines
3.1 KiB
PHP
115 lines
3.1 KiB
PHP
<?php
|
|
$config = parse_ini_file('private/config.ini');
|
|
|
|
# TODO: Move this verification to another file
|
|
$required_keys = ['secret_key', 'password', 'totp_secret', 'totp_digits', 'secure_cookies'];
|
|
$missing_keys = array_filter($required_keys, fn($key) => !isset($config[$key]));
|
|
|
|
if (!empty($missing_keys)) {
|
|
die('Missing required keys in config.ini: ' . implode(', ', $missing_keys));
|
|
}
|
|
|
|
# To make it more secure, something like JWT could be used instead
|
|
|
|
const COOKIE_NAME = 'timeline_login';
|
|
const ENCRYPTION_METHOD = 'aes-256-cbc';
|
|
const EXPIRATION_DAYS = 30;
|
|
|
|
session_start([
|
|
'name' => 'timeline_session',
|
|
'use_strict_mode' => true,
|
|
'cookie_httponly' => true,
|
|
'cookie_secure' => $config['secure_cookies'],
|
|
'sid_length' => 64,
|
|
'sid_bits_per_character' => 6,
|
|
'cookie_samesite' => 'Strict', # Not compatible with PHP < 7.3
|
|
]);
|
|
|
|
function hasValidSession(): bool|string {
|
|
# If short lived session is valid
|
|
if (isset($_SESSION['valid_session'])) {
|
|
return true;
|
|
}
|
|
|
|
# Otherwise, check the persistent cookie
|
|
return isSavedCookieValid();
|
|
}
|
|
|
|
function encrypt(string $data, string $key, string $method): string {
|
|
$ivSize = openssl_cipher_iv_length($method);
|
|
$iv = openssl_random_pseudo_bytes($ivSize);
|
|
$encrypted = openssl_encrypt($data, $method, $key, OPENSSL_RAW_DATA, $iv);
|
|
$encrypted = strtoupper(implode(unpack('H*', $encrypted)));
|
|
|
|
return $encrypted;
|
|
}
|
|
|
|
function decrypt(string $data, string $key, string $method): string | bool {
|
|
$data = pack('H*', $data);
|
|
$ivSize = openssl_cipher_iv_length($method);
|
|
$iv = openssl_random_pseudo_bytes($ivSize);
|
|
$decrypted = openssl_decrypt($data, $method, $key, OPENSSL_RAW_DATA, $iv);
|
|
|
|
var_dump($decrypted);
|
|
|
|
if ($decrypted === false) {
|
|
return false;
|
|
}
|
|
|
|
return trim($decrypted);
|
|
}
|
|
|
|
function saveLoginSuccess() {
|
|
$_SESSION['valid_session'] = true;
|
|
|
|
$config = parse_ini_file('private/config.ini');
|
|
|
|
# Set a cookie to remember the user
|
|
$cookieExpiry = EXPIRATION_DAYS * 24 * 60 * 60 + time();
|
|
$encodedCookieValue = generateCookieValue(strval($cookieExpiry), $config['secret_key']);
|
|
|
|
setcookie(COOKIE_NAME, $encodedCookieValue, [
|
|
'expires' => $cookieExpiry,
|
|
'secure' => $config['secure_cookies'],
|
|
'httponly' => true,
|
|
'samesite' => 'Strict',
|
|
]);
|
|
}
|
|
|
|
function generateCookieValue($value, $secretKey) {
|
|
$key = bin2hex($secretKey);
|
|
|
|
$encrypted = encrypt($value, $key, ENCRYPTION_METHOD);
|
|
return $encrypted;
|
|
}
|
|
|
|
function isSavedCookieValid() {
|
|
if (!isset($_COOKIE[COOKIE_NAME])) {
|
|
return false;
|
|
}
|
|
|
|
$config = parse_ini_file('private/config.ini');
|
|
|
|
$encoded_cookie_value = $_COOKIE[COOKIE_NAME];
|
|
$key = bin2hex($config['secret_key']);
|
|
|
|
$cookieVal = decrypt($encoded_cookie_value, $key, ENCRYPTION_METHOD);
|
|
|
|
if ($cookieVal === false) {
|
|
deletePersistentCookie();
|
|
return false;
|
|
}
|
|
|
|
# TODO: Check that the cookie is not expired
|
|
|
|
saveLoginSuccess(); # Extend expiracy for previous cookie
|
|
|
|
return true; # If it was decoded correctly, it's a valid session
|
|
}
|
|
|
|
function deletePersistentCookie() {
|
|
if (isset($_COOKIE[COOKIE_NAME])) {
|
|
unset($_COOKIE[COOKIE_NAME]);
|
|
setcookie(COOKIE_NAME, '', time() - 3600);
|
|
}
|
|
}
|