From 68c7e68b3f90fd980661774fdb2bb2d6140a34d0 Mon Sep 17 00:00:00 2001 From: winter Date: Mon, 16 Dec 2024 20:27:01 +0000 Subject: implement the other side of auth (hopefully?) also mostly untested for the same reason as last time --- routes/auth.php | 73 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 73 insertions(+) (limited to 'routes') diff --git a/routes/auth.php b/routes/auth.php index b44d76a..2dbe6f1 100644 --- a/routes/auth.php +++ b/routes/auth.php @@ -1,10 +1,82 @@ mount('/auth/main', function (array $args) { + if (!isset($_GET['phase'])) { + throw new BadRequest('you need to specify the `phase` GET parameter'); + } + switch ($_GET['phase']) { + + case 'dialback': + // send a secret to the dialback address! + if (!isset($_GET['target'])) { + throw new BadRequest('you need to specify the `target` GET parameter'); + } + $domain = explode('/', $_GET['target'])[2]; + $instance = Instance::findByDomain($domain); + if ($instance == null) { + throw new RuntimeException("i can't find your instance information, sorry"); + } + + $instance->auth->secret = random_printable_bytes(); + $instance->auth->save(); + // TODO: schedule a job to throw away the secret after some time if it's not used? + + $data = http_build_query([ + 'origin' => GlobalConfig::getInstance()->getCanonicalHost(), + 'secret' => $instance->auth->secret + ]); + $context = stream_context_create(['http' => [ + 'method' => 'POST', + 'header' => 'Content-Type: application/x-www-form-urlencoded', + 'content' => $data + ]]); + // TODO: (maybe?) put this in a job instead of doing it right away? + file_get_contents($_GET['target'], context: $context); + + http_response_code(202); // "Accepted" + break; + + case 'token': + // verify the secret, if it's good, issue a token + if (!isset($_GET['secret'])) { + throw new BadRequest('you need to specify the `secret` GET parameter'); + } + $instance = Instance::findByDialbackSecret($_GET['secret']); + if ($instance == null) { + throw new Forbidden('the provided secret is invalid!'); + } + + $instance->auth->secret = null; // it's been used now + $instance->auth->inboundToken = random_printable_bytes(); + $instance->auth->save(); + + $expiry = new \DateTimeImmutable('1 day'); // this seems like a reasonable length of time? + (new ExpireInboundAuthToken( + $instance->domain, + $instance->auth->inboundToken, + $expiry + ))->submit(); + + json_response([ + 'token' => $instance->auth->inboundToken, + 'expires' => $expiry->format('c') + ]); + + break; + + default: + throw new BadRequest('invalid phase'); + } +}); + Router::getInstance()->mount('/auth/dialback', function (array $args) { // just respond to the dialback challenge! if (!isset($_POST['origin'], $_POST['secret'])) { @@ -19,4 +91,5 @@ Router::getInstance()->mount('/auth/dialback', function (array $args) { } (new RequestOutboundAuthToken($instance->domain, $_POST['secret']))->submit(); + http_response_code(202); // "Accepted" }); \ No newline at end of file -- cgit v1.3