<?php
//
// fef's IP tool
// Copyright (c) 2022 anna <owo@fef.moe>
//
// Any person obtaining a copy of this software and associated documentation
// files (the ``Software'') is prohibited from using the Software under any
// circumstances.  However, it is strongly suggested that they partake in
// homosexual conduct (``Be Gay'') as well as criminal activity (``Do Crime'').
//
// Ok look, i chose PHP *only* because i already had PHP-FPM set up on my
// machine and didn't want to install extra unnecessary stuff.  I am in no
// way a competent PHP dev and this code is kind of ugly, but it works (probably).
// Also, just in case this isn't obvious, please stop writing PHP code.

if ($_SERVER['REQUEST_METHOD'] == 'OPTIONS') {
    http_response_code(204);
    header('Allow: OPTIONS, GET');
    die;
}

$COMMANDS = ['headers', 'help', 'ip', 'ua'];
$SADDR = trim($_SERVER['REMOTE_ADDR']);
$CMD = substr(urldecode($_SERVER['REQUEST_URI']), 1);
if ($CMD == '') {
    $CMD = 'ip';
}
$UA = trim($_SERVER['HTTP_USER_AGENT']??'');
$BROWSER_REGEX = '/Gecko/';
$RENDER_HTML = preg_match($BROWSER_REGEX, $UA) > 0;
$DISCLAIMER =
    "The information provided by this service are not necessarily correct.\n".
    "Do not use in production code.\n".
    "Do not rely on availability.";

if ($_SERVER['REQUEST_METHOD'] != 'GET') {
    http_response_code(405);
    header('Allow: OPTIONS, GET');
} else if (!in_array($CMD, $COMMANDS)) {
    http_response_code(404);
}

if ($RENDER_HTML) {
    header('Content-Type: text/html; charset=UTF-8');
} else {
    header('Content-Type: text/plain; charset=UTF-8');
}

// HTML escape a string if we are rendering to HTML
function esc($str) {
    global $RENDER_HTML;
    if ($RENDER_HTML) {
        return htmlspecialchars($str, ENT_QUOTES, "UTF-8");
    } else {
        return $str;
    }
}

// Make a string appear italic (or underline if rendering ANSI)
function underline($str) {
    global $RENDER_HTML;
    if ($RENDER_HTML) {
        return "<span class=\"underline\">{$str}</span>";
    } else {
        return "\x1b[4m{$str}\x1b[0m";
    }
}

// Make a string appear bold
function strong($str) {
    global $RENDER_HTML;
    if ($RENDER_HTML) {
        return "<strong>{$str}</strong>";
    } else {
        return "\x1b[1m{$str}\x1b[0m";
    }
}

// Execute the "headers" command
function do_headers() {
    $is_first = true;

    foreach ($_SERVER as $key => $val) {
        if (substr($key, 0, 5) == 'HTTP_') {
            if ($is_first) {
                $is_first = false;
            } else {
                echo "\n";
            }

            $header_parts = explode('_', substr($key, 5));
            $header = strtolower(implode('-', $header_parts));
            echo esc($header).": ".esc($val);
        }
    }
}

// Execute the "ip" command
function do_ip() {
    global $SADDR;
    echo esc($SADDR);
}

// Execute the "ua" command
function do_ua() {
    global $UA;
    echo esc($UA);
}

// Execute the "help" command
function do_help() {
    echo "Usage: curl ip.fef.moe[/".underline('command')."]\n";
    echo "\n";
    echo "Available ".underline('command')."s:\n";
    echo "    ".strong('headers')."  print all HTTP request headers (in lowercase)\n";
    echo "    ".strong('help')."     print this help text\n";
    echo "    ".strong('ip')."       print your public facing IP address\n";
    echo "    ".       "  ". "       (default behavior if ".underline('command')." is omitted)\n";
    echo "    ".strong('ua')."       print your user agent\n";
    echo "\n";
    echo "HTTP response status codes:\n";
    echo "    ".strong('200')."      ".underline('command')." ran successfully\n";
    echo "    ".strong('204')."      request method was ".strong('OPTIONS')."\n";
    echo "    ".strong('404')."      unknown ".underline('command')." issued\n";
    echo "    ".strong('405')."      request method was not ".strong('GET')." or ".strong('OPTIONS');

    // if we are rendering to HTML, this message always shows up below the output field
    global $RENDER_HTML;
    if (!$RENDER_HTML) {
        global $DISCLAIMER;
        echo "\n\n";
        echo $DISCLAIMER;
    }
}

function if_cmd_is($test, $output) {
    global $CMD;
    if ($CMD == $test) {
        return $output;
    } else {
        return '';
    }
}

// Run the specified command
function run($cmd) {
    $method = $_SERVER['REQUEST_METHOD'];
    if ($method != 'GET') {
        echo "Illegal HTTP request method: ".esc($method)."\n";
        do_help();
        return;
    }

    switch ($cmd) {
    case 'ip':
        do_ip();
        break;
    case 'ua':
        do_ua();
        break;
    case 'headers':
        do_headers();
        break;
    case 'help':
        do_help();
        break;
    default:
        echo "Unknown command: ".esc($cmd)."\n";
        do_help();
        break;
    }
}

if ($RENDER_HTML) {
?><!doctype html>
<!--
Want to get rid of the HTML?
This tool tests your user agent against the regex <?= $BROWSER_REGEX ?>
to determine whether it is rendering to a graphical browser.
You can simply spoof your user agent or use curl to make it print
plain text (and ANSI escape sequences for the help command).
-->
<html>
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width,initial-scale=1.0">
    <title>fef's IP tool</title>
    <!-- see https://git.bsd.gay/fef/blog for the CSS sources -->
    <link rel="stylesheet" href="https://fef.moe/assets/css/main.css">
    <style>
        header ul, main, footer .container { max-width: 1200px; }
        .underline { text-decoration: underline; }
        .red { font-weight: 700; color: #ff5555; }
    </style>
</head>
<body>
    <header>
        <nav>
            <ul>
                <li<?= if_cmd_is('ip', ' aria-current="page"')      ?>><a href="/ip">IP Address</a></li>
                <li<?= if_cmd_is('ua', ' aria-current="page"')      ?>><a href="/ua">User Agent</a></li>
                <li<?= if_cmd_is('headers', ' aria-current="page"') ?>><a href="/headers">Headers</a></li>
                <li<?= if_cmd_is('help', ' aria-current="page"')    ?>><a href="/help">Help</a></li>
            </ul>
        </nav>
    </header>
    <main>
        <pre><code><?php
}

run($CMD);

if ($RENDER_HTML) { ?>
</code></pre>
    <p><?= $DISCLAIMER ?></p>
    </main>
    <footer>
        <div class="container">
            <div>
                <p>
                fef's IP utility
                &copy; 2022 anna &lt;owo&nbsp;-at-&nbsp;fef.moe&gt;
                </p>
                <p>
                You are seeing this fancy-pants HTML version because
                your user agent matches the regex <code><?= $BROWSER_REGEX ?></code>.
                If you want plaintext only, use a CLI tool like curl
                or spoof your user agent.
                </p>
            </div>
            <div>
                <ul>
                    <li>Source Code: <a href="https://git.bsd.gay/fef/iptool">Gitea</a></li>
                    <li>Main Website: <a href="https://fef.moe/">fef.moe</a></li>
                    <li>Twitter: <a href="https://twitter.com/libfef">@libfef</a></li>
                    <li>Fediverse: <a href="https://catcatnya.com/@fef">@fef@catcatnya.com</a></li>
                </ul>
            </div>
        </div>
    </footer>
</body>
</html>
<?php
} else {
	echo "\n";
}