diff --git a/jobs/check.php b/jobs/check.php index 0e5f47c..3e17b67 100644 --- a/jobs/check.php +++ b/jobs/check.php @@ -12,8 +12,21 @@ foreach (CONF['reg']['suffixes'] as $suffix => $openness) if (!defined('SUFFIX')) exit('Unable to start tests: no suffix open to registration'); +$test_start = 0; +function startTest(string $test_name): void { + global $test_start; + $test_start = microtime(true); + echo 'Testing ' . $test_name . '... '; +} +function stopTest(): void { + global $test_start; + echo 'OK (' . round(microtime(true) - $test_start, 2) . 's)' . LF; +} + +startTest('DNSSEC resolution'); if (kdig(name: 'nlnet.nl', type: 'AAAA')['AD'] !== 1) exit('DNS queries don\'t seem to be DNSSEC-validated.' . LF); +stopTest(); define('COOKIE_FILE', sys_get_temp_dir() . '/cookie-' . bin2hex(random_bytes(16)) . '.txt'); @@ -54,17 +67,21 @@ function curlTest(string $address, array $post = [], bool $tor = false): string $username = 'check-' . bin2hex(random_bytes(16)); $password = bin2hex(random_bytes(16)); +startTest('account registration'); curlTest('/auth/register', [ 'username' => $username, 'password' => $password, ]); +stopTest(); +startTest('account password change'); $new_password = bin2hex(random_bytes(16)); curlTest('/auth/password', [ 'current-password' => $password, 'new-password' => $new_password, ]); $password = $new_password; +stopTest(); curlTest('/auth/register', [ 'username' => $username . '2', @@ -93,22 +110,31 @@ function testReg(): string { $subdomain = bin2hex(random_bytes(16)); + startTest('domain registration'); curlTest('/reg/register', [ 'subdomain' => $subdomain, 'suffix' => SUFFIX, 'action' => 'register', ]); + stopTest(); $domain = $subdomain . '.' . SUFFIX; - curlTest('/reg/ns', [ - 'action' => 'add', - 'domain' => $domain, - 'ns' => 'ns1.servnest.invalid.', - ]); - $results = kdig(name: $domain, type: 'NS', server: CONF['reg']['address']); - if (($results['authorityRRs'][0]['rdataNS'] ?? NULL) !== 'ns1.servnest.invalid.') - exit('Error: /reg/ns: NS record not set' . LF); + { + startTest('NS record writing in registry'); + curlTest('/reg/ns', [ + 'action' => 'add', + 'domain' => $domain, + 'ns' => 'ns1.servnest.invalid.', + ]); + stopTest(); + + startTest('NS record reading in registry'); + $results = kdig(name: $domain, type: 'NS', server: CONF['reg']['address']); + if (($results['authorityRRs'][0]['rdataNS'] ?? NULL) !== 'ns1.servnest.invalid.') + exit('Error: /reg/ns: NS record not set' . LF); + stopTest(); + } curlTest('/reg/ns', [ 'action' => 'delete', @@ -117,6 +143,7 @@ function testReg(): string { ]); { // Domain transfer + startTest('domain transfer procedure'); curlTest('/auth/logout'); curlTest('/auth/login', [ 'username' => $username . '2', @@ -145,6 +172,7 @@ function testReg(): string { 'suffix' => SUFFIX, 'ns' => $matches['token'], ]); + stopTest(); $username = $username . '2'; } @@ -167,9 +195,11 @@ function testNs(string $domain): void { 'ns' => $matches['token'], ]); + startTest('/ns/zone-add'); curlTest('/ns/zone-add', [ 'domain' => $domain, ]); + stopTest(); curlTest('/reg/ns', [ 'action' => 'delete', @@ -177,33 +207,48 @@ function testNs(string $domain): void { 'ns' => $matches['token'], ]); - curlTest('/ns/caa', [ - 'action' => 'add', - 'subdomain' => '@', - 'zone' => $domain, - 'ttl-value' => '2', - 'ttl-multiplier' => '3600', - 'flag' => '0', - 'tag' => 'issue', - 'value' => 'letsencrypt.org', - ]); - $results = kdig(name: $domain, type: 'CAA', server: CONF['reg']['address']); - if (($results['answerRRs'][0]['TTL'] ?? NULL) !== 7200) - exit('Error: /ns/caa: wrong TTL' . LF); - if (($results['answerRRs'][0]['rdataCAA'] ?? NULL) !== '0 issue "letsencrypt.org" ') - exit('Error: /ns/caa: CAA record not set' . LF); + { + startTest('/ns/caa writing'); + curlTest('/ns/caa', [ + 'action' => 'add', + 'subdomain' => '@', + 'zone' => $domain, + 'ttl-value' => '2', + 'ttl-multiplier' => '3600', + 'flag' => '0', + 'tag' => 'issue', + 'value' => 'letsencrypt.org', + ]); + stopTest(); - curlTest('/ns/edit', [ - 'domain' => $domain, - 'records' => 'aaaa.' . $domain . ' 3600 AAAA ' . CONF['ht']['ipv6_address'] . "\r\n" - . '@ 86400 NS ' . CONF['ns']['servers'][0] . "\r\n", - ]); - $results = kdig(name: 'aaaa.' . $domain, type: 'AAAA', server: CONF['reg']['address']); - if (($results['answerRRs'][0]['rdataAAAA'] ?? NULL) !== CONF['ht']['ipv6_address']) - exit('Error: /ns/edit: AAAA record not set' . LF); + startTest('/ns/caa reading'); + $results = kdig(name: $domain, type: 'CAA', server: CONF['reg']['address']); + if (($results['answerRRs'][0]['TTL'] ?? NULL) !== 7200) + exit('Error: /ns/caa: wrong TTL' . LF); + if (($results['answerRRs'][0]['rdataCAA'] ?? NULL) !== '0 issue "letsencrypt.org" ') + exit('Error: /ns/caa: CAA record not set' . LF); + stopTest(); + } + + { + startTest('/ns/edit writing'); + curlTest('/ns/edit', [ + 'domain' => $domain, + 'records' => 'aaaa.' . $domain . ' 3600 AAAA ' . CONF['ht']['ipv6_address'] . "\r\n" + . '@ 86400 NS ' . CONF['ns']['servers'][0] . "\r\n", + ]); + stopTest(); + + startTest('/ns/edit reading'); + $results = kdig(name: 'aaaa.' . $domain, type: 'AAAA', server: CONF['reg']['address']); + if (($results['answerRRs'][0]['rdataAAAA'] ?? NULL) !== CONF['ht']['ipv6_address']) + exit('Error: /ns/edit: AAAA record not set' . LF); + stopTest(); + } } function testHt(string $username, string $password): void { + startTest('SFTP file upload'); define('TEST_CONTENT', 'test-' . bin2hex(random_bytes(16))); file_put_contents(sys_get_temp_dir() . '/index.html', TEST_CONTENT); @@ -220,45 +265,74 @@ exit fclose($pipes[0]); if (proc_close($process) !== 0) exit('File not sent successfully.' . LF); + stopTest(); { $ht_subpath = bin2hex(random_bytes(16)); + + startTest('subpath site creation'); curlTest('/ht/add-subpath', [ 'path' => $ht_subpath, 'dir' => '_site0-', ]); + stopTest(); + + startTest('subpath site reachability'); if (curlTest('https://' . CONF['ht']['subpath_domain'] . ':' . HTTPS_PORT . '/' . $ht_subpath . '/') !== TEST_CONTENT) exit('Unexpected subpath response' . LF); + stopTest(); + + startTest('subpath site deletion'); curlTest('/ht/del', [ 'site' => 'subpath:' . $ht_subpath, ]); + stopTest(); } { $ht_subdomain = 'test3'; + + startTest('subdomain site creation'); curlTest('/ht/add-subdomain', [ 'subdomain' => $ht_subdomain, 'dir' => '_site0-', ]); + stopTest(); + + startTest('subdomain site reachability'); if (curlTest('https://' . $ht_subdomain . '.' . CONF['ht']['subpath_domain'] . ':' . HTTPS_PORT . '/') !== TEST_CONTENT) exit('Unexpected subpath response' . LF); + stopTest(); + + startTest('subdomain site deletion'); curlTest('/ht/del', [ 'site' => 'subdomain:' . $ht_subdomain, ]); + stopTest(); } + { + startTest('onion site creation'); $html = curlTest('/ht/add-onion', [ 'dir' => '_site0-', ]); + stopTest(); + if (preg_match('#\http\://(?[0-9a-z]{56})\.onion/\#D', $html, $matches) !== 1) exit('Can\'t find onion address.' . LF); sleep(5); // Onion services are not immediately reachable + + startTest('onion site reachability'); if (curlTest('http://' . $matches['onion'] . '.onion/', tor: true) !== TEST_CONTENT) exit('Unexpected onion service response (' . $matches['onion'] . '.onion)' . LF); + stopTest(); + + startTest('onion site deletion'); curlTest('/ht/del', [ 'site' => 'onion:' . $matches['onion'] . '.onion', ]); + stopTest(); } } @@ -266,11 +340,13 @@ $domain = testReg(); testNs($domain); testHt($username, $password); +startTest('account deletion'); curlTest('/auth/unregister', [ 'current-password' => $password, 'delete' => 'on', ]); +stopTest(); unlink(COOKIE_FILE); -echo 'OK' . LF; +echo 'All tests succeeded! 🎉' . LF;