diff --git a/check.php b/check.php
new file mode 100644
index 0000000..a0e92db
--- /dev/null
+++ b/check.php
@@ -0,0 +1,158 @@
+ true,
+ CURLOPT_SSL_VERIFYPEER => false,
+ CURLOPT_SSL_VERIFYHOST => 0,
+ CURLOPT_RETURNTRANSFER => true,
+ CURLOPT_HEADER => true,
+ CURLOPT_HTTPHEADER => [
+ 'Sec-Fetch-Site: none',
+ ],
+];
+
+define('COOKIE_FILE', sys_get_temp_dir() . '/cookie-' . random_bytes(16) . '.txt');
+
+function curlTest($path, $args) {
+ $req = curl_init();
+ curl_setopt_array($req, COMMON_OPT);
+ curl_setopt_array($req, [
+ CURLOPT_URL => URL . $path,
+ CURLOPT_COOKIEFILE => COOKIE_FILE,
+ CURLOPT_COOKIEJAR => COOKIE_FILE,
+ CURLOPT_POSTFIELDS => $args,
+ ]);
+ var_dump(curl_error($req));
+ $status_code = curl_getinfo($req, CURLINFO_RESPONSE_CODE);
+ if ($status_code >= 400) {
+ var_dump(curl_exec($req));
+ exit($path . ' test failed with status code ' . $status_code . LF);
+ }
+ return curl_exec($req);
+}
+
+// AUTH TEST
+
+$username = 'check-' . bin2hex(random_bytes(16));
+$password = bin2hex(random_bytes(16));
+
+curlTest('/auth/register', [
+ 'username' => $username,
+ 'password' => $password,
+]);
+
+curlTest('/auth/logout', []);
+
+curlTest('/auth/login', [
+ 'username' => $username,
+ 'password' => $password,
+]);
+
+$new_password = bin2hex(random_bytes(16));
+curlTest('/auth/password', [
+ 'current-password' => $password,
+ 'new-password' => $new_password,
+]);
+$password = $new_password;
+
+curlTest('/auth/username', [
+ 'current-password' => $password,
+ 'new-username' => $username . '2',
+]);
+
+curlTest('/auth/username', [
+ 'current-password' => $password,
+ 'new-username' => $username,
+]);
+
+echo 'Created account with username "' . $username . '" and password "' . $password . '".' . LF;
+
+// REG TEST
+
+$subdomain = bin2hex(random_bytes(16));
+var_dump($subdomain);
+curlTest('/reg/register', [
+ 'subdomain' => $subdomain,
+ 'suffix' => SUFFIX,
+]);
+
+curlTest('/reg/ns', [
+ 'action' => 'add',
+ 'domain' => $subdomain . '.' . SUFFIX,
+ 'ns' => 'ns1.servnest.invalid.',
+]);
+
+exec(CONF['dns']['kdig_path'] . ' @' . CONF['reg']['address'] . ' ' . $subdomain . '.' . SUFFIX . ' NS', $output2, $return_code);
+if (preg_match('/[ \t]+ns1.servnest.invalid.$/Dm', implode(LF, $output2)) !== 1)
+ exit('Error: /reg/ns: NS record not set');
+
+// HT TEST
+
+curlTest('/ht/', []);
+
+define('TEST_CONTENT', 'test-' . random_bytes(4));
+
+file_put_contents(sys_get_temp_dir() . '/index.html', TEST_CONTENT);
+
+file_put_contents(sys_get_temp_dir() . '/exec.txt', 'mkdir /_site0-
+put ' . sys_get_temp_dir() . '/index.html /_site0-/index.html
+exit
+');
+
+$process = proc_open(SSHPASS . ' ' . SFTP . ' -o BatchMode=no -b ' . sys_get_temp_dir() . '/exec.txt -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -P ' . CONF['ht']['public_sftp_port'] . ' ' . $username . '@' . CONF['ht']['sftp_domain'], [0 => ['pipe', 'r']], $pipes);
+if (is_resource($process) !== true)
+ exit('Can\'t spawn sftp with sshpass.');
+fwrite($pipes[0], $password);
+fclose($pipes[0]);
+if (proc_close($process) !== 0)
+ exit('File not sent successfully.');
+
+$html = curlTest('/ht/add-onion', [
+ 'dir' => '_site0-'
+]);
+var_dump($html);
+if (preg_match('#\http\://(?[0-9a-z]{56})\.onion/\
#D', $html, $matches) !== 1)
+ exit('Can\'t find onion address.');
+
+sleep(10);
+
+$req = curl_init();
+curl_setopt_array($req, [
+ CURLOPT_PROXY => TOR_PROXY,
+ CURLOPT_URL => 'http://' . $matches['onion'] . '.onion/',
+ CURLOPT_RETURNTRANSFER => true,
+]);
+var_dump(curl_error($req));
+if (curl_exec($req) !== TEST_CONTENT) {
+ var_dump(curl_exec($req));
+ exit('Unexpected onion service response (status:' . $status_code . ') (' . $matches['onion'] . '.onion)' . LF);
+}
+
+// STOP
+
+curlTest('/auth/unregister', [
+ 'current-password' => $password,
+ 'delete' => 'on',
+]);
+
+unlink(COOKIE_FILE);
diff --git a/router.php b/router.php
index d4d3a26..c0fafbc 100644
--- a/router.php
+++ b/router.php
@@ -136,7 +136,8 @@ if ($_POST !== []) {
if (isset($_SERVER['HTTP_SEC_FETCH_SITE']) !== true)
output(403, 'The Sec-Fetch-Site
HTTP header is required when submitting a POST request to prevent Cross-Site Request Forgery (CSRF).');
if ($_SERVER['HTTP_SEC_FETCH_SITE'] !== 'same-origin')
- output(403, 'The Sec-Fetch-Site
HTTP header must be same-origin
when submitting a POST request to prevent Cross-Site Request Forgery (CSRF).');
+ if (!in_array($_SERVER['HTTP_SEC_FETCH_SITE'], ['none', 'same-origin'], true))
+ output(403, 'The Sec-Fetch-Site
HTTP header must be same-origin
or none
when submitting a POST request to prevent Cross-Site Request Forgery (CSRF).');
if (PAGE_METADATA['require-login'] ?? true !== false) {
if (isset($_SESSION['id']) !== true)