diff --git a/db/migrations/006-create-ns-syncs-table.sql b/db/migrations/006-create-ns-syncs-table.sql new file mode 100644 index 0000000..baca87f --- /dev/null +++ b/db/migrations/006-create-ns-syncs-table.sql @@ -0,0 +1,12 @@ +BEGIN TRANSACTION; + +CREATE TABLE IF NOT EXISTS "ns-syncs" ( + "username" TEXT NOT NULL, + "source" TEXT NOT NULL, + "destination" TEXT NOT NULL UNIQUE, + UNIQUE("username", "source", "destination"), + FOREIGN KEY("username") REFERENCES "users"("id"), + FOREIGN KEY("destination") REFERENCES "zones"("zone") +); + +COMMIT; diff --git a/db/schema.sql b/db/schema.sql index 8233bbe..4d253f2 100644 --- a/db/schema.sql +++ b/db/schema.sql @@ -42,6 +42,13 @@ CREATE TABLE IF NOT EXISTS "zones" ( PRIMARY KEY("zone"), FOREIGN KEY("username") REFERENCES "users"("id") ); +CREATE TABLE IF NOT EXISTS "ns-syncs" ( + "username" TEXT NOT NULL, + "source" TEXT NOT NULL, + "destination" TEXT NOT NULL UNIQUE, + FOREIGN KEY("username") REFERENCES "users"("id"), + FOREIGN KEY("destination") REFERENCES "zones"("zone") +); CREATE TABLE IF NOT EXISTS "sites" ( "username" TEXT NOT NULL, "site_dir" TEXT NOT NULL, diff --git a/fn/auth.php b/fn/auth.php index 4f321e2..240f8ea 100644 --- a/fn/auth.php +++ b/fn/auth.php @@ -1,4 +1,4 @@ - 64, ]; -function checkUsernameFormat($username) { +function checkUsernameFormat(string $username): void { if (preg_match('/' . USERNAME_REGEX . '/Du', $username) !== 1) output(403, 'Username malformed.'); } -function checkPasswordFormat($password) { +function checkPasswordFormat(string $password): void { if (preg_match('/' . PASSWORD_REGEX . '/Du', $password) !== 1) output(403, 'Password malformed.'); } -function hashUsername($username) { +function hashUsername(string $username): string { return base64_encode(sodium_crypto_pwhash(32, $username, hex2bin(query('select', 'params', ['name' => 'username_salt'], 'value')[0]), 2**10, 2**14, SODIUM_CRYPTO_PWHASH_ALG_ARGON2ID13)); } -function hashPassword($password) { +function hashPassword(string $password): string { return password_hash($password, ALGO_PASSWORD, OPTIONS_PASSWORD); } -function usernameExists($username) { +function usernameExists(string $username): bool { return isset(query('select', 'users', ['username' => $username], 'id')[0]); } -function checkPassword($id, $password) { +function checkPassword(string $id, string $password): bool { return password_verify($password, query('select', 'users', ['id' => $id], 'password')[0]); } -function outdatedPasswordHash($id) { +function outdatedPasswordHash(string $id): bool { return password_needs_rehash(query('select', 'users', ['id' => $id], 'password')[0], ALGO_PASSWORD, OPTIONS_PASSWORD); } -function changePassword($id, $password) { +function changePassword(string $id, string $password): void { DB->prepare('UPDATE users SET password = :password WHERE id = :id') ->execute([':password' => hashPassword($password), ':id' => $id]); } -function stopSession() { +function stopSession(): void { if (session_status() === PHP_SESSION_ACTIVE) session_destroy(); } -function logout() { +function logout(): never { stopSession(); header('Clear-Site-Data: "*"'); @@ -62,7 +62,7 @@ function logout() { redir(); } -function setupDisplayUsername($display_username) { +function setupDisplayUsername(string $display_username): void { $nonce = random_bytes(24); $key = sodium_crypto_aead_xchacha20poly1305_ietf_keygen(); $cyphertext = sodium_crypto_aead_xchacha20poly1305_ietf_encrypt( @@ -87,7 +87,7 @@ function setupDisplayUsername($display_username) { $_SESSION['display-username-cyphertext'] = $cyphertext; } -function authDeleteUser($user_id) { +function authDeleteUser(string $user_id): void { $user_services = explode(',', query('select', 'users', ['id' => $user_id], 'services')[0]); foreach (SERVICES_USER as $service) @@ -133,12 +133,14 @@ function authDeleteUser($user_id) { ], result_code: $code); if ($code !== 0) output(500, 'Can\'t remove user\'s directory.'); + + query('delete', 'ssh-keys', ['username' => $user_id]); } query('delete', 'users', ['id' => $user_id]); } -function rateLimit() { +function rateLimit(): void { if (PAGE_METADATA['tokens_account_cost'] ?? 0 > 0) rateLimitAccount(PAGE_METADATA['tokens_account_cost']); @@ -147,7 +149,7 @@ function rateLimit() { } const MAX_ACCOUNT_TOKENS = 86400; -function rateLimitAccount($requestedTokens) { +function rateLimitAccount(int $requestedTokens): int { // Get $userData = query('select', 'users', ['id' => $_SESSION['id']]); $tokens = $userData[0]['bucket_tokens']; @@ -174,7 +176,7 @@ function rateLimitAccount($requestedTokens) { return $tokens; } -function rateLimitInstance($requestedTokens) { +function rateLimitInstance(int $requestedTokens): void { // Get $tokens = query('select', 'params', ['name' => 'instance_bucket_tokens'], 'value')[0]; $bucketLastUpdate = query('select', 'params', ['name' => 'instance_bucket_last_update'], 'value')[0]; diff --git a/fn/common.php b/fn/common.php index 0002ca1..bb20853 100644 --- a/fn/common.php +++ b/fn/common.php @@ -1,6 +1,6 @@ - $val) { @@ -44,7 +62,7 @@ function insert($table, $values) { ->execute($values); } -function query($action, $table, $conditions = [], $column = NULL) { +function query(string $action, string $table, array $conditions = [], string $column = NULL): array { $query = match ($action) { 'select' => 'SELECT *', @@ -66,7 +84,7 @@ function query($action, $table, $conditions = [], $column = NULL) { return array_column($stmt->fetchAll(PDO::FETCH_ASSOC), $column); } -function displayIndex() { ?> +function displayIndex(): void { ?>