Add single-user password utils (#9)

- Constrain images to reading viewport
This commit is contained in:
Daniel J. Summers 2024-04-27 16:34:59 -04:00
parent 0df40f3cfd
commit 9611893da3
6 changed files with 75 additions and 25 deletions

View File

@ -28,3 +28,17 @@ function cli_title(string $title): void {
printfn(' | %s | %s |', $title, $appTitle); printfn(' | %s | %s |', $title, $appTitle);
printfn($dashes . PHP_EOL); printfn($dashes . PHP_EOL);
} }
/**
* Capitalize the first letter of the given string
*
* @param string $value The string to be capitalized
* @return string The given string with the first letter capitalized
*/
function init_cap(string $value): string {
return match (strlen($value)) {
0 => "",
1 => strtoupper($value),
default => strtoupper(substr($value, 0, 1)) . substr($value, 1),
};
}

View File

@ -245,7 +245,7 @@ class Feed {
$code = curl_getinfo($feedReq, CURLINFO_RESPONSE_CODE); $code = curl_getinfo($feedReq, CURLINFO_RESPONSE_CODE);
if ($error) { if ($error) {
$result['error'] = $error; $result['error'] = $error;
} else if ($code == 200) { } elseif ($code == 200) {
$parsed = self::parseFeed($feedContent); $parsed = self::parseFeed($feedContent);
if (array_key_exists('error', $parsed)) { if (array_key_exists('error', $parsed)) {
$result['error'] = $parsed['error']; $result['error'] = $parsed['error'];
@ -398,7 +398,7 @@ class Feed {
$feedExtract = self::retrieveFeed($url); $feedExtract = self::retrieveFeed($url);
if (array_key_exists('error', $feedExtract)) return $feedExtract; if (array_key_exists('error', $feedExtract)) return $feedExtract;
$feed = $feedExtract['ok']; $feed = $feedExtract['ok'];
$query = $db->prepare(<<<'SQL' $query = $db->prepare(<<<'SQL'
INSERT INTO feed (user_id, url, title, updated_on, checked_on) INSERT INTO feed (user_id, url, title, updated_on, checked_on)
VALUES (:user, :url, :title, :updated, :checked) VALUES (:user, :url, :title, :updated, :checked)

View File

@ -18,7 +18,7 @@ class Security {
public const string SINGLE_USER_EMAIL = 'solouser@example.com'; public const string SINGLE_USER_EMAIL = 'solouser@example.com';
/** @var string The password for the single user with no password */ /** @var string The password for the single user with no password */
private const string SINGLE_USER_PASSWORD = 'no-password-required'; public const string SINGLE_USER_PASSWORD = 'no-password-required';
/** @var string The password algorithm to use for our passwords */ /** @var string The password algorithm to use for our passwords */
public const string PW_ALGORITHM = PASSWORD_DEFAULT; public const string PW_ALGORITHM = PASSWORD_DEFAULT;
@ -82,11 +82,16 @@ class Security {
* @param SQLite3 $db The database connection to use to verify the user's credentials * @param SQLite3 $db The database connection to use to verify the user's credentials
*/ */
public static function logOnUser(string $email, string $password, ?string $returnTo, SQLite3 $db): void { public static function logOnUser(string $email, string $password, ?string $returnTo, SQLite3 $db): void {
if ($email == self::SINGLE_USER_EMAIL) { if (SECURITY_MODEL == self::SINGLE_USER_WITH_PASSWORD) {
add_error('Invalid credentials; log on unsuccessful'); $dbEmail = self::SINGLE_USER_EMAIL;
return; } else {
if ($email == self::SINGLE_USER_EMAIL) {
add_error('Invalid credentials; log on unsuccessful');
return;
}
$dbEmail = $email;
} }
$user = self::findUserByEmail($email, $db); $user = self::findUserByEmail($dbEmail, $db);
if ($user) self::verifyPassword($user, $password, $returnTo, $db); if ($user) self::verifyPassword($user, $password, $returnTo, $db);
add_error('Invalid credentials; log on unsuccessful'); add_error('Invalid credentials; log on unsuccessful');
} }

View File

@ -61,6 +61,13 @@ article {
border-radius: .5rem; border-radius: .5rem;
background-color: white; background-color: white;
padding: .5rem; padding: .5rem;
img {
max-width: 100%;
object-fit: contain;
height: unset;
width: unset;
}
} }
} }
input[type=url], input[type=url],

View File

@ -43,12 +43,10 @@ function add_info(string $message): void {
* @param string $title The title of the page being displayed * @param string $title The title of the page being displayed
*/ */
function page_head(string $title): void { function page_head(string $title): void {
if (str_ends_with(FRC_VERSION, '.0.0')) { $version = match (true) {
$version = substr(FRC_VERSION, 0, strlen(FRC_VERSION) - 4); str_ends_with(FRC_VERSION, '.0.0') => substr(FRC_VERSION, 0, strlen(FRC_VERSION) - 4),
} elseif (str_ends_with(FRC_VERSION, '.0')) { str_ends_with(FRC_VERSION, '.0') => substr(FRC_VERSION, 0, strlen(FRC_VERSION) - 2),
$version = substr(FRC_VERSION, 0, strlen(FRC_VERSION) - 2); default => FRC_VERSION
} else {
$version = FRC_VERSION;
} ?> } ?>
<!DOCTYPE html> <!DOCTYPE html>
<html lang=en> <html lang=en>

View File

@ -20,7 +20,7 @@ switch ($argv[1]) {
printfn('Missing parameters: set-password requires e-mail and password'); printfn('Missing parameters: set-password requires e-mail and password');
exit(-1); exit(-1);
} }
set_password(); set_password($argv[2], $argv[3]);
break; break;
case 'delete-user': case 'delete-user':
if ($argc < 3) { if ($argc < 3) {
@ -29,6 +29,16 @@ switch ($argv[1]) {
} }
delete_user($argv[2]); delete_user($argv[2]);
break; break;
case 'set-single-password':
if ($argc < 3) {
printfn('Missing parameters: set-single-password requires a new password');
exit(-1);
}
set_password(Security::SINGLE_USER_EMAIL, $argv[2]);
break;
case 'reset-single-password':
set_password(Security::SINGLE_USER_EMAIL, Security::SINGLE_USER_PASSWORD);
break;
case 'migrate-single-user': case 'migrate-single-user':
if ($argc < 4) { if ($argc < 4) {
printfn('Missing parameters: migrate-single-user requires e-mail and password'); printfn('Missing parameters: migrate-single-user requires e-mail and password');
@ -57,7 +67,12 @@ function display_help(): void {
printfn(' Sets the password for the given user'); printfn(' Sets the password for the given user');
printfn(' - delete-user [e-mail]'); printfn(' - delete-user [e-mail]');
printfn(' Deletes a user and all their data' . PHP_EOL); printfn(' Deletes a user and all their data' . PHP_EOL);
printfn('To assist with migrating from single-user to multi-user mode:'); printfn('To assist with changing from single-user to single-user-with-password mode:');
printfn(' - set-single-password [password]');
printfn(' Sets the password for the single-user mode user');
printfn(' - reset-single-password');
printfn(' Resets the single-user mode user\'s password to its default' . PHP_EOL);
printfn('To assist with changing from single-user to multi-user mode:');
printfn(' - migrate-single-user [e-mail] [password]'); printfn(' - migrate-single-user [e-mail] [password]');
printfn(' Changes the e-mail address and password for the single-user mode user'); printfn(' Changes the e-mail address and password for the single-user mode user');
printfn(' - remove-single-user'); printfn(' - remove-single-user');
@ -89,25 +104,36 @@ function add_user(): void {
} }
} }
/**
* Get the way we will refer to the user against whom action is being taken
*
* @param string $email The e-mail address of the user
* @return string The string to use when displaying results
*/
function display_user(string $email): string {
return $email == Security::SINGLE_USER_EMAIL ? 'single-user mode user' : "user \"$email\"";
}
/** /**
* Set a user's password * Set a user's password
*/ */
function set_password(): void { function set_password(string $email, string $password): void {
global $argv;
$db = Data::getConnection(); $db = Data::getConnection();
try { try {
$displayUser = display_user($email);
// Ensure this user exists // Ensure this user exists
$user = Security::findUserByEmail($argv[2], $db); $user = Security::findUserByEmail($email, $db);
if (!$user) { if (!$user) {
printfn('No user exists with e-mail address "%s"', $argv[2]); printfn('No %s exists', $displayUser);
return; return;
} }
Security::updatePassword($argv[2], $argv[3], $db); Security::updatePassword($email, $password, $db);
printfn('User "%s" password set to "%s" successfully', $argv[2], $argv[3]); $msg = $email == Security::SINGLE_USER_EMAIL && $password == Security::SINGLE_USER_PASSWORD
? 'reset' : sprintf('set to "%s"', $password);
printfn('%s password %s successfully', init_cap($displayUser), $msg);
} finally { } finally {
$db->close(); $db->close();
} }
@ -123,7 +149,7 @@ function delete_user(string $email): void {
$db = Data::getConnection(); $db = Data::getConnection();
try { try {
$displayUser = $email == Security::SINGLE_USER_EMAIL ? 'single-user mode user' : "user \"$email\""; $displayUser = display_user($email);
// Get the ID for the provided e-mail address // Get the ID for the provided e-mail address
$user = Security::findUserByEmail($email, $db); $user = Security::findUserByEmail($email, $db);
@ -159,7 +185,7 @@ function delete_user(string $email): void {
$userDelete->bindValue(':user', $user['id']); $userDelete->bindValue(':user', $user['id']);
$userDelete->execute(); $userDelete->execute();
printfn(strtoupper(substr($displayUser, 0, 1)) . substr($displayUser, 1) . ' deleted successfully'); printfn('%s deleted successfully', init_cap($displayUser));
} finally { } finally {
$db->close(); $db->close();
} }