aboutsummaryrefslogtreecommitdiffhomepage
path: root/misc/send_request_authenticated.php
blob: 9019da802fbaecc2e43e5badcd0a2b806d4fd835 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
<?php

use Digitigrade\GlobalConfig;
use Digitigrade\Model\Actor;
use Digitigrade\Model\Instance;

/**
 * Makes an HTTPS request to a remote instance, using the corresponding outbound auth token (if any)
 * @param string $uri
 * @param bool $dontLookUpInstance if true, will skip looking up the Instance, and consequently the auth token
 * @param string $method HTTP verb
 * @param ?Actor $actingAs if specified, the local actor to send the request on behalf of
 * @return stdClass object with fields `body` and `headers`
 */
function send_request_authenticated(
    string $uri,
    bool $dontLookUpInstance = false,
    string $method = 'GET',
    ?Actor $actingAs = null
) {
    if (!str_starts_with($uri, 'https://')) {
        throw new RuntimeException('refusing to fetch a non-https uri');
    }

    $remoteHost = hostname_from_uri($uri);
    if ($remoteHost == GlobalConfig::getInstance()->getCanonicalHost()) {
        throw new RuntimeException('refusing to fetch content from myself');
    }

    $instance = null;
    if (!$dontLookUpInstance) {
        $instance = Instance::findByHostname($remoteHost);
    }

    if (!isset($instance->auth->outboundToken) || $instance->auth->outboundToken == null) {
        // hopefully we can make the request anyway?
        $context = stream_context_create(['http' => ['method' => $method]]);
        $resp = file_get_contents($uri);
        // $http_response_header just poofs into existence .
        // i don't like this api. i should probably use curl instead. hmm
        // TODO: use curl instead of file_get_contents
        if (str_contains($http_response_header[0], '401') || str_contains($http_response_header[0], '403')) {
            // we can't authenticate right now because it's asynchronous
            // so i'm choosing to begin the auth process now and return false in the hopes that
            // this request will be retried later
            $instance?->beginOutboundAuth();
        }
        $result = new stdClass();
        $result->body = $resp;
        $result->headers = $http_response_header;
        return $result;
    }

    $header = 'Authorization: Bearer ' . $instance->auth->outboundToken;
    if ($actingAs != null) {
        $header .= "\nX-PawPub-Actor: $actingAs->uri";
    }
    $context = stream_context_create(['http' => [
        'method' => $method,
        'header' => $header
    ]]);
    $result = new stdClass();
    $result->body = file_get_contents($uri, context: $context);
    $result->headers = $http_response_header;
    return $result;
}