diff options
-rw-r--r-- | .gitignore | 3 | ||||
-rw-r--r-- | .idea/.gitignore | 8 | ||||
-rw-r--r-- | .idea/BitsServer.iml | 8 | ||||
-rw-r--r-- | .idea/deployment.xml | 15 | ||||
-rw-r--r-- | .idea/discord.xml | 7 | ||||
-rw-r--r-- | .idea/modules.xml | 8 | ||||
-rw-r--r-- | .idea/php.xml | 4 | ||||
-rw-r--r-- | .idea/vcs.xml | 6 | ||||
-rw-r--r-- | Application/TransactionsList/index.php | 52 | ||||
-rw-r--r-- | Authentication/Callback/index.php | 63 | ||||
-rw-r--r-- | Authentication/Disallowed/index.php | 30 | ||||
-rw-r--r-- | Authentication/Start/index.php | 4 | ||||
-rw-r--r-- | Authentication/Success/index.php | 30 | ||||
-rw-r--r-- | Authentication/Test/index.php | 4 | ||||
-rw-r--r-- | Authentication/Username/index.php | 11 | ||||
-rw-r--r-- | Authentication/index.php | 1 | ||||
-rw-r--r-- | Private/AllowedUsers.json | 4 | ||||
-rw-r--r-- | Private/SessionChecker.php | 25 | ||||
-rw-r--r-- | Private/SessionManager.php | 33 | ||||
-rw-r--r-- | index.php | 2 |
20 files changed, 318 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..8849011 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +Private/Application.json +Private/SessionTokens +Data
\ No newline at end of file diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..13566b8 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,8 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Editor-based HTTP Client requests +/httpRequests/ +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml diff --git a/.idea/BitsServer.iml b/.idea/BitsServer.iml new file mode 100644 index 0000000..c956989 --- /dev/null +++ b/.idea/BitsServer.iml @@ -0,0 +1,8 @@ +<?xml version="1.0" encoding="UTF-8"?> +<module type="WEB_MODULE" version="4"> + <component name="NewModuleRootManager"> + <content url="file://$MODULE_DIR$" /> + <orderEntry type="inheritedJdk" /> + <orderEntry type="sourceFolder" forTests="false" /> + </component> +</module>
\ No newline at end of file diff --git a/.idea/deployment.xml b/.idea/deployment.xml new file mode 100644 index 0000000..8cdf222 --- /dev/null +++ b/.idea/deployment.xml @@ -0,0 +1,15 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project version="4"> + <component name="PublishConfigData" autoUpload="Always" serverName="Minteck.org" filePermissions="511" folderPermissions="511" remoteFilesAllowedToDisappearOnAutoupload="false"> + <serverData> + <paths name="Minteck.org"> + <serverdata> + <mappings> + <mapping deploy="/mnt/bits" local="$PROJECT_DIR$" web="/" /> + </mappings> + </serverdata> + </paths> + </serverData> + <option name="myAutoUpload" value="ALWAYS" /> + </component> +</project>
\ No newline at end of file diff --git a/.idea/discord.xml b/.idea/discord.xml new file mode 100644 index 0000000..d8e9561 --- /dev/null +++ b/.idea/discord.xml @@ -0,0 +1,7 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project version="4"> + <component name="DiscordProjectSettings"> + <option name="show" value="PROJECT_FILES" /> + <option name="description" value="" /> + </component> +</project>
\ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..8762b61 --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project version="4"> + <component name="ProjectModuleManager"> + <modules> + <module fileurl="file://$PROJECT_DIR$/.idea/BitsServer.iml" filepath="$PROJECT_DIR$/.idea/BitsServer.iml" /> + </modules> + </component> +</project>
\ No newline at end of file diff --git a/.idea/php.xml b/.idea/php.xml new file mode 100644 index 0000000..7e5d55a --- /dev/null +++ b/.idea/php.xml @@ -0,0 +1,4 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project version="4"> + <component name="PhpProjectSharedConfiguration" php_language_level="8.1" /> +</project>
\ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..94a25f7 --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project version="4"> + <component name="VcsDirectoryMappings"> + <mapping directory="$PROJECT_DIR$" vcs="Git" /> + </component> +</project>
\ No newline at end of file diff --git a/Application/TransactionsList/index.php b/Application/TransactionsList/index.php new file mode 100644 index 0000000..185e94b --- /dev/null +++ b/Application/TransactionsList/index.php @@ -0,0 +1,52 @@ +<?php + +function timeAgo($time): string { + if (!is_numeric($time)) { + $time = strtotime($time); + } + + $periods = ["second", "minute", "hour", "day", "week", "month", "year", "age"]; + $lengths = array("60", "60", "24", "7", "4.35", "12", "100"); + + $now = time(); + + $difference = $now - $time; + if ($difference <= 10 && $difference >= 0) { + return $tense = "now"; + } elseif ($difference > 0) { + $tense = "ago"; + } else { + $tense = "later"; + } + + for ($j = 0; $difference >= $lengths[$j] && $j < count($lengths)-1; $j++) { + $difference /= $lengths[$j]; + } + + $difference = round($difference); + + $period = $periods[$j] . ($difference >1 ? "s" :''); + return "{$difference} {$period} {$tense} "; +} + +require_once $_SERVER['DOCUMENT_ROOT'] . "/Private/SessionManager.php"; +header("Content-Type: application/json"); + +$users = json_decode(file_get_contents($_SERVER['DOCUMENT_ROOT'] . "/Private/Data/Users.json"), true); +$list = json_decode(file_get_contents($_SERVER['DOCUMENT_ROOT'] . "/Private/Data/Transactions.json"), true); +$plist = []; + +foreach ($list as $item) { + $item["author"] = [ + "id" => $item["author"], + "name" => $users[$item["author"]] ?? $item["author"], + "avatar" => "https://account.minteck.org/hub/api/rest/avatar/" . $item["author"] . "?dpr=2&size=48" + ]; + $item["date"] = [ + "absolute" => $item["date"], + "relative" => trim(timeAgo($item["date"])) + ]; + $plist[] = $item; +} + +die(json_encode($plist));
\ No newline at end of file diff --git a/Authentication/Callback/index.php b/Authentication/Callback/index.php new file mode 100644 index 0000000..3f50e1c --- /dev/null +++ b/Authentication/Callback/index.php @@ -0,0 +1,63 @@ +<?php + +header("Content-Type: text/plain"); +// TODO: handle errors + +if (!isset($_GET['code'])) { + die(); +} + +$appdata = json_decode(file_get_contents($_SERVER['DOCUMENT_ROOT'] . "/Private/Application.json"), true); + +$crl = curl_init('https://account.minteck.org/hub/api/rest/oauth2/token'); +curl_setopt($crl, CURLOPT_RETURNTRANSFER, true); +curl_setopt($crl, CURLINFO_HEADER_OUT, true); +curl_setopt($crl, CURLOPT_POST, true); +curl_setopt($crl, CURLOPT_HTTPHEADER, [ + "Authorization: Basic " . base64_encode($appdata["id"] . ":" . $appdata["secret"]), + "Content-Type: application/x-www-form-urlencoded", + "Accept: application/json" +]); +curl_setopt($crl, CURLOPT_POSTFIELDS, "grant_type=authorization_code&redirect_uri=" . urlencode("http" . ($_SERVER['HTTPS'] ? "s" : "") . "://" . $_SERVER['HTTP_HOST'] . "/Authentication/Callback") . "&code=" . $_GET['code']); + +$result = curl_exec($crl); +$result = json_decode($result, true); + +curl_close($crl); + +if (isset($result["access_token"])) { + $crl = curl_init('https://account.minteck.org/hub/api/rest/users/me'); + curl_setopt($crl, CURLOPT_RETURNTRANSFER, true); + curl_setopt($crl, CURLINFO_HEADER_OUT, true); + curl_setopt($crl, CURLOPT_HTTPHEADER, [ + "Authorization: Bearer " . $result["access_token"], + "Accept: application/json" + ]); + + $result = curl_exec($crl); + $result = json_decode($result, true); + + if (!file_exists($_SERVER['DOCUMENT_ROOT'] . "/Private/SessionTokens")) mkdir($_SERVER['DOCUMENT_ROOT'] . "/Private/SessionTokens"); + + if (in_array($result["id"], json_decode(file_get_contents($_SERVER['DOCUMENT_ROOT'] . "/Private/AllowedUsers.json"), true))) { + $token = bin2hex(random_bytes(32)); + file_put_contents($_SERVER['DOCUMENT_ROOT'] . "/Private/SessionTokens/" . $token, json_encode($result)); + session_start(); + session_set_cookie_params([ + 'lifetime' => 0, + 'path' => '/', + 'domain' => "", + 'secure' => true, + 'httponly' => true, + 'samesite' => 'None' + ]); + setcookie("BITS_SESSION_TOKEN", $token, 0, "/", "", true, true); + header("Set-Cookie: BITS_SESSION_TOKEN=" . $token . "; SameSite=None; Path=/; Secure; HttpOnly"); + + header("Location: /Authentication/Success"); + } else { + header("Location: /Authentication/Disallowed"); + } + + die(); +}
\ No newline at end of file diff --git a/Authentication/Disallowed/index.php b/Authentication/Disallowed/index.php new file mode 100644 index 0000000..bae4da7 --- /dev/null +++ b/Authentication/Disallowed/index.php @@ -0,0 +1,30 @@ +<!doctype html> +<html lang="en"> +<head> + <meta charset="UTF-8"> + <meta name="viewport" + content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0"> + <meta http-equiv="X-UA-Compatible" content="ie=edge"> + <title>Authentication</title> + <style> + body { + background: #222; + color: white; + font-family: sans-serif; + text-align: center; + display: flex; + align-items: center; + justify-content: center; + position: fixed; + inset: 0; + } + </style> +</head> +<body> +<div> + <h2>Not allowed</h2> + <p>You are not allowed to use this application. Please close it now.</p> +</div> +</body> +</html> + diff --git a/Authentication/Start/index.php b/Authentication/Start/index.php new file mode 100644 index 0000000..006752e --- /dev/null +++ b/Authentication/Start/index.php @@ -0,0 +1,4 @@ +<?php + +header("Location: https://account.minteck.org/hub/api/rest/oauth2/auth?client_id=" . json_decode(file_get_contents($_SERVER['DOCUMENT_ROOT'] . "/Private/Application.json"), true)["id"] . "&response_type=code&redirect_uri=http" . ($_SERVER['HTTPS'] ? "s" : "") . "://" . $_SERVER['HTTP_HOST'] . "/Authentication/Callback&scope=Hub&request_credentials=default&access_type=offline"); +die(); diff --git a/Authentication/Success/index.php b/Authentication/Success/index.php new file mode 100644 index 0000000..882eecc --- /dev/null +++ b/Authentication/Success/index.php @@ -0,0 +1,30 @@ +<?php require_once $_SERVER['DOCUMENT_ROOT'] . "/Private/SessionManager.php"; ?> +<!doctype html> +<html lang="en"> +<head> + <meta charset="UTF-8"> + <meta name="viewport" + content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0"> + <meta http-equiv="X-UA-Compatible" content="ie=edge"> + <title>Authentication</title> + <style> + body { + background: #222; + color: white; + font-family: sans-serif; + text-align: center; + display: flex; + align-items: center; + justify-content: center; + position: fixed; + inset: 0; + } + </style> +</head> +<body> + <div> + <h2>Success</h2> + <p>Authentication succeeded, you will be redirected to the requested application in a few seconds.</p> + </div> +</body> +</html> diff --git a/Authentication/Test/index.php b/Authentication/Test/index.php new file mode 100644 index 0000000..7c0d1fb --- /dev/null +++ b/Authentication/Test/index.php @@ -0,0 +1,4 @@ +<?php + +require_once $_SERVER['DOCUMENT_ROOT'] . "/Private/SessionChecker.php"; +header("Content-Type: application/json"); die("{\n \"status\": 0\n}");
\ No newline at end of file diff --git a/Authentication/Username/index.php b/Authentication/Username/index.php new file mode 100644 index 0000000..63b4aed --- /dev/null +++ b/Authentication/Username/index.php @@ -0,0 +1,11 @@ +<?php + +require_once $_SERVER['DOCUMENT_ROOT'] . "/Private/SessionManager.php"; global $_PROFILE; +header("Content-Type: application/json"); + +$a = [ + "name" => $_PROFILE["name"], + "id" => $_PROFILE['id'] +]; + +die(json_encode($a));
\ No newline at end of file diff --git a/Authentication/index.php b/Authentication/index.php new file mode 100644 index 0000000..9fd9e4a --- /dev/null +++ b/Authentication/index.php @@ -0,0 +1 @@ +<?php header("Location: /Authentication/Start") and die();
\ No newline at end of file diff --git a/Private/AllowedUsers.json b/Private/AllowedUsers.json new file mode 100644 index 0000000..b94bf28 --- /dev/null +++ b/Private/AllowedUsers.json @@ -0,0 +1,4 @@ +[ + "e2d08242-9107-40fc-834e-28e6000ef1cd", + "0204b8a8-4468-4f59-859d-a82e731b1378" +]
\ No newline at end of file diff --git a/Private/SessionChecker.php b/Private/SessionChecker.php new file mode 100644 index 0000000..194c398 --- /dev/null +++ b/Private/SessionChecker.php @@ -0,0 +1,25 @@ +<?php + +global $SessionManagerAllowDisallowed; + +if (isset($_COOKIE['BITS_SESSION_TOKEN'])) { + if (str_contains($_COOKIE['BITS_SESSION_TOKEN'], ".") || str_contains($_COOKIE['BITS_SESSION_TOKEN'], "/")) { + header("Content-Type: application/json"); die("{\n \"status\": 1\n}"); + } + + if (file_exists($_SERVER['DOCUMENT_ROOT'] . "/Private/SessionTokens/" . str_replace(".", "", str_replace("/", "", $_COOKIE['BITS_SESSION_TOKEN'])))) { + $_PROFILE = json_decode(file_get_contents($_SERVER['DOCUMENT_ROOT'] . "/Private/SessionTokens/" . str_replace(".", "", str_replace("/", "", $_COOKIE['BITS_SESSION_TOKEN']))), true); + + if (!in_array($_PROFILE["id"], json_decode(file_get_contents($_SERVER['DOCUMENT_ROOT'] . "/Private/AllowedUsers.json"), true)) && !$SessionManagerAllowDisallowed) { + header("Content-Type: application/json"); die("{\n \"status\": 1\n}"); + } else { + $users = json_decode(file_get_contents($_SERVER['DOCUMENT_ROOT'] . "/Private/Data/Users.json"), true); + $users[$_PROFILE["id"]] = $_PROFILE["name"]; + file_put_contents($_SERVER['DOCUMENT_ROOT'] . "/Private/Data/Users.json", json_encode($users)); + } + } else { + header("Content-Type: application/json"); die("{\n \"status\": 1\n}"); + } +} else { + header("Content-Type: application/json"); die("{\n \"status\": 1\n}"); +}
\ No newline at end of file diff --git a/Private/SessionManager.php b/Private/SessionManager.php new file mode 100644 index 0000000..bb6c721 --- /dev/null +++ b/Private/SessionManager.php @@ -0,0 +1,33 @@ +<?php + +if (!file_exists($_SERVER['DOCUMENT_ROOT'] . "/Data")) mkdir($_SERVER['DOCUMENT_ROOT'] . "/Data"); +if (!file_exists($_SERVER['DOCUMENT_ROOT'] . "/Data/Transactions.json")) file_put_contents($_SERVER['DOCUMENT_ROOT'] . "/Data/Transactions.json", "[]"); +if (!file_exists($_SERVER['DOCUMENT_ROOT'] . "/Data/Users.json")) file_put_contents($_SERVER['DOCUMENT_ROOT'] . "/Data/Users.json", "{}"); + +global $SessionManagerAllowDisallowed; + +if (isset($_COOKIE['BITS_SESSION_TOKEN'])) { + if (str_contains($_COOKIE['BITS_SESSION_TOKEN'], ".") || str_contains($_COOKIE['BITS_SESSION_TOKEN'], "/")) { + header("Location: /Authentication/Start"); + die(); + } + + if (file_exists($_SERVER['DOCUMENT_ROOT'] . "/Private/SessionTokens/" . str_replace(".", "", str_replace("/", "", $_COOKIE['BITS_SESSION_TOKEN'])))) { + $_PROFILE = json_decode(file_get_contents($_SERVER['DOCUMENT_ROOT'] . "/Private/SessionTokens/" . str_replace(".", "", str_replace("/", "", $_COOKIE['BITS_SESSION_TOKEN']))), true); + + if (!in_array($_PROFILE["id"], json_decode(file_get_contents($_SERVER['DOCUMENT_ROOT'] . "/Private/AllowedUsers.json"), true)) && !$SessionManagerAllowDisallowed) { + header("Location: /Authentication/Disallowed"); + die(); + } else { + $users = json_decode(file_get_contents($_SERVER['DOCUMENT_ROOT'] . "/Private/Data/Users.json"), true); + $users[$_PROFILE["id"]] = $_PROFILE["name"]; + file_put_contents($_SERVER['DOCUMENT_ROOT'] . "/Private/Data/Users.json", json_encode($users)); + } + } else { + header("Location: /Authentication/Start"); + die(); + } +} else { + header("Location: /Authentication/Start"); + die(); +}
\ No newline at end of file diff --git a/index.php b/index.php new file mode 100644 index 0000000..0ef5364 --- /dev/null +++ b/index.php @@ -0,0 +1,2 @@ +<?php +header("Location: https://git.equestria.dev/equestria.dev/bits-server");
\ No newline at end of file |