OAuth & SSH Keygen
This commit is contained in:
parent
155afadba9
commit
60f182b99d
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
vendor/
|
@ -1,3 +1,5 @@
|
|||||||
# Hackers Town Tilde User Generator
|
# Hackers Town Tilde User Generator
|
||||||
|
|
||||||
use Mastodon oauth to generate system users
|
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 compressor = kompressor || 1;
|
||||||
|
|
||||||
var resizer = function () {
|
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.
|
// Call once to set.
|
||||||
|
@ -9,6 +9,7 @@
|
|||||||
<link href="/style.css" rel="stylesheet"/>
|
<link href="/style.css" rel="stylesheet"/>
|
||||||
<!-- Javascript -->
|
<!-- 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/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/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="/fittext.js"></script>
|
||||||
<script src="https://livejs.com/live.js"></script>
|
<script src="https://livejs.com/live.js"></script>
|
||||||
@ -20,7 +21,9 @@
|
|||||||
<div class="desktopOnly col-4"></div>
|
<div class="desktopOnly col-4"></div>
|
||||||
<div id="content" class="col-4 center">
|
<div id="content" class="col-4 center">
|
||||||
<div class="row">
|
<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>
|
||||||
<div id="title" class="row center">
|
<div id="title" class="row center">
|
||||||
<span id="resizer">
|
<span id="resizer">
|
||||||
@ -28,9 +31,10 @@
|
|||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="row button">
|
<div class="row button">
|
||||||
<button id="bttn">Create Account</button>
|
<button id="bttn" class="keyButton" onclick="beginOauth()">Create Account</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="row copyright">
|
<div class="row copyright">
|
||||||
|
<!-- TODO: Make this file PHP and make the canary dependent on /etc/ttyserver/canary -->
|
||||||
Canary
|
Canary
|
||||||
<br>
|
<br>
|
||||||
Copyright ©️ 2022 Elizabeth Anne Cray
|
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 = () => {
|
const disableNonDesktopElements = () => {
|
||||||
var disableElements = document.getElementsByClassName("desktopOnly");
|
var disableElements = document.getElementsByClassName("desktopOnly");
|
||||||
for(var i=0; i< disableElements.length; i++){
|
for(var i=0; i< disableElements.length; i++){
|
||||||
@ -41,8 +54,66 @@ const disableNonDesktopElements = () => {
|
|||||||
content.classList.add("col-10");
|
content.classList.add("col-10");
|
||||||
var te = document.getElementById("resizer");
|
var te = document.getElementById("resizer");
|
||||||
window.fitText(te);
|
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");
|
dbp("Begin Init Content");
|
||||||
// Device Detection
|
// 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%;
|
height: 80%;
|
||||||
margin: 2vw;
|
margin: 2vw;
|
||||||
padding: 2vw;
|
padding: 2vw;
|
||||||
color: white;
|
color: #79F257;
|
||||||
border: 2px solid #377326;
|
border: 2px solid #377326;
|
||||||
border-radius: 1em;
|
border-radius: 1em;
|
||||||
}
|
}
|
||||||
@ -43,6 +43,12 @@ span {
|
|||||||
display: block;
|
display: block;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.message {
|
||||||
|
width: 100%;
|
||||||
|
text-align: center;
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
.button {
|
.button {
|
||||||
margin: 8px;
|
margin: 8px;
|
||||||
}
|
}
|
||||||
@ -60,3 +66,7 @@ span {
|
|||||||
display: block;
|
display: block;
|
||||||
color: #377326;
|
color: #377326;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.keyButton {
|
||||||
|
margin: 1px;
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user