OAuth & SSH Keygen
This commit is contained in:
		
							
								
								
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1 @@
 | 
			
		||||
vendor/
 | 
			
		||||
@@ -1,3 +1,5 @@
 | 
			
		||||
# Hackers Town Tilde User Generator
 | 
			
		||||
 | 
			
		||||
use Mastodon oauth to generate system users
 | 
			
		||||
 | 
			
		||||
Warrant canary available at /etc/ttyserver/canary
 | 
			
		||||
							
								
								
									
										155
									
								
								auth/index.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										155
									
								
								auth/index.php
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,155 @@
 | 
			
		||||
<?php
 | 
			
		||||
$config = json_decode(file_get_contents("/var/www/usergen/config.json", true));
 | 
			
		||||
 | 
			
		||||
if (isset($_REQUEST["act"])){
 | 
			
		||||
    // internal functions such as id request
 | 
			
		||||
    switch($_REQUEST["act"]){
 | 
			
		||||
        case "id":
 | 
			
		||||
            // return OAUTH app ID
 | 
			
		||||
            header('Content-type: application/json');
 | 
			
		||||
            echo json_encode(array("id" => $config->oauth->key));
 | 
			
		||||
            exit();
 | 
			
		||||
            break;
 | 
			
		||||
        default:
 | 
			
		||||
            break;
 | 
			
		||||
    }
 | 
			
		||||
}else if (isset($_REQUEST["code"])){
 | 
			
		||||
    // Mastodon callback
 | 
			
		||||
    $MastCode = $_REQUEST["code"];
 | 
			
		||||
}
 | 
			
		||||
?>
 | 
			
		||||
<HTML lang="en">
 | 
			
		||||
    <Head>
 | 
			
		||||
        <Title>HackersTown Server Access</Title>
 | 
			
		||||
        <meta charset="utf-8">
 | 
			
		||||
        <base href="/auth"/>
 | 
			
		||||
        <meta name="viewport" content="width=device-width, initial-scale=1">
 | 
			
		||||
        <!-- Stylesheets -->
 | 
			
		||||
        <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3" crossorigin="anonymous">
 | 
			
		||||
        <link href="/style.css" rel="stylesheet"/>
 | 
			
		||||
        <!-- Javascript -->
 | 
			
		||||
        <script src="https://code.jquery.com/jquery-3.6.0.min.js" integrity="sha256-/xUj+3OJU5yExlq6GSYGSHk7tPXikynS7ogEvDej/m4=" crossorigin="anonymous"></script>
 | 
			
		||||
        <script src="https://code.jquery.com/color/jquery.color.plus-names-2.1.2.min.js"></script>
 | 
			
		||||
        <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js" integrity="sha384-ka7Sk0Gln4gmtz2MlQnikT1wXgYsOg+OMhuP+IlRH9sENBO0LRn5q+8nbTov4+1p" crossorigin="anonymous"></script>
 | 
			
		||||
        <script src="https://cdn.jsdelivr.net/npm/jszip@3.9.1/dist/jszip.min.js" integrity="sha256-aSPPIlJfSHQ5T7wunbPcp7tM0rlq5dHoUGeN8O5odMg=" crossorigin="anonymous"></script>
 | 
			
		||||
        <script src="/base64url.js"></script>
 | 
			
		||||
        <script src="/ssh-util.js"></script>
 | 
			
		||||
        <script src="/keygen.js"></script>
 | 
			
		||||
        <script src="/fittext.js"></script>
 | 
			
		||||
        <script src="/index.js"></script>
 | 
			
		||||
    </Head>
 | 
			
		||||
    <Body>
 | 
			
		||||
        <div class="row">
 | 
			
		||||
            <div class="desktopOnly col-4"></div>
 | 
			
		||||
            <div id="content" class="col-4 center">
 | 
			
		||||
                <div class="row">
 | 
			
		||||
                    <a href="https://tty.hackers.town">
 | 
			
		||||
                        <img src="/Assets/HTown.png" class="logo self-align-center mx-auto d-block" alt="Hacker Town logo in ASCII art. Rendered as image to force correct visualization."/>
 | 
			
		||||
                    </a>
 | 
			
		||||
                </div>
 | 
			
		||||
                <?php 
 | 
			
		||||
                    // Query /oauth/token
 | 
			
		||||
                    $AuthToken = "";
 | 
			
		||||
                    $UserName = "";
 | 
			
		||||
                    $ErrorDesc = "";
 | 
			
		||||
                    $request = curl_init();
 | 
			
		||||
                    curl_setopt($request, CURLOPT_POST, 1);
 | 
			
		||||
                    curl_setopt($request, CURLOPT_URL, "https://hackers.town/oauth/token");
 | 
			
		||||
                    curl_setopt($request, CURLOPT_RETURNTRANSFER, 1);
 | 
			
		||||
                    // $reqirectUri = "urn:ietf:wg:oauth:2.0:oob";
 | 
			
		||||
                    $reqirectUri = "https://tty.hackers.town/auth";
 | 
			
		||||
                    $options = "grant_type=authorization_code&code=".$MastCode."&client_id=".$config->oauth->key."&client_secret=".$config->oauth->secret."&scope=read:accounts&redirect_uri=".$reqirectUri;
 | 
			
		||||
                    curl_setopt($request, CURLOPT_POSTFIELDS, $options);
 | 
			
		||||
                    // echo $options;
 | 
			
		||||
                    // echo json_encode($request);
 | 
			
		||||
                    $response = curl_exec($request);
 | 
			
		||||
                    curl_close($request);
 | 
			
		||||
                    // echo $response;
 | 
			
		||||
                    $Auth = json_decode($response);
 | 
			
		||||
                    if(isset($Auth->token_type)){
 | 
			
		||||
                        // Valid Auth?
 | 
			
		||||
                        $request = curl_init();
 | 
			
		||||
                        curl_setopt($request, CURLOPT_URL, "https://hackers.town/api/v1/accounts/verify_credentials");
 | 
			
		||||
                        curl_setopt($request, CURLOPT_RETURNTRANSFER, 1);
 | 
			
		||||
                        curl_setopt($request, CURLOPT_HTTPHEADER, array(
 | 
			
		||||
                            "Authorization: ".$Auth->token_type." ".$Auth->access_token
 | 
			
		||||
                        ));
 | 
			
		||||
                        $response = curl_exec($request);
 | 
			
		||||
                        curl_close($request);
 | 
			
		||||
                        $User = json_decode($response);
 | 
			
		||||
 | 
			
		||||
                        if (isset($User->id)){
 | 
			
		||||
                            // Congrats!
 | 
			
		||||
                            $AuthToken = $Auth->access_token;
 | 
			
		||||
                            $UserName = $User->display_name;
 | 
			
		||||
                        }else{
 | 
			
		||||
                            // invalid auth
 | 
			
		||||
                            $AuthToken = "BadUser";
 | 
			
		||||
                            $ErrorDesc = "User Not Found";
 | 
			
		||||
                        }
 | 
			
		||||
                    }else{
 | 
			
		||||
                        // invalid auth
 | 
			
		||||
                        $AuthToken = "BadOauth";
 | 
			
		||||
                        $ErrorDesc = "Invalid OAuth";
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    // revoke token after usage
 | 
			
		||||
                ?>
 | 
			
		||||
                <div id="usertoken" hidden><?php echo $AuthToken; ?></div>
 | 
			
		||||
                <div class="row"<?php if(strpos($AuthToken, "Bad") === false){
 | 
			
		||||
                    echo "hidden";
 | 
			
		||||
                }?>>
 | 
			
		||||
                    <!-- Select to upload public key or generate a new one locally -->
 | 
			
		||||
                    <span>
 | 
			
		||||
                        Invalid
 | 
			
		||||
                    </span>
 | 
			
		||||
                    <span>
 | 
			
		||||
                        try again
 | 
			
		||||
                    </span>
 | 
			
		||||
                    <div class="message">
 | 
			
		||||
                        <?php echo $ErrorDesc; ?>
 | 
			
		||||
                    </div>
 | 
			
		||||
                </div><div class="row button"<?php if(strpos($AuthToken, "Bad") === false){
 | 
			
		||||
                    echo "hidden";
 | 
			
		||||
                }?>>
 | 
			
		||||
                    <!-- Select to upload public key or generate a new one locally -->
 | 
			
		||||
                    <button class="col keyButton" onclick="beginOauth()">Retry</button>
 | 
			
		||||
                </div>
 | 
			
		||||
                <div class="row"<?php if(strpos($AuthToken, "Bad") !== false){
 | 
			
		||||
                    echo "hidden";
 | 
			
		||||
                }?>>
 | 
			
		||||
                    <!-- Select to upload public key or generate a new one locally -->
 | 
			
		||||
                    <span>
 | 
			
		||||
                        <?php 
 | 
			
		||||
                            $Welcomes = array("Welcome", "Dobrodošli", "Vitejte", "Welkom", "Tervetuloa", "Willkommen", "Fáilte", "Benvenuto", "Bienvenidos", "Välkommen", "ようこそ");
 | 
			
		||||
                            echo $Welcomes[array_rand($Welcomes)];
 | 
			
		||||
                        ?>
 | 
			
		||||
                    </span>
 | 
			
		||||
                    <span id="resizer">
 | 
			
		||||
                        <?php echo $UserName; ?>
 | 
			
		||||
                    </span>
 | 
			
		||||
                    <div class="message">
 | 
			
		||||
                        Setup an account SSH key
 | 
			
		||||
                    </div>
 | 
			
		||||
                </div>
 | 
			
		||||
                <div class="row button" <?php if(strpos($AuthToken, "Bad") !== false){
 | 
			
		||||
                    echo "hidden";
 | 
			
		||||
                }?>>
 | 
			
		||||
                    <button class="col keyButton" onclick="generateSSH('<?php echo $UserName; ?>')">Generate</button>
 | 
			
		||||
                    <button class="col keyButton" onclick="uploadSSH()">Upload</button>
 | 
			
		||||
                </div>
 | 
			
		||||
                <div class="row copyright">
 | 
			
		||||
                    <!-- TODO: Make this file PHP and make the canary dependent on /etc/ttyserver/canary -->
 | 
			
		||||
                    <?php 
 | 
			
		||||
                        if (file_exists("/etc/ttyserver/canary")){
 | 
			
		||||
                            echo "Canary";
 | 
			
		||||
                        }
 | 
			
		||||
                    ?>
 | 
			
		||||
                    <br>
 | 
			
		||||
                    Copyright ©️ 2022 Elizabeth Anne Cray
 | 
			
		||||
                </div>
 | 
			
		||||
            </div>
 | 
			
		||||
            <div class="desktopOnly col-4"></div>
 | 
			
		||||
        </div>
 | 
			
		||||
    </Body>
 | 
			
		||||
</HTML>
 | 
			
		||||
							
								
								
									
										31
									
								
								base64url.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										31
									
								
								base64url.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,31 @@
 | 
			
		||||
// adapted from https://tools.ietf.org/html/draft-ietf-jose-json-web-signature-08#appendix-C
 | 
			
		||||
 | 
			
		||||
function base64urlEncode(arg) {
 | 
			
		||||
    const step1 = window.btoa(arg); // Regular base64 encoder
 | 
			
		||||
    const step2 = step1.split("=")[0]; // Remove any trailing '='s
 | 
			
		||||
    const step3 = step2.replace(/\+/g, "-"); // 62nd char of encoding
 | 
			
		||||
    const step4 = step3.replace(/\//g, "_"); // 63rd char of encoding
 | 
			
		||||
    return step4;
 | 
			
		||||
  }
 | 
			
		||||
  
 | 
			
		||||
  function base64urlDecode(s) {
 | 
			
		||||
    const step1 = s.replace(/-/g, "+"); // 62nd char of encoding
 | 
			
		||||
    const step2 = step1.replace(/_/g, "/"); // 63rd char of encoding
 | 
			
		||||
    let step3 = step2;
 | 
			
		||||
    switch (step2.length % 4) { // Pad with trailing '='s
 | 
			
		||||
      case 0: // No pad chars in this case
 | 
			
		||||
        break;
 | 
			
		||||
      case 2: // Two pad chars
 | 
			
		||||
        step3 += "==";
 | 
			
		||||
        break;
 | 
			
		||||
      case 3: // One pad char
 | 
			
		||||
        step3 += "=";
 | 
			
		||||
        break;
 | 
			
		||||
      default:
 | 
			
		||||
        throw new Error("Illegal base64url string!");
 | 
			
		||||
    }
 | 
			
		||||
    return window.atob(step3); // Regular base64 decoder
 | 
			
		||||
  }
 | 
			
		||||
  
 | 
			
		||||
  const module = window.module || {};
 | 
			
		||||
  module.exports = { base64urlDecode, base64urlEncode };
 | 
			
		||||
							
								
								
									
										5
									
								
								composer.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								composer.json
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,5 @@
 | 
			
		||||
{
 | 
			
		||||
    "require": {
 | 
			
		||||
        "lrf141/oauth2-mastodon": "^1.0"
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										794
									
								
								composer.lock
									
									
									
										generated
									
									
									
										Normal file
									
								
							
							
						
						
									
										794
									
								
								composer.lock
									
									
									
										generated
									
									
									
										Normal file
									
								
							@@ -0,0 +1,794 @@
 | 
			
		||||
{
 | 
			
		||||
    "_readme": [
 | 
			
		||||
        "This file locks the dependencies of your project to a known state",
 | 
			
		||||
        "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
 | 
			
		||||
        "This file is @generated automatically"
 | 
			
		||||
    ],
 | 
			
		||||
    "content-hash": "d823e547e45f296dd119344b20f3fbcd",
 | 
			
		||||
    "packages": [
 | 
			
		||||
        {
 | 
			
		||||
            "name": "guzzlehttp/guzzle",
 | 
			
		||||
            "version": "7.4.2",
 | 
			
		||||
            "source": {
 | 
			
		||||
                "type": "git",
 | 
			
		||||
                "url": "https://github.com/guzzle/guzzle.git",
 | 
			
		||||
                "reference": "ac1ec1cd9b5624694c3a40be801d94137afb12b4"
 | 
			
		||||
            },
 | 
			
		||||
            "dist": {
 | 
			
		||||
                "type": "zip",
 | 
			
		||||
                "url": "https://api.github.com/repos/guzzle/guzzle/zipball/ac1ec1cd9b5624694c3a40be801d94137afb12b4",
 | 
			
		||||
                "reference": "ac1ec1cd9b5624694c3a40be801d94137afb12b4",
 | 
			
		||||
                "shasum": ""
 | 
			
		||||
            },
 | 
			
		||||
            "require": {
 | 
			
		||||
                "ext-json": "*",
 | 
			
		||||
                "guzzlehttp/promises": "^1.5",
 | 
			
		||||
                "guzzlehttp/psr7": "^1.8.3 || ^2.1",
 | 
			
		||||
                "php": "^7.2.5 || ^8.0",
 | 
			
		||||
                "psr/http-client": "^1.0",
 | 
			
		||||
                "symfony/deprecation-contracts": "^2.2 || ^3.0"
 | 
			
		||||
            },
 | 
			
		||||
            "provide": {
 | 
			
		||||
                "psr/http-client-implementation": "1.0"
 | 
			
		||||
            },
 | 
			
		||||
            "require-dev": {
 | 
			
		||||
                "bamarni/composer-bin-plugin": "^1.4.1",
 | 
			
		||||
                "ext-curl": "*",
 | 
			
		||||
                "php-http/client-integration-tests": "^3.0",
 | 
			
		||||
                "phpunit/phpunit": "^8.5.5 || ^9.3.5",
 | 
			
		||||
                "psr/log": "^1.1 || ^2.0 || ^3.0"
 | 
			
		||||
            },
 | 
			
		||||
            "suggest": {
 | 
			
		||||
                "ext-curl": "Required for CURL handler support",
 | 
			
		||||
                "ext-intl": "Required for Internationalized Domain Name (IDN) support",
 | 
			
		||||
                "psr/log": "Required for using the Log middleware"
 | 
			
		||||
            },
 | 
			
		||||
            "type": "library",
 | 
			
		||||
            "extra": {
 | 
			
		||||
                "branch-alias": {
 | 
			
		||||
                    "dev-master": "7.4-dev"
 | 
			
		||||
                }
 | 
			
		||||
            },
 | 
			
		||||
            "autoload": {
 | 
			
		||||
                "files": [
 | 
			
		||||
                    "src/functions_include.php"
 | 
			
		||||
                ],
 | 
			
		||||
                "psr-4": {
 | 
			
		||||
                    "GuzzleHttp\\": "src/"
 | 
			
		||||
                }
 | 
			
		||||
            },
 | 
			
		||||
            "notification-url": "https://packagist.org/downloads/",
 | 
			
		||||
            "license": [
 | 
			
		||||
                "MIT"
 | 
			
		||||
            ],
 | 
			
		||||
            "authors": [
 | 
			
		||||
                {
 | 
			
		||||
                    "name": "Graham Campbell",
 | 
			
		||||
                    "email": "hello@gjcampbell.co.uk",
 | 
			
		||||
                    "homepage": "https://github.com/GrahamCampbell"
 | 
			
		||||
                },
 | 
			
		||||
                {
 | 
			
		||||
                    "name": "Michael Dowling",
 | 
			
		||||
                    "email": "mtdowling@gmail.com",
 | 
			
		||||
                    "homepage": "https://github.com/mtdowling"
 | 
			
		||||
                },
 | 
			
		||||
                {
 | 
			
		||||
                    "name": "Jeremy Lindblom",
 | 
			
		||||
                    "email": "jeremeamia@gmail.com",
 | 
			
		||||
                    "homepage": "https://github.com/jeremeamia"
 | 
			
		||||
                },
 | 
			
		||||
                {
 | 
			
		||||
                    "name": "George Mponos",
 | 
			
		||||
                    "email": "gmponos@gmail.com",
 | 
			
		||||
                    "homepage": "https://github.com/gmponos"
 | 
			
		||||
                },
 | 
			
		||||
                {
 | 
			
		||||
                    "name": "Tobias Nyholm",
 | 
			
		||||
                    "email": "tobias.nyholm@gmail.com",
 | 
			
		||||
                    "homepage": "https://github.com/Nyholm"
 | 
			
		||||
                },
 | 
			
		||||
                {
 | 
			
		||||
                    "name": "Márk Sági-Kazár",
 | 
			
		||||
                    "email": "mark.sagikazar@gmail.com",
 | 
			
		||||
                    "homepage": "https://github.com/sagikazarmark"
 | 
			
		||||
                },
 | 
			
		||||
                {
 | 
			
		||||
                    "name": "Tobias Schultze",
 | 
			
		||||
                    "email": "webmaster@tubo-world.de",
 | 
			
		||||
                    "homepage": "https://github.com/Tobion"
 | 
			
		||||
                }
 | 
			
		||||
            ],
 | 
			
		||||
            "description": "Guzzle is a PHP HTTP client library",
 | 
			
		||||
            "keywords": [
 | 
			
		||||
                "client",
 | 
			
		||||
                "curl",
 | 
			
		||||
                "framework",
 | 
			
		||||
                "http",
 | 
			
		||||
                "http client",
 | 
			
		||||
                "psr-18",
 | 
			
		||||
                "psr-7",
 | 
			
		||||
                "rest",
 | 
			
		||||
                "web service"
 | 
			
		||||
            ],
 | 
			
		||||
            "support": {
 | 
			
		||||
                "issues": "https://github.com/guzzle/guzzle/issues",
 | 
			
		||||
                "source": "https://github.com/guzzle/guzzle/tree/7.4.2"
 | 
			
		||||
            },
 | 
			
		||||
            "funding": [
 | 
			
		||||
                {
 | 
			
		||||
                    "url": "https://github.com/GrahamCampbell",
 | 
			
		||||
                    "type": "github"
 | 
			
		||||
                },
 | 
			
		||||
                {
 | 
			
		||||
                    "url": "https://github.com/Nyholm",
 | 
			
		||||
                    "type": "github"
 | 
			
		||||
                },
 | 
			
		||||
                {
 | 
			
		||||
                    "url": "https://tidelift.com/funding/github/packagist/guzzlehttp/guzzle",
 | 
			
		||||
                    "type": "tidelift"
 | 
			
		||||
                }
 | 
			
		||||
            ],
 | 
			
		||||
            "time": "2022-03-20T14:16:28+00:00"
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
            "name": "guzzlehttp/promises",
 | 
			
		||||
            "version": "1.5.1",
 | 
			
		||||
            "source": {
 | 
			
		||||
                "type": "git",
 | 
			
		||||
                "url": "https://github.com/guzzle/promises.git",
 | 
			
		||||
                "reference": "fe752aedc9fd8fcca3fe7ad05d419d32998a06da"
 | 
			
		||||
            },
 | 
			
		||||
            "dist": {
 | 
			
		||||
                "type": "zip",
 | 
			
		||||
                "url": "https://api.github.com/repos/guzzle/promises/zipball/fe752aedc9fd8fcca3fe7ad05d419d32998a06da",
 | 
			
		||||
                "reference": "fe752aedc9fd8fcca3fe7ad05d419d32998a06da",
 | 
			
		||||
                "shasum": ""
 | 
			
		||||
            },
 | 
			
		||||
            "require": {
 | 
			
		||||
                "php": ">=5.5"
 | 
			
		||||
            },
 | 
			
		||||
            "require-dev": {
 | 
			
		||||
                "symfony/phpunit-bridge": "^4.4 || ^5.1"
 | 
			
		||||
            },
 | 
			
		||||
            "type": "library",
 | 
			
		||||
            "extra": {
 | 
			
		||||
                "branch-alias": {
 | 
			
		||||
                    "dev-master": "1.5-dev"
 | 
			
		||||
                }
 | 
			
		||||
            },
 | 
			
		||||
            "autoload": {
 | 
			
		||||
                "files": [
 | 
			
		||||
                    "src/functions_include.php"
 | 
			
		||||
                ],
 | 
			
		||||
                "psr-4": {
 | 
			
		||||
                    "GuzzleHttp\\Promise\\": "src/"
 | 
			
		||||
                }
 | 
			
		||||
            },
 | 
			
		||||
            "notification-url": "https://packagist.org/downloads/",
 | 
			
		||||
            "license": [
 | 
			
		||||
                "MIT"
 | 
			
		||||
            ],
 | 
			
		||||
            "authors": [
 | 
			
		||||
                {
 | 
			
		||||
                    "name": "Graham Campbell",
 | 
			
		||||
                    "email": "hello@gjcampbell.co.uk",
 | 
			
		||||
                    "homepage": "https://github.com/GrahamCampbell"
 | 
			
		||||
                },
 | 
			
		||||
                {
 | 
			
		||||
                    "name": "Michael Dowling",
 | 
			
		||||
                    "email": "mtdowling@gmail.com",
 | 
			
		||||
                    "homepage": "https://github.com/mtdowling"
 | 
			
		||||
                },
 | 
			
		||||
                {
 | 
			
		||||
                    "name": "Tobias Nyholm",
 | 
			
		||||
                    "email": "tobias.nyholm@gmail.com",
 | 
			
		||||
                    "homepage": "https://github.com/Nyholm"
 | 
			
		||||
                },
 | 
			
		||||
                {
 | 
			
		||||
                    "name": "Tobias Schultze",
 | 
			
		||||
                    "email": "webmaster@tubo-world.de",
 | 
			
		||||
                    "homepage": "https://github.com/Tobion"
 | 
			
		||||
                }
 | 
			
		||||
            ],
 | 
			
		||||
            "description": "Guzzle promises library",
 | 
			
		||||
            "keywords": [
 | 
			
		||||
                "promise"
 | 
			
		||||
            ],
 | 
			
		||||
            "support": {
 | 
			
		||||
                "issues": "https://github.com/guzzle/promises/issues",
 | 
			
		||||
                "source": "https://github.com/guzzle/promises/tree/1.5.1"
 | 
			
		||||
            },
 | 
			
		||||
            "funding": [
 | 
			
		||||
                {
 | 
			
		||||
                    "url": "https://github.com/GrahamCampbell",
 | 
			
		||||
                    "type": "github"
 | 
			
		||||
                },
 | 
			
		||||
                {
 | 
			
		||||
                    "url": "https://github.com/Nyholm",
 | 
			
		||||
                    "type": "github"
 | 
			
		||||
                },
 | 
			
		||||
                {
 | 
			
		||||
                    "url": "https://tidelift.com/funding/github/packagist/guzzlehttp/promises",
 | 
			
		||||
                    "type": "tidelift"
 | 
			
		||||
                }
 | 
			
		||||
            ],
 | 
			
		||||
            "time": "2021-10-22T20:56:57+00:00"
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
            "name": "guzzlehttp/psr7",
 | 
			
		||||
            "version": "2.2.1",
 | 
			
		||||
            "source": {
 | 
			
		||||
                "type": "git",
 | 
			
		||||
                "url": "https://github.com/guzzle/psr7.git",
 | 
			
		||||
                "reference": "c94a94f120803a18554c1805ef2e539f8285f9a2"
 | 
			
		||||
            },
 | 
			
		||||
            "dist": {
 | 
			
		||||
                "type": "zip",
 | 
			
		||||
                "url": "https://api.github.com/repos/guzzle/psr7/zipball/c94a94f120803a18554c1805ef2e539f8285f9a2",
 | 
			
		||||
                "reference": "c94a94f120803a18554c1805ef2e539f8285f9a2",
 | 
			
		||||
                "shasum": ""
 | 
			
		||||
            },
 | 
			
		||||
            "require": {
 | 
			
		||||
                "php": "^7.2.5 || ^8.0",
 | 
			
		||||
                "psr/http-factory": "^1.0",
 | 
			
		||||
                "psr/http-message": "^1.0",
 | 
			
		||||
                "ralouphie/getallheaders": "^3.0"
 | 
			
		||||
            },
 | 
			
		||||
            "provide": {
 | 
			
		||||
                "psr/http-factory-implementation": "1.0",
 | 
			
		||||
                "psr/http-message-implementation": "1.0"
 | 
			
		||||
            },
 | 
			
		||||
            "require-dev": {
 | 
			
		||||
                "bamarni/composer-bin-plugin": "^1.4.1",
 | 
			
		||||
                "http-interop/http-factory-tests": "^0.9",
 | 
			
		||||
                "phpunit/phpunit": "^8.5.8 || ^9.3.10"
 | 
			
		||||
            },
 | 
			
		||||
            "suggest": {
 | 
			
		||||
                "laminas/laminas-httphandlerrunner": "Emit PSR-7 responses"
 | 
			
		||||
            },
 | 
			
		||||
            "type": "library",
 | 
			
		||||
            "extra": {
 | 
			
		||||
                "branch-alias": {
 | 
			
		||||
                    "dev-master": "2.2-dev"
 | 
			
		||||
                }
 | 
			
		||||
            },
 | 
			
		||||
            "autoload": {
 | 
			
		||||
                "psr-4": {
 | 
			
		||||
                    "GuzzleHttp\\Psr7\\": "src/"
 | 
			
		||||
                }
 | 
			
		||||
            },
 | 
			
		||||
            "notification-url": "https://packagist.org/downloads/",
 | 
			
		||||
            "license": [
 | 
			
		||||
                "MIT"
 | 
			
		||||
            ],
 | 
			
		||||
            "authors": [
 | 
			
		||||
                {
 | 
			
		||||
                    "name": "Graham Campbell",
 | 
			
		||||
                    "email": "hello@gjcampbell.co.uk",
 | 
			
		||||
                    "homepage": "https://github.com/GrahamCampbell"
 | 
			
		||||
                },
 | 
			
		||||
                {
 | 
			
		||||
                    "name": "Michael Dowling",
 | 
			
		||||
                    "email": "mtdowling@gmail.com",
 | 
			
		||||
                    "homepage": "https://github.com/mtdowling"
 | 
			
		||||
                },
 | 
			
		||||
                {
 | 
			
		||||
                    "name": "George Mponos",
 | 
			
		||||
                    "email": "gmponos@gmail.com",
 | 
			
		||||
                    "homepage": "https://github.com/gmponos"
 | 
			
		||||
                },
 | 
			
		||||
                {
 | 
			
		||||
                    "name": "Tobias Nyholm",
 | 
			
		||||
                    "email": "tobias.nyholm@gmail.com",
 | 
			
		||||
                    "homepage": "https://github.com/Nyholm"
 | 
			
		||||
                },
 | 
			
		||||
                {
 | 
			
		||||
                    "name": "Márk Sági-Kazár",
 | 
			
		||||
                    "email": "mark.sagikazar@gmail.com",
 | 
			
		||||
                    "homepage": "https://github.com/sagikazarmark"
 | 
			
		||||
                },
 | 
			
		||||
                {
 | 
			
		||||
                    "name": "Tobias Schultze",
 | 
			
		||||
                    "email": "webmaster@tubo-world.de",
 | 
			
		||||
                    "homepage": "https://github.com/Tobion"
 | 
			
		||||
                },
 | 
			
		||||
                {
 | 
			
		||||
                    "name": "Márk Sági-Kazár",
 | 
			
		||||
                    "email": "mark.sagikazar@gmail.com",
 | 
			
		||||
                    "homepage": "https://sagikazarmark.hu"
 | 
			
		||||
                }
 | 
			
		||||
            ],
 | 
			
		||||
            "description": "PSR-7 message implementation that also provides common utility methods",
 | 
			
		||||
            "keywords": [
 | 
			
		||||
                "http",
 | 
			
		||||
                "message",
 | 
			
		||||
                "psr-7",
 | 
			
		||||
                "request",
 | 
			
		||||
                "response",
 | 
			
		||||
                "stream",
 | 
			
		||||
                "uri",
 | 
			
		||||
                "url"
 | 
			
		||||
            ],
 | 
			
		||||
            "support": {
 | 
			
		||||
                "issues": "https://github.com/guzzle/psr7/issues",
 | 
			
		||||
                "source": "https://github.com/guzzle/psr7/tree/2.2.1"
 | 
			
		||||
            },
 | 
			
		||||
            "funding": [
 | 
			
		||||
                {
 | 
			
		||||
                    "url": "https://github.com/GrahamCampbell",
 | 
			
		||||
                    "type": "github"
 | 
			
		||||
                },
 | 
			
		||||
                {
 | 
			
		||||
                    "url": "https://github.com/Nyholm",
 | 
			
		||||
                    "type": "github"
 | 
			
		||||
                },
 | 
			
		||||
                {
 | 
			
		||||
                    "url": "https://tidelift.com/funding/github/packagist/guzzlehttp/psr7",
 | 
			
		||||
                    "type": "tidelift"
 | 
			
		||||
                }
 | 
			
		||||
            ],
 | 
			
		||||
            "time": "2022-03-20T21:55:58+00:00"
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
            "name": "league/oauth2-client",
 | 
			
		||||
            "version": "2.6.1",
 | 
			
		||||
            "source": {
 | 
			
		||||
                "type": "git",
 | 
			
		||||
                "url": "https://github.com/thephpleague/oauth2-client.git",
 | 
			
		||||
                "reference": "2334c249907190c132364f5dae0287ab8666aa19"
 | 
			
		||||
            },
 | 
			
		||||
            "dist": {
 | 
			
		||||
                "type": "zip",
 | 
			
		||||
                "url": "https://api.github.com/repos/thephpleague/oauth2-client/zipball/2334c249907190c132364f5dae0287ab8666aa19",
 | 
			
		||||
                "reference": "2334c249907190c132364f5dae0287ab8666aa19",
 | 
			
		||||
                "shasum": ""
 | 
			
		||||
            },
 | 
			
		||||
            "require": {
 | 
			
		||||
                "guzzlehttp/guzzle": "^6.0 || ^7.0",
 | 
			
		||||
                "paragonie/random_compat": "^1 || ^2 || ^9.99",
 | 
			
		||||
                "php": "^5.6 || ^7.0 || ^8.0"
 | 
			
		||||
            },
 | 
			
		||||
            "require-dev": {
 | 
			
		||||
                "mockery/mockery": "^1.3.5",
 | 
			
		||||
                "php-parallel-lint/php-parallel-lint": "^1.3.1",
 | 
			
		||||
                "phpunit/phpunit": "^5.7 || ^6.0 || ^9.5",
 | 
			
		||||
                "squizlabs/php_codesniffer": "^2.3 || ^3.0"
 | 
			
		||||
            },
 | 
			
		||||
            "type": "library",
 | 
			
		||||
            "extra": {
 | 
			
		||||
                "branch-alias": {
 | 
			
		||||
                    "dev-2.x": "2.0.x-dev"
 | 
			
		||||
                }
 | 
			
		||||
            },
 | 
			
		||||
            "autoload": {
 | 
			
		||||
                "psr-4": {
 | 
			
		||||
                    "League\\OAuth2\\Client\\": "src/"
 | 
			
		||||
                }
 | 
			
		||||
            },
 | 
			
		||||
            "notification-url": "https://packagist.org/downloads/",
 | 
			
		||||
            "license": [
 | 
			
		||||
                "MIT"
 | 
			
		||||
            ],
 | 
			
		||||
            "authors": [
 | 
			
		||||
                {
 | 
			
		||||
                    "name": "Alex Bilbie",
 | 
			
		||||
                    "email": "hello@alexbilbie.com",
 | 
			
		||||
                    "homepage": "http://www.alexbilbie.com",
 | 
			
		||||
                    "role": "Developer"
 | 
			
		||||
                },
 | 
			
		||||
                {
 | 
			
		||||
                    "name": "Woody Gilk",
 | 
			
		||||
                    "homepage": "https://github.com/shadowhand",
 | 
			
		||||
                    "role": "Contributor"
 | 
			
		||||
                }
 | 
			
		||||
            ],
 | 
			
		||||
            "description": "OAuth 2.0 Client Library",
 | 
			
		||||
            "keywords": [
 | 
			
		||||
                "Authentication",
 | 
			
		||||
                "SSO",
 | 
			
		||||
                "authorization",
 | 
			
		||||
                "identity",
 | 
			
		||||
                "idp",
 | 
			
		||||
                "oauth",
 | 
			
		||||
                "oauth2",
 | 
			
		||||
                "single sign on"
 | 
			
		||||
            ],
 | 
			
		||||
            "support": {
 | 
			
		||||
                "issues": "https://github.com/thephpleague/oauth2-client/issues",
 | 
			
		||||
                "source": "https://github.com/thephpleague/oauth2-client/tree/2.6.1"
 | 
			
		||||
            },
 | 
			
		||||
            "time": "2021-12-22T16:42:49+00:00"
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
            "name": "lrf141/oauth2-mastodon",
 | 
			
		||||
            "version": "1.0.1",
 | 
			
		||||
            "source": {
 | 
			
		||||
                "type": "git",
 | 
			
		||||
                "url": "https://github.com/lrf141/oauth2-mastodon.git",
 | 
			
		||||
                "reference": "ba051985643bf46788c151dc70bc8ee85edff6a4"
 | 
			
		||||
            },
 | 
			
		||||
            "dist": {
 | 
			
		||||
                "type": "zip",
 | 
			
		||||
                "url": "https://api.github.com/repos/lrf141/oauth2-mastodon/zipball/ba051985643bf46788c151dc70bc8ee85edff6a4",
 | 
			
		||||
                "reference": "ba051985643bf46788c151dc70bc8ee85edff6a4",
 | 
			
		||||
                "shasum": ""
 | 
			
		||||
            },
 | 
			
		||||
            "require": {
 | 
			
		||||
                "league/oauth2-client": "^2.0"
 | 
			
		||||
            },
 | 
			
		||||
            "require-dev": {
 | 
			
		||||
                "mockery/mockery": "^1.1",
 | 
			
		||||
                "phpunit/phpunit": ">=5.4.3",
 | 
			
		||||
                "squizlabs/php_codesniffer": "^2.3"
 | 
			
		||||
            },
 | 
			
		||||
            "type": "library",
 | 
			
		||||
            "extra": {
 | 
			
		||||
                "branch-alias": {
 | 
			
		||||
                    "dev-master": "1.0-dev"
 | 
			
		||||
                }
 | 
			
		||||
            },
 | 
			
		||||
            "autoload": {
 | 
			
		||||
                "psr-4": {
 | 
			
		||||
                    "Lrf141\\OAuth2\\Client\\": "src"
 | 
			
		||||
                }
 | 
			
		||||
            },
 | 
			
		||||
            "notification-url": "https://packagist.org/downloads/",
 | 
			
		||||
            "license": [
 | 
			
		||||
                "MIT"
 | 
			
		||||
            ],
 | 
			
		||||
            "authors": [
 | 
			
		||||
                {
 | 
			
		||||
                    "name": "K.Takeuchi",
 | 
			
		||||
                    "email": "ghost141.kentyo@gmail.com",
 | 
			
		||||
                    "homepage": "https://github.com/lrf141",
 | 
			
		||||
                    "role": "Developer"
 | 
			
		||||
                }
 | 
			
		||||
            ],
 | 
			
		||||
            "description": "Mastodon OAuth 2.0 support for the PHP League's OAuth 2.0 Client",
 | 
			
		||||
            "homepage": "https://github.com/lrf141/oauth2-client",
 | 
			
		||||
            "keywords": [
 | 
			
		||||
                "authorization",
 | 
			
		||||
                "client",
 | 
			
		||||
                "lrf141",
 | 
			
		||||
                "mastodon",
 | 
			
		||||
                "oauth2",
 | 
			
		||||
                "oauth2-mastodon"
 | 
			
		||||
            ],
 | 
			
		||||
            "support": {
 | 
			
		||||
                "issues": "https://github.com/lrf141/oauth2-mastodon/issues",
 | 
			
		||||
                "source": "https://github.com/lrf141/oauth2-mastodon/tree/1.0.1"
 | 
			
		||||
            },
 | 
			
		||||
            "time": "2018-08-31T08:03:49+00:00"
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
            "name": "paragonie/random_compat",
 | 
			
		||||
            "version": "v9.99.100",
 | 
			
		||||
            "source": {
 | 
			
		||||
                "type": "git",
 | 
			
		||||
                "url": "https://github.com/paragonie/random_compat.git",
 | 
			
		||||
                "reference": "996434e5492cb4c3edcb9168db6fbb1359ef965a"
 | 
			
		||||
            },
 | 
			
		||||
            "dist": {
 | 
			
		||||
                "type": "zip",
 | 
			
		||||
                "url": "https://api.github.com/repos/paragonie/random_compat/zipball/996434e5492cb4c3edcb9168db6fbb1359ef965a",
 | 
			
		||||
                "reference": "996434e5492cb4c3edcb9168db6fbb1359ef965a",
 | 
			
		||||
                "shasum": ""
 | 
			
		||||
            },
 | 
			
		||||
            "require": {
 | 
			
		||||
                "php": ">= 7"
 | 
			
		||||
            },
 | 
			
		||||
            "require-dev": {
 | 
			
		||||
                "phpunit/phpunit": "4.*|5.*",
 | 
			
		||||
                "vimeo/psalm": "^1"
 | 
			
		||||
            },
 | 
			
		||||
            "suggest": {
 | 
			
		||||
                "ext-libsodium": "Provides a modern crypto API that can be used to generate random bytes."
 | 
			
		||||
            },
 | 
			
		||||
            "type": "library",
 | 
			
		||||
            "notification-url": "https://packagist.org/downloads/",
 | 
			
		||||
            "license": [
 | 
			
		||||
                "MIT"
 | 
			
		||||
            ],
 | 
			
		||||
            "authors": [
 | 
			
		||||
                {
 | 
			
		||||
                    "name": "Paragon Initiative Enterprises",
 | 
			
		||||
                    "email": "security@paragonie.com",
 | 
			
		||||
                    "homepage": "https://paragonie.com"
 | 
			
		||||
                }
 | 
			
		||||
            ],
 | 
			
		||||
            "description": "PHP 5.x polyfill for random_bytes() and random_int() from PHP 7",
 | 
			
		||||
            "keywords": [
 | 
			
		||||
                "csprng",
 | 
			
		||||
                "polyfill",
 | 
			
		||||
                "pseudorandom",
 | 
			
		||||
                "random"
 | 
			
		||||
            ],
 | 
			
		||||
            "support": {
 | 
			
		||||
                "email": "info@paragonie.com",
 | 
			
		||||
                "issues": "https://github.com/paragonie/random_compat/issues",
 | 
			
		||||
                "source": "https://github.com/paragonie/random_compat"
 | 
			
		||||
            },
 | 
			
		||||
            "time": "2020-10-15T08:29:30+00:00"
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
            "name": "psr/http-client",
 | 
			
		||||
            "version": "1.0.1",
 | 
			
		||||
            "source": {
 | 
			
		||||
                "type": "git",
 | 
			
		||||
                "url": "https://github.com/php-fig/http-client.git",
 | 
			
		||||
                "reference": "2dfb5f6c5eff0e91e20e913f8c5452ed95b86621"
 | 
			
		||||
            },
 | 
			
		||||
            "dist": {
 | 
			
		||||
                "type": "zip",
 | 
			
		||||
                "url": "https://api.github.com/repos/php-fig/http-client/zipball/2dfb5f6c5eff0e91e20e913f8c5452ed95b86621",
 | 
			
		||||
                "reference": "2dfb5f6c5eff0e91e20e913f8c5452ed95b86621",
 | 
			
		||||
                "shasum": ""
 | 
			
		||||
            },
 | 
			
		||||
            "require": {
 | 
			
		||||
                "php": "^7.0 || ^8.0",
 | 
			
		||||
                "psr/http-message": "^1.0"
 | 
			
		||||
            },
 | 
			
		||||
            "type": "library",
 | 
			
		||||
            "extra": {
 | 
			
		||||
                "branch-alias": {
 | 
			
		||||
                    "dev-master": "1.0.x-dev"
 | 
			
		||||
                }
 | 
			
		||||
            },
 | 
			
		||||
            "autoload": {
 | 
			
		||||
                "psr-4": {
 | 
			
		||||
                    "Psr\\Http\\Client\\": "src/"
 | 
			
		||||
                }
 | 
			
		||||
            },
 | 
			
		||||
            "notification-url": "https://packagist.org/downloads/",
 | 
			
		||||
            "license": [
 | 
			
		||||
                "MIT"
 | 
			
		||||
            ],
 | 
			
		||||
            "authors": [
 | 
			
		||||
                {
 | 
			
		||||
                    "name": "PHP-FIG",
 | 
			
		||||
                    "homepage": "http://www.php-fig.org/"
 | 
			
		||||
                }
 | 
			
		||||
            ],
 | 
			
		||||
            "description": "Common interface for HTTP clients",
 | 
			
		||||
            "homepage": "https://github.com/php-fig/http-client",
 | 
			
		||||
            "keywords": [
 | 
			
		||||
                "http",
 | 
			
		||||
                "http-client",
 | 
			
		||||
                "psr",
 | 
			
		||||
                "psr-18"
 | 
			
		||||
            ],
 | 
			
		||||
            "support": {
 | 
			
		||||
                "source": "https://github.com/php-fig/http-client/tree/master"
 | 
			
		||||
            },
 | 
			
		||||
            "time": "2020-06-29T06:28:15+00:00"
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
            "name": "psr/http-factory",
 | 
			
		||||
            "version": "1.0.1",
 | 
			
		||||
            "source": {
 | 
			
		||||
                "type": "git",
 | 
			
		||||
                "url": "https://github.com/php-fig/http-factory.git",
 | 
			
		||||
                "reference": "12ac7fcd07e5b077433f5f2bee95b3a771bf61be"
 | 
			
		||||
            },
 | 
			
		||||
            "dist": {
 | 
			
		||||
                "type": "zip",
 | 
			
		||||
                "url": "https://api.github.com/repos/php-fig/http-factory/zipball/12ac7fcd07e5b077433f5f2bee95b3a771bf61be",
 | 
			
		||||
                "reference": "12ac7fcd07e5b077433f5f2bee95b3a771bf61be",
 | 
			
		||||
                "shasum": ""
 | 
			
		||||
            },
 | 
			
		||||
            "require": {
 | 
			
		||||
                "php": ">=7.0.0",
 | 
			
		||||
                "psr/http-message": "^1.0"
 | 
			
		||||
            },
 | 
			
		||||
            "type": "library",
 | 
			
		||||
            "extra": {
 | 
			
		||||
                "branch-alias": {
 | 
			
		||||
                    "dev-master": "1.0.x-dev"
 | 
			
		||||
                }
 | 
			
		||||
            },
 | 
			
		||||
            "autoload": {
 | 
			
		||||
                "psr-4": {
 | 
			
		||||
                    "Psr\\Http\\Message\\": "src/"
 | 
			
		||||
                }
 | 
			
		||||
            },
 | 
			
		||||
            "notification-url": "https://packagist.org/downloads/",
 | 
			
		||||
            "license": [
 | 
			
		||||
                "MIT"
 | 
			
		||||
            ],
 | 
			
		||||
            "authors": [
 | 
			
		||||
                {
 | 
			
		||||
                    "name": "PHP-FIG",
 | 
			
		||||
                    "homepage": "http://www.php-fig.org/"
 | 
			
		||||
                }
 | 
			
		||||
            ],
 | 
			
		||||
            "description": "Common interfaces for PSR-7 HTTP message factories",
 | 
			
		||||
            "keywords": [
 | 
			
		||||
                "factory",
 | 
			
		||||
                "http",
 | 
			
		||||
                "message",
 | 
			
		||||
                "psr",
 | 
			
		||||
                "psr-17",
 | 
			
		||||
                "psr-7",
 | 
			
		||||
                "request",
 | 
			
		||||
                "response"
 | 
			
		||||
            ],
 | 
			
		||||
            "support": {
 | 
			
		||||
                "source": "https://github.com/php-fig/http-factory/tree/master"
 | 
			
		||||
            },
 | 
			
		||||
            "time": "2019-04-30T12:38:16+00:00"
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
            "name": "psr/http-message",
 | 
			
		||||
            "version": "1.0.1",
 | 
			
		||||
            "source": {
 | 
			
		||||
                "type": "git",
 | 
			
		||||
                "url": "https://github.com/php-fig/http-message.git",
 | 
			
		||||
                "reference": "f6561bf28d520154e4b0ec72be95418abe6d9363"
 | 
			
		||||
            },
 | 
			
		||||
            "dist": {
 | 
			
		||||
                "type": "zip",
 | 
			
		||||
                "url": "https://api.github.com/repos/php-fig/http-message/zipball/f6561bf28d520154e4b0ec72be95418abe6d9363",
 | 
			
		||||
                "reference": "f6561bf28d520154e4b0ec72be95418abe6d9363",
 | 
			
		||||
                "shasum": ""
 | 
			
		||||
            },
 | 
			
		||||
            "require": {
 | 
			
		||||
                "php": ">=5.3.0"
 | 
			
		||||
            },
 | 
			
		||||
            "type": "library",
 | 
			
		||||
            "extra": {
 | 
			
		||||
                "branch-alias": {
 | 
			
		||||
                    "dev-master": "1.0.x-dev"
 | 
			
		||||
                }
 | 
			
		||||
            },
 | 
			
		||||
            "autoload": {
 | 
			
		||||
                "psr-4": {
 | 
			
		||||
                    "Psr\\Http\\Message\\": "src/"
 | 
			
		||||
                }
 | 
			
		||||
            },
 | 
			
		||||
            "notification-url": "https://packagist.org/downloads/",
 | 
			
		||||
            "license": [
 | 
			
		||||
                "MIT"
 | 
			
		||||
            ],
 | 
			
		||||
            "authors": [
 | 
			
		||||
                {
 | 
			
		||||
                    "name": "PHP-FIG",
 | 
			
		||||
                    "homepage": "http://www.php-fig.org/"
 | 
			
		||||
                }
 | 
			
		||||
            ],
 | 
			
		||||
            "description": "Common interface for HTTP messages",
 | 
			
		||||
            "homepage": "https://github.com/php-fig/http-message",
 | 
			
		||||
            "keywords": [
 | 
			
		||||
                "http",
 | 
			
		||||
                "http-message",
 | 
			
		||||
                "psr",
 | 
			
		||||
                "psr-7",
 | 
			
		||||
                "request",
 | 
			
		||||
                "response"
 | 
			
		||||
            ],
 | 
			
		||||
            "support": {
 | 
			
		||||
                "source": "https://github.com/php-fig/http-message/tree/master"
 | 
			
		||||
            },
 | 
			
		||||
            "time": "2016-08-06T14:39:51+00:00"
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
            "name": "ralouphie/getallheaders",
 | 
			
		||||
            "version": "3.0.3",
 | 
			
		||||
            "source": {
 | 
			
		||||
                "type": "git",
 | 
			
		||||
                "url": "https://github.com/ralouphie/getallheaders.git",
 | 
			
		||||
                "reference": "120b605dfeb996808c31b6477290a714d356e822"
 | 
			
		||||
            },
 | 
			
		||||
            "dist": {
 | 
			
		||||
                "type": "zip",
 | 
			
		||||
                "url": "https://api.github.com/repos/ralouphie/getallheaders/zipball/120b605dfeb996808c31b6477290a714d356e822",
 | 
			
		||||
                "reference": "120b605dfeb996808c31b6477290a714d356e822",
 | 
			
		||||
                "shasum": ""
 | 
			
		||||
            },
 | 
			
		||||
            "require": {
 | 
			
		||||
                "php": ">=5.6"
 | 
			
		||||
            },
 | 
			
		||||
            "require-dev": {
 | 
			
		||||
                "php-coveralls/php-coveralls": "^2.1",
 | 
			
		||||
                "phpunit/phpunit": "^5 || ^6.5"
 | 
			
		||||
            },
 | 
			
		||||
            "type": "library",
 | 
			
		||||
            "autoload": {
 | 
			
		||||
                "files": [
 | 
			
		||||
                    "src/getallheaders.php"
 | 
			
		||||
                ]
 | 
			
		||||
            },
 | 
			
		||||
            "notification-url": "https://packagist.org/downloads/",
 | 
			
		||||
            "license": [
 | 
			
		||||
                "MIT"
 | 
			
		||||
            ],
 | 
			
		||||
            "authors": [
 | 
			
		||||
                {
 | 
			
		||||
                    "name": "Ralph Khattar",
 | 
			
		||||
                    "email": "ralph.khattar@gmail.com"
 | 
			
		||||
                }
 | 
			
		||||
            ],
 | 
			
		||||
            "description": "A polyfill for getallheaders.",
 | 
			
		||||
            "support": {
 | 
			
		||||
                "issues": "https://github.com/ralouphie/getallheaders/issues",
 | 
			
		||||
                "source": "https://github.com/ralouphie/getallheaders/tree/develop"
 | 
			
		||||
            },
 | 
			
		||||
            "time": "2019-03-08T08:55:37+00:00"
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
            "name": "symfony/deprecation-contracts",
 | 
			
		||||
            "version": "v3.0.1",
 | 
			
		||||
            "source": {
 | 
			
		||||
                "type": "git",
 | 
			
		||||
                "url": "https://github.com/symfony/deprecation-contracts.git",
 | 
			
		||||
                "reference": "26954b3d62a6c5fd0ea8a2a00c0353a14978d05c"
 | 
			
		||||
            },
 | 
			
		||||
            "dist": {
 | 
			
		||||
                "type": "zip",
 | 
			
		||||
                "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/26954b3d62a6c5fd0ea8a2a00c0353a14978d05c",
 | 
			
		||||
                "reference": "26954b3d62a6c5fd0ea8a2a00c0353a14978d05c",
 | 
			
		||||
                "shasum": ""
 | 
			
		||||
            },
 | 
			
		||||
            "require": {
 | 
			
		||||
                "php": ">=8.0.2"
 | 
			
		||||
            },
 | 
			
		||||
            "type": "library",
 | 
			
		||||
            "extra": {
 | 
			
		||||
                "branch-alias": {
 | 
			
		||||
                    "dev-main": "3.0-dev"
 | 
			
		||||
                },
 | 
			
		||||
                "thanks": {
 | 
			
		||||
                    "name": "symfony/contracts",
 | 
			
		||||
                    "url": "https://github.com/symfony/contracts"
 | 
			
		||||
                }
 | 
			
		||||
            },
 | 
			
		||||
            "autoload": {
 | 
			
		||||
                "files": [
 | 
			
		||||
                    "function.php"
 | 
			
		||||
                ]
 | 
			
		||||
            },
 | 
			
		||||
            "notification-url": "https://packagist.org/downloads/",
 | 
			
		||||
            "license": [
 | 
			
		||||
                "MIT"
 | 
			
		||||
            ],
 | 
			
		||||
            "authors": [
 | 
			
		||||
                {
 | 
			
		||||
                    "name": "Nicolas Grekas",
 | 
			
		||||
                    "email": "p@tchwork.com"
 | 
			
		||||
                },
 | 
			
		||||
                {
 | 
			
		||||
                    "name": "Symfony Community",
 | 
			
		||||
                    "homepage": "https://symfony.com/contributors"
 | 
			
		||||
                }
 | 
			
		||||
            ],
 | 
			
		||||
            "description": "A generic function and convention to trigger deprecation notices",
 | 
			
		||||
            "homepage": "https://symfony.com",
 | 
			
		||||
            "support": {
 | 
			
		||||
                "source": "https://github.com/symfony/deprecation-contracts/tree/v3.0.1"
 | 
			
		||||
            },
 | 
			
		||||
            "funding": [
 | 
			
		||||
                {
 | 
			
		||||
                    "url": "https://symfony.com/sponsor",
 | 
			
		||||
                    "type": "custom"
 | 
			
		||||
                },
 | 
			
		||||
                {
 | 
			
		||||
                    "url": "https://github.com/fabpot",
 | 
			
		||||
                    "type": "github"
 | 
			
		||||
                },
 | 
			
		||||
                {
 | 
			
		||||
                    "url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
 | 
			
		||||
                    "type": "tidelift"
 | 
			
		||||
                }
 | 
			
		||||
            ],
 | 
			
		||||
            "time": "2022-01-02T09:55:41+00:00"
 | 
			
		||||
        }
 | 
			
		||||
    ],
 | 
			
		||||
    "packages-dev": [],
 | 
			
		||||
    "aliases": [],
 | 
			
		||||
    "minimum-stability": "stable",
 | 
			
		||||
    "stability-flags": [],
 | 
			
		||||
    "prefer-stable": false,
 | 
			
		||||
    "prefer-lowest": false,
 | 
			
		||||
    "platform": [],
 | 
			
		||||
    "platform-dev": [],
 | 
			
		||||
    "plugin-api-version": "2.3.0"
 | 
			
		||||
}
 | 
			
		||||
@@ -35,7 +35,7 @@
 | 
			
		||||
        var compressor = kompressor || 1;
 | 
			
		||||
  
 | 
			
		||||
        var resizer = function () {
 | 
			
		||||
          el.style.fontSize = Math.max(Math.min(el.clientWidth / (compressor*10), parseFloat(settings.maxFontSize)), parseFloat(settings.minFontSize)) + 'px';
 | 
			
		||||
          el.style.fontSize = Math.max(Math.min(el.clientWidth / (compressor*10.5), parseFloat(settings.maxFontSize)), parseFloat(settings.minFontSize)) + 'px';
 | 
			
		||||
        };
 | 
			
		||||
  
 | 
			
		||||
        // Call once to set.
 | 
			
		||||
 
 | 
			
		||||
@@ -9,6 +9,7 @@
 | 
			
		||||
        <link href="/style.css" rel="stylesheet"/>
 | 
			
		||||
        <!-- Javascript -->
 | 
			
		||||
        <script src="https://code.jquery.com/jquery-3.6.0.min.js" integrity="sha256-/xUj+3OJU5yExlq6GSYGSHk7tPXikynS7ogEvDej/m4=" crossorigin="anonymous"></script>
 | 
			
		||||
        <script src="https://code.jquery.com/color/jquery.color.plus-names-2.1.2.min.js"></script>
 | 
			
		||||
        <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js" integrity="sha384-ka7Sk0Gln4gmtz2MlQnikT1wXgYsOg+OMhuP+IlRH9sENBO0LRn5q+8nbTov4+1p" crossorigin="anonymous"></script>
 | 
			
		||||
        <script src="/fittext.js"></script>
 | 
			
		||||
        <script src="https://livejs.com/live.js"></script>
 | 
			
		||||
@@ -20,7 +21,9 @@
 | 
			
		||||
            <div class="desktopOnly col-4"></div>
 | 
			
		||||
            <div id="content" class="col-4 center">
 | 
			
		||||
                <div class="row">
 | 
			
		||||
                    <img src="/Assets/HTown.png" class="logo self-align-center mx-auto d-block" alt="Hacker Town logo in ASCII art. Rendered as image to force correct visualization."/>
 | 
			
		||||
                    <a href="https://hackers.town">
 | 
			
		||||
                        <img src="/Assets/HTown.png" class="logo self-align-center mx-auto d-block" alt="Hacker Town logo in ASCII art. Rendered as image to force correct visualization."/>
 | 
			
		||||
                    </a>
 | 
			
		||||
                </div>
 | 
			
		||||
                <div id="title" class="row center">
 | 
			
		||||
                    <span id="resizer">
 | 
			
		||||
@@ -28,9 +31,10 @@
 | 
			
		||||
                    </span>
 | 
			
		||||
                </div>
 | 
			
		||||
                <div class="row button">
 | 
			
		||||
                    <button id="bttn">Create Account</button>
 | 
			
		||||
                    <button id="bttn" class="keyButton" onclick="beginOauth()">Create Account</button>
 | 
			
		||||
                </div>
 | 
			
		||||
                <div class="row copyright">
 | 
			
		||||
                    <!-- TODO: Make this file PHP and make the canary dependent on /etc/ttyserver/canary -->
 | 
			
		||||
                    Canary
 | 
			
		||||
                    <br>
 | 
			
		||||
                    Copyright ©️ 2022 Elizabeth Anne Cray
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										73
									
								
								index.js
									
									
									
									
									
								
							
							
						
						
									
										73
									
								
								index.js
									
									
									
									
									
								
							@@ -27,6 +27,19 @@ const resizeText = ({ element, elements, minSize = 10, maxSize = 512, step = 1,
 | 
			
		||||
  })
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const saveFile = (name, type, data) => {
 | 
			
		||||
  if (data !== null && navigator.msSaveBlob)
 | 
			
		||||
      return navigator.msSaveBlob(new Blob([data], { type: type }), name);
 | 
			
		||||
  var a = $("<a style='display: none;'/>");
 | 
			
		||||
  var url = window.URL.createObjectURL(new Blob([data], {type: type}));
 | 
			
		||||
  a.attr("href", url);
 | 
			
		||||
  a.attr("download", name);
 | 
			
		||||
  $("body").append(a);
 | 
			
		||||
  a[0].click();
 | 
			
		||||
  window.URL.revokeObjectURL(url);
 | 
			
		||||
  a.remove();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const disableNonDesktopElements = () => {
 | 
			
		||||
  var disableElements = document.getElementsByClassName("desktopOnly");
 | 
			
		||||
  for(var i=0; i< disableElements.length; i++){
 | 
			
		||||
@@ -41,8 +54,66 @@ const disableNonDesktopElements = () => {
 | 
			
		||||
  content.classList.add("col-10");
 | 
			
		||||
  var te = document.getElementById("resizer");
 | 
			
		||||
  window.fitText(te);
 | 
			
		||||
  document.getElementById("bttn").style.height = "15vw";
 | 
			
		||||
 | 
			
		||||
  var buttons = document.getElementsByClassName("keyButton");
 | 
			
		||||
  for(var i=0; i<buttons.length; i++){
 | 
			
		||||
    var bttn = buttons.item(i);
 | 
			
		||||
    bttn.style.height = "15vw";
 | 
			
		||||
  }
 | 
			
		||||
  // document.getElementById("bttn").style.height = "15vw";
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const generateSSH = async (name) => {
 | 
			
		||||
  dbp("Generate Key");
 | 
			
		||||
  generateKeyPair("RSASSA-PKCS1-v1_5", 4096, "namehere")
 | 
			
		||||
    .then((keys) => {
 | 
			
		||||
      console.dir(keys);
 | 
			
		||||
      // saveFile("ssh_key.pem", "text/plain", keys[0]);
 | 
			
		||||
      // saveFile("ssh_key.pub", "text/plain", keys[1]);
 | 
			
		||||
      var KeyExport = new JSZip();
 | 
			
		||||
      KeyExport.file("HackersTownTTY-"+name, keys[0]);
 | 
			
		||||
      KeyExport.file("HackersTownTTY-"+name+".pub", keys[1]);
 | 
			
		||||
      KeyExport.generateAsync({type:"blob"})
 | 
			
		||||
        .then((content) => {
 | 
			
		||||
          saveFile("HackersTownTTY-"+name+".zip", "application/zip", content);
 | 
			
		||||
          // saveAs(content, "HackersTownTTY-"+name+".zip");
 | 
			
		||||
       });
 | 
			
		||||
    }).catch((err) => {
 | 
			
		||||
      console.log(err);
 | 
			
		||||
    });
 | 
			
		||||
  
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const uploadSSH = () => {
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const beginOauth = () => {
 | 
			
		||||
  dbp("Auth");
 | 
			
		||||
  $.ajax({
 | 
			
		||||
    url: "https://tty.hackers.town/auth?act=id"
 | 
			
		||||
  }).then((data) => {
 | 
			
		||||
    console.table(data);
 | 
			
		||||
    if(data.id){
 | 
			
		||||
      var redirect = "https://hackers.town/oauth/authorize?"+
 | 
			
		||||
        "response_type=code&client_id="+data.id+"&redirect_uri="+
 | 
			
		||||
        "https://tty.hackers.town/auth&scope=read:accounts";
 | 
			
		||||
      dbp(redirect);
 | 
			
		||||
      window.location.href = redirect;
 | 
			
		||||
    }else{
 | 
			
		||||
      // Auth Failed
 | 
			
		||||
      $("#resizer").html("AUTH FAILED");
 | 
			
		||||
      $("#resizer").css("color", "#400112");
 | 
			
		||||
      $("#resizer").css("background-color", "#79F257");
 | 
			
		||||
      $("#resizer").animate({
 | 
			
		||||
        color: "#79F257",
 | 
			
		||||
        backgroundColor: "#022601"
 | 
			
		||||
      }, 1000);
 | 
			
		||||
    }
 | 
			
		||||
  });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// On Page Load...
 | 
			
		||||
$(() => {
 | 
			
		||||
  dbp("Begin Init Content");
 | 
			
		||||
  // Device Detection
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										52
									
								
								keygen.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										52
									
								
								keygen.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,52 @@
 | 
			
		||||
/* global encodePrivateKey, encodePublicKey */
 | 
			
		||||
const extractable = true;
 | 
			
		||||
 | 
			
		||||
function wrap(text, len) {
 | 
			
		||||
  const length = len || 72;
 | 
			
		||||
  let result = "";
 | 
			
		||||
  for (let i = 0; i < text.length; i += length) {
 | 
			
		||||
    result += text.slice(i, i + length);
 | 
			
		||||
    result += "\n";
 | 
			
		||||
  }
 | 
			
		||||
  return result;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function rsaPrivateKey(key) {
 | 
			
		||||
  return `-----BEGIN RSA PRIVATE KEY-----\n${key}-----END RSA PRIVATE KEY-----`;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function arrayBufferToBase64(buffer) {
 | 
			
		||||
  let binary = "";
 | 
			
		||||
  const bytes = new Uint8Array(buffer);
 | 
			
		||||
  const len = bytes.byteLength;
 | 
			
		||||
  for (let i = 0; i < len; i += 1) {
 | 
			
		||||
    binary += String.fromCharCode(bytes[i]);
 | 
			
		||||
  }
 | 
			
		||||
  return window.btoa(binary);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function generateKeyPair(alg, size, name) {
 | 
			
		||||
  return window.crypto.subtle
 | 
			
		||||
    .generateKey(
 | 
			
		||||
      {
 | 
			
		||||
        name: "RSASSA-PKCS1-v1_5",
 | 
			
		||||
        modulusLength: 2048, // can be 1024, 2048, or 4096
 | 
			
		||||
        publicExponent: new Uint8Array([0x01, 0x00, 0x01]),
 | 
			
		||||
        hash: { name: "SHA-1" }, // can be "SHA-1", "SHA-256", "SHA-384", or "SHA-512"
 | 
			
		||||
      },
 | 
			
		||||
      extractable,
 | 
			
		||||
      ["sign", "verify"]
 | 
			
		||||
    )
 | 
			
		||||
    .then(key => {
 | 
			
		||||
      const privateKey = window.crypto.subtle
 | 
			
		||||
        .exportKey("jwk", key.privateKey)
 | 
			
		||||
        .then(encodePrivateKey)
 | 
			
		||||
        .then(wrap)
 | 
			
		||||
        .then(rsaPrivateKey);
 | 
			
		||||
 | 
			
		||||
      const publicKey = window.crypto.subtle.exportKey("jwk", key.publicKey).then(jwk => encodePublicKey(jwk, name));
 | 
			
		||||
      return Promise.all([privateKey, publicKey]);
 | 
			
		||||
    });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// module.exports = { arrayBufferToBase64, generateKeyPair };
 | 
			
		||||
							
								
								
									
										84
									
								
								pkcs1To8.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										84
									
								
								pkcs1To8.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,84 @@
 | 
			
		||||
/* eslint no-bitwise: 0 */
 | 
			
		||||
 | 
			
		||||
function wrap(text, len) {
 | 
			
		||||
    const length = len || 72;
 | 
			
		||||
    let result = "";
 | 
			
		||||
    for (let i = 0; i < text.length; i += length) {
 | 
			
		||||
      result += text.slice(i, i + length);
 | 
			
		||||
      result += "\n";
 | 
			
		||||
    }
 | 
			
		||||
    return result;
 | 
			
		||||
  }
 | 
			
		||||
  
 | 
			
		||||
  function pemPrivateKey(key) {
 | 
			
		||||
    return `-----BEGIN PRIVATE KEY-----\n${wrap(key, 64)}-----END PRIVATE KEY-----`;
 | 
			
		||||
  }
 | 
			
		||||
  
 | 
			
		||||
  function stripPemFormatting(str) {
 | 
			
		||||
    return str
 | 
			
		||||
      .replace(/^-----BEGIN (?:RSA )?(?:PRIVATE|PUBLIC) KEY-----$/m, "")
 | 
			
		||||
      .replace(/^-----END (?:RSA )?(?:PRIVATE|PUBLIC) KEY-----$/m, "")
 | 
			
		||||
      .replace(/[\n\r]/g, "");
 | 
			
		||||
  }
 | 
			
		||||
  function arrayToPem(a) {
 | 
			
		||||
    return window.btoa(a.map(c => String.fromCharCode(c)).join(""));
 | 
			
		||||
  }
 | 
			
		||||
  
 | 
			
		||||
  function stringToArray(s) {
 | 
			
		||||
    return s.split("").map(c => c.charCodeAt());
 | 
			
		||||
  }
 | 
			
		||||
  
 | 
			
		||||
  function pemToArray(pem) {
 | 
			
		||||
    return stringToArray(window.atob(pem));
 | 
			
		||||
  }
 | 
			
		||||
  
 | 
			
		||||
  const prefix = [
 | 
			
		||||
    0x30,
 | 
			
		||||
    0x82,
 | 
			
		||||
    0x04,
 | 
			
		||||
    0xbc,
 | 
			
		||||
    0x02,
 | 
			
		||||
    0x01,
 | 
			
		||||
    0x00,
 | 
			
		||||
    0x30,
 | 
			
		||||
    0x0d,
 | 
			
		||||
    0x06,
 | 
			
		||||
    0x09,
 | 
			
		||||
    0x2a,
 | 
			
		||||
    0x86,
 | 
			
		||||
    0x48,
 | 
			
		||||
    0x86,
 | 
			
		||||
    0xf7,
 | 
			
		||||
    0x0d,
 | 
			
		||||
    0x01,
 | 
			
		||||
    0x01,
 | 
			
		||||
    0x01,
 | 
			
		||||
    0x05,
 | 
			
		||||
    0x00,
 | 
			
		||||
    0x04,
 | 
			
		||||
    0x82,
 | 
			
		||||
    0x04,
 | 
			
		||||
    0xa6,
 | 
			
		||||
  ];
 | 
			
		||||
  
 | 
			
		||||
  function pkcs1To8(privateKeyPkcs1Pem) {
 | 
			
		||||
    const pem = stripPemFormatting(privateKeyPkcs1Pem);
 | 
			
		||||
    const privateKeyPkcs1Array = pemToArray(pem);
 | 
			
		||||
    const prefixPkcs8 = prefix.concat(privateKeyPkcs1Array);
 | 
			
		||||
    const privateKeyPkcs8Pem = arrayToPem(prefixPkcs8);
 | 
			
		||||
    const pkcs8Pem = pemPrivateKey(privateKeyPkcs8Pem);
 | 
			
		||||
    return pkcs8Pem;
 | 
			
		||||
  }
 | 
			
		||||
  
 | 
			
		||||
  // crypto.subtle.importKey(
 | 
			
		||||
  //   "spki",
 | 
			
		||||
  //   keyTextBuffer,
 | 
			
		||||
  //   {
 | 
			
		||||
  //     name: "RSASSA-PKCS1-v1_5",
 | 
			
		||||
  //     hash: { name: "SHA-256" },
 | 
			
		||||
  //   },
 | 
			
		||||
  //   true,
 | 
			
		||||
  //   ["verify"]
 | 
			
		||||
  // );
 | 
			
		||||
  
 | 
			
		||||
  module.exports = { pkcs1To8 };
 | 
			
		||||
							
								
								
									
										103
									
								
								publicSshToPem.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										103
									
								
								publicSshToPem.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,103 @@
 | 
			
		||||
/* eslint no-bitwise: 0 */
 | 
			
		||||
 | 
			
		||||
function wrap(text, len) {
 | 
			
		||||
    const length = len || 72;
 | 
			
		||||
    let result = "";
 | 
			
		||||
    for (let i = 0; i < text.length; i += length) {
 | 
			
		||||
      result += text.slice(i, i + length);
 | 
			
		||||
      result += "\n";
 | 
			
		||||
    }
 | 
			
		||||
    return result;
 | 
			
		||||
  }
 | 
			
		||||
  
 | 
			
		||||
  function pemPublicKey(key) {
 | 
			
		||||
    return `---- BEGIN RSA PUBLIC KEY ----\n${wrap(key, 65)}---- END RSA PUBLIC KEY ----`;
 | 
			
		||||
  }
 | 
			
		||||
  
 | 
			
		||||
  function integerToOctet(n) {
 | 
			
		||||
    const result = [];
 | 
			
		||||
    for (let i = n; i > 0; i >>= 8) {
 | 
			
		||||
      result.push(i & 0xff);
 | 
			
		||||
    }
 | 
			
		||||
    return result.reverse();
 | 
			
		||||
  }
 | 
			
		||||
  
 | 
			
		||||
  function asnEncodeLen(n) {
 | 
			
		||||
    let result = [];
 | 
			
		||||
    if (n >> 7) {
 | 
			
		||||
      result = integerToOctet(n);
 | 
			
		||||
      result.unshift(0x80 + result.length);
 | 
			
		||||
    } else {
 | 
			
		||||
      result.push(n);
 | 
			
		||||
    }
 | 
			
		||||
    return result;
 | 
			
		||||
  }
 | 
			
		||||
  
 | 
			
		||||
  function checkHighestBit(v) {
 | 
			
		||||
    if (v[0] >> 7 === 1) {
 | 
			
		||||
      v.unshift(0); // add leading zero if first bit is set
 | 
			
		||||
    }
 | 
			
		||||
    return v;
 | 
			
		||||
  }
 | 
			
		||||
  
 | 
			
		||||
  function asn1Int(int) {
 | 
			
		||||
    const v = checkHighestBit(int);
 | 
			
		||||
    const len = asnEncodeLen(v.length);
 | 
			
		||||
    return [0x02].concat(len, v); // int tag is 0x02
 | 
			
		||||
  }
 | 
			
		||||
  
 | 
			
		||||
  function asn1Seq(seq) {
 | 
			
		||||
    const len = asnEncodeLen(seq.length);
 | 
			
		||||
    return [0x30].concat(len, seq); // seq tag is 0x30
 | 
			
		||||
  }
 | 
			
		||||
  
 | 
			
		||||
  function arrayToPem(a) {
 | 
			
		||||
    return window.btoa(a.map(c => String.fromCharCode(c)).join(""));
 | 
			
		||||
  }
 | 
			
		||||
  
 | 
			
		||||
  function arrayToString(a) {
 | 
			
		||||
    return String.fromCharCode.apply(null, a);
 | 
			
		||||
  }
 | 
			
		||||
  
 | 
			
		||||
  function stringToArray(s) {
 | 
			
		||||
    return s.split("").map(c => c.charCodeAt());
 | 
			
		||||
  }
 | 
			
		||||
  
 | 
			
		||||
  function pemToArray(pem) {
 | 
			
		||||
    return stringToArray(window.atob(pem));
 | 
			
		||||
  }
 | 
			
		||||
  
 | 
			
		||||
  function arrayToLen(a) {
 | 
			
		||||
    let result = 0;
 | 
			
		||||
    for (let i = 0; i < a.length; i += 1) {
 | 
			
		||||
      result = result * 256 + a[i];
 | 
			
		||||
    }
 | 
			
		||||
    return result;
 | 
			
		||||
  }
 | 
			
		||||
  
 | 
			
		||||
  function decodePublicKey(s) {
 | 
			
		||||
    const split = s.split(" ");
 | 
			
		||||
    const prefix = split[0];
 | 
			
		||||
    if (prefix !== "ssh-rsa") {
 | 
			
		||||
      throw new Error(`Unknown prefix: ${prefix}`);
 | 
			
		||||
    }
 | 
			
		||||
    const buffer = pemToArray(split[1]);
 | 
			
		||||
    const nameLen = arrayToLen(buffer.splice(0, 4));
 | 
			
		||||
    const type = arrayToString(buffer.splice(0, nameLen));
 | 
			
		||||
    if (type !== "ssh-rsa") {
 | 
			
		||||
      throw new Error(`Unknown key type: ${type}`);
 | 
			
		||||
    }
 | 
			
		||||
    const exponentLen = arrayToLen(buffer.splice(0, 4));
 | 
			
		||||
    const exponent = buffer.splice(0, exponentLen);
 | 
			
		||||
    const keyLen = arrayToLen(buffer.splice(0, 4));
 | 
			
		||||
    const key = buffer.splice(0, keyLen);
 | 
			
		||||
    return { type, exponent, key, name: split[2] };
 | 
			
		||||
  }
 | 
			
		||||
  
 | 
			
		||||
  function publicSshToPem(publicKey) {
 | 
			
		||||
    const { key, exponent } = decodePublicKey(publicKey);
 | 
			
		||||
    const seq = [key, exponent].map(asn1Int).reduce((acc, a) => acc.concat(a));
 | 
			
		||||
    return pemPublicKey(arrayToPem(asn1Seq(seq)));
 | 
			
		||||
  }
 | 
			
		||||
  
 | 
			
		||||
  module.exports = { publicSshToPem };
 | 
			
		||||
							
								
								
									
										56
									
								
								send.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										56
									
								
								send.php
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,56 @@
 | 
			
		||||
<?php
 | 
			
		||||
exit();
 | 
			
		||||
$z=1/0;
 | 
			
		||||
use Lrf141\OAuth2\Client\Provider\Mastodon;
 | 
			
		||||
$config = json_decode(file_get_contents("config.json", true));
 | 
			
		||||
 | 
			
		||||
session_start();
 | 
			
		||||
 | 
			
		||||
$provider = new Mastodon([
 | 
			
		||||
    'clientId' => $config.oauth.key,
 | 
			
		||||
    'clientSecret' => $config.oauth.secret,
 | 
			
		||||
    'redirectUri' => 'https://tty.hackers.town/auth',
 | 
			
		||||
    'instance' => 'https://hackers.town',
 | 
			
		||||
    'scope' => 'read:accounts',
 | 
			
		||||
]);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
if (!isset($_GET['code'])) {
 | 
			
		||||
 | 
			
		||||
    $authUrl = $provider->getAuthorizationUrl();
 | 
			
		||||
 | 
			
		||||
    $_SESSION['oauth2state'] = $provider->getState();
 | 
			
		||||
    header('Location: '.$authUrl);
 | 
			
		||||
    exit;
 | 
			
		||||
 | 
			
		||||
// Check given state against previously stored one to mitigate CSRF attack
 | 
			
		||||
} elseif (empty($_GET['state']) || ($_GET['state'] !== $_SESSION['oauth2state'])) {
 | 
			
		||||
 | 
			
		||||
    unset($_SESSION['oauth2state']);
 | 
			
		||||
    exit('Invalid state');
 | 
			
		||||
 | 
			
		||||
} else {
 | 
			
		||||
 | 
			
		||||
    // Try to get an access token (using the authorization code grant)
 | 
			
		||||
    $token = $provider->getAccessToken('authorization_code', [
 | 
			
		||||
        'code' => $_GET['code']
 | 
			
		||||
    ]);
 | 
			
		||||
    
 | 
			
		||||
    // Optional: Now you have a token you can look up a users profile data
 | 
			
		||||
    try {
 | 
			
		||||
    
 | 
			
		||||
        $user = $provider->getResourceOwner($token);
 | 
			
		||||
       
 | 
			
		||||
        echo $user->getName();
 | 
			
		||||
        
 | 
			
		||||
    } catch(Exception $e) {
 | 
			
		||||
       
 | 
			
		||||
       
 | 
			
		||||
        exit('Oh dear...');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    echo $token->getToken();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
?>
 | 
			
		||||
							
								
								
									
										121
									
								
								ssh-util.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										121
									
								
								ssh-util.js
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,121 @@
 | 
			
		||||
/* eslint no-bitwise: 0 */
 | 
			
		||||
/* global base64urlDecode */
 | 
			
		||||
 | 
			
		||||
function arrayToString(a) {
 | 
			
		||||
    return String.fromCharCode.apply(null, a);
 | 
			
		||||
  }
 | 
			
		||||
  
 | 
			
		||||
  function stringToArray(s) {
 | 
			
		||||
    return s.split("").map(c => c.charCodeAt());
 | 
			
		||||
  }
 | 
			
		||||
  
 | 
			
		||||
  function base64urlToArray(s) {
 | 
			
		||||
    return stringToArray(base64urlDecode(s));
 | 
			
		||||
  }
 | 
			
		||||
  
 | 
			
		||||
  function pemToArray(pem) {
 | 
			
		||||
    return stringToArray(window.atob(pem));
 | 
			
		||||
  }
 | 
			
		||||
  
 | 
			
		||||
  function arrayToPem(a) {
 | 
			
		||||
    return window.btoa(a.map(c => String.fromCharCode(c)).join(""));
 | 
			
		||||
  }
 | 
			
		||||
  
 | 
			
		||||
  function arrayToLen(a) {
 | 
			
		||||
    let result = 0;
 | 
			
		||||
    for (let i = 0; i < a.length; i += 1) {
 | 
			
		||||
      result = result * 256 + a[i];
 | 
			
		||||
    }
 | 
			
		||||
    return result;
 | 
			
		||||
  }
 | 
			
		||||
  
 | 
			
		||||
  function integerToOctet(n) {
 | 
			
		||||
    const result = [];
 | 
			
		||||
    for (let i = n; i > 0; i >>= 8) {
 | 
			
		||||
      result.push(i & 0xff);
 | 
			
		||||
    }
 | 
			
		||||
    return result.reverse();
 | 
			
		||||
  }
 | 
			
		||||
  
 | 
			
		||||
  function lenToArray(n) {
 | 
			
		||||
    const oct = integerToOctet(n);
 | 
			
		||||
    let i;
 | 
			
		||||
    for (i = oct.length; i < 4; i += 1) {
 | 
			
		||||
      oct.unshift(0);
 | 
			
		||||
    }
 | 
			
		||||
    return oct;
 | 
			
		||||
  }
 | 
			
		||||
  
 | 
			
		||||
  function decodePublicKey(s) {
 | 
			
		||||
    const split = s.split(" ");
 | 
			
		||||
    const prefix = split[0];
 | 
			
		||||
    if (prefix !== "ssh-rsa") {
 | 
			
		||||
      throw new Error(`Unknown prefix: ${prefix}`);
 | 
			
		||||
    }
 | 
			
		||||
    const buffer = pemToArray(split[1]);
 | 
			
		||||
    const nameLen = arrayToLen(buffer.splice(0, 4));
 | 
			
		||||
    const type = arrayToString(buffer.splice(0, nameLen));
 | 
			
		||||
    if (type !== "ssh-rsa") {
 | 
			
		||||
      throw new Error(`Unknown key type: ${type}`);
 | 
			
		||||
    }
 | 
			
		||||
    const exponentLen = arrayToLen(buffer.splice(0, 4));
 | 
			
		||||
    const exponent = buffer.splice(0, exponentLen);
 | 
			
		||||
    const keyLen = arrayToLen(buffer.splice(0, 4));
 | 
			
		||||
    const key = buffer.splice(0, keyLen);
 | 
			
		||||
    return { type, exponent, key, name: split[2] };
 | 
			
		||||
  }
 | 
			
		||||
  
 | 
			
		||||
  function checkHighestBit(v) {
 | 
			
		||||
    if (v[0] >> 7 === 1) {
 | 
			
		||||
      // add leading zero if first bit is set
 | 
			
		||||
      v.unshift(0);
 | 
			
		||||
    }
 | 
			
		||||
    return v;
 | 
			
		||||
  }
 | 
			
		||||
  
 | 
			
		||||
  function jwkToInternal(jwk) {
 | 
			
		||||
    return {
 | 
			
		||||
      type: "ssh-rsa",
 | 
			
		||||
      exponent: checkHighestBit(stringToArray(base64urlDecode(jwk.e))),
 | 
			
		||||
      name: "name",
 | 
			
		||||
      key: checkHighestBit(stringToArray(base64urlDecode(jwk.n))),
 | 
			
		||||
    };
 | 
			
		||||
  }
 | 
			
		||||
  
 | 
			
		||||
  function encodePublicKey(jwk, name) {
 | 
			
		||||
    const k = jwkToInternal(jwk);
 | 
			
		||||
    k.name = name;
 | 
			
		||||
    const keyLenA = lenToArray(k.key.length);
 | 
			
		||||
    const exponentLenA = lenToArray(k.exponent.length);
 | 
			
		||||
    const typeLenA = lenToArray(k.type.length);
 | 
			
		||||
    const array = [].concat(typeLenA, stringToArray(k.type), exponentLenA, k.exponent, keyLenA, k.key);
 | 
			
		||||
    const encoding = arrayToPem(array);
 | 
			
		||||
    return `${k.type} ${encoding} ${k.name}`;
 | 
			
		||||
  }
 | 
			
		||||
  
 | 
			
		||||
  function asnEncodeLen(n) {
 | 
			
		||||
    let result = [];
 | 
			
		||||
    if (n >> 7) {
 | 
			
		||||
      result = integerToOctet(n);
 | 
			
		||||
      result.unshift(0x80 + result.length);
 | 
			
		||||
    } else {
 | 
			
		||||
      result.push(n);
 | 
			
		||||
    }
 | 
			
		||||
    return result;
 | 
			
		||||
  }
 | 
			
		||||
  
 | 
			
		||||
  function encodePrivateKey(jwk) {
 | 
			
		||||
    const order = ["n", "e", "d", "p", "q", "dp", "dq", "qi"];
 | 
			
		||||
    const list = order.map(prop => {
 | 
			
		||||
      const v = checkHighestBit(stringToArray(base64urlDecode(jwk[prop])));
 | 
			
		||||
      const len = asnEncodeLen(v.length);
 | 
			
		||||
      return [0x02].concat(len, v); // int tag is 0x02
 | 
			
		||||
    });
 | 
			
		||||
    let seq = [0x02, 0x01, 0x00]; // extra seq for SSH
 | 
			
		||||
    seq = seq.concat(...list);
 | 
			
		||||
    const len = asnEncodeLen(seq.length);
 | 
			
		||||
    const a = [0x30].concat(len, seq); // seq is 0x30
 | 
			
		||||
    return arrayToPem(a);
 | 
			
		||||
  }
 | 
			
		||||
  
 | 
			
		||||
  module.exports = { base64urlToArray, decodePublicKey, encodePublicKey, encodePrivateKey };
 | 
			
		||||
							
								
								
									
										12
									
								
								style.css
									
									
									
									
									
								
							
							
						
						
									
										12
									
								
								style.css
									
									
									
									
									
								
							@@ -23,7 +23,7 @@ body {
 | 
			
		||||
    height: 80%;
 | 
			
		||||
    margin: 2vw;
 | 
			
		||||
    padding: 2vw;
 | 
			
		||||
    color: white;
 | 
			
		||||
    color: #79F257;
 | 
			
		||||
    border: 2px solid #377326;
 | 
			
		||||
    border-radius: 1em;
 | 
			
		||||
}
 | 
			
		||||
@@ -43,6 +43,12 @@ span {
 | 
			
		||||
    display: block;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.message {
 | 
			
		||||
    width: 100%;
 | 
			
		||||
    text-align: center;
 | 
			
		||||
    display: block;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.button {
 | 
			
		||||
    margin: 8px;
 | 
			
		||||
}
 | 
			
		||||
@@ -59,4 +65,8 @@ span {
 | 
			
		||||
    text-align: center;
 | 
			
		||||
    display: block;
 | 
			
		||||
    color: #377326;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.keyButton {
 | 
			
		||||
    margin: 1px;
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user