diff --git a/.github/workflows/phpmd.yml b/.github/workflows/phpmd.yml deleted file mode 100644 index 2b57989c..00000000 --- a/.github/workflows/phpmd.yml +++ /dev/null @@ -1,57 +0,0 @@ -# This workflow uses actions that are not certified by GitHub. -# They are provided by a third-party and are governed by -# separate terms of service, privacy policy, and support -# documentation. -# PHPMD is a spin-off project of PHP Depend and -# aims to be a PHP equivalent of the well known Java tool PMD. -# What PHPMD does is: It takes a given PHP source code base -# and look for several potential problems within that source. -# These problems can be things like: -# Possible bugs -# Suboptimal code -# Overcomplicated expressions -# Unused parameters, methods, properties -# More details at https://phpmd.org/ - -name: PHPMD - -on: - push: - branches: [ "main" ] - pull_request: - # The branches below must be a subset of the branches above - branches: [ "main" ] - schedule: - - cron: '33 18 * * 3' - -permissions: - contents: read - -jobs: - PHPMD: - name: Run PHPMD scanning - runs-on: ubuntu-latest - permissions: - contents: read # for checkout to fetch code - security-events: write # for github/codeql-action/upload-sarif to upload SARIF results - actions: read # only required for a private repository by github/codeql-action/upload-sarif to get the Action run status - - steps: - - name: Checkout code - uses: actions/checkout@v3 - - - name: Setup PHP - uses: shivammathur/setup-php@aa1fe473f9c687b6fb896056d771232c0bc41161 - with: - coverage: none - tools: phpmd - - - name: Run PHPMD - run: phpmd . sarif codesize --reportfile phpmd-results.sarif - continue-on-error: true - - - name: Upload analysis results to GitHub - uses: github/codeql-action/upload-sarif@v2 - with: - sarif_file: phpmd-results.sarif - wait-for-processing: true diff --git a/.github/workflows/pr_notification.yml b/.github/workflows/pr_notification.yml deleted file mode 100644 index de44c8b8..00000000 --- a/.github/workflows/pr_notification.yml +++ /dev/null @@ -1,12 +0,0 @@ -name: Pull Request Notification - -on: - pull_request_target: - types: - - opened - -jobs: - notify: - uses: KeyAuth/.github/.github/workflows/pr_notification_global.yml@main - secrets: - DISCORD_PR: ${{ secrets.DISCORD_PR }} diff --git a/.gitignore b/.gitignore deleted file mode 100644 index ea9cf22f..00000000 --- a/.gitignore +++ /dev/null @@ -1,45 +0,0 @@ -# Nelson Cybersecurity LLC -# keyauth.cc - -# private -api/admin/ -api/discord/ -api/upgrade/ -api/status/ -api/dashboard/ -app/pages/admin-panel.php -app/pages/upgrade.php -app/pages/support.php -changeEmail/ -changeUsername/ -deleteAccount/ -forgot/ -owner/ -paddle/ -purge-redis/ -reset/ -resetUser/ -whoami/ -vendor/ -login/accShare/ -login/emailVerify/ -sitemap.xml -includes/credentials.php -includes/redis.php -app/pages/application-functions.php -app/pages/application-prompts.php -app/pages/bug-bounty.php -app/pages/forms.php -app/pages/staff-panel.php - -# purchase KeyAuth enterprise for these files https://shop.keyauth.cc/product/6361c20e415e9 -api/reseller/ -api/seller/ -panel/ -app/pages/manage-accs.php -app/pages/reseller-balance.php -app/pages/reseller-licenses.php -app/pages/reseller-users.php -app/pages/seller-settings.php -app/pages/seller-logs.php -app/pages/webloader.php diff --git a/LICENSE b/LICENSE deleted file mode 100644 index 92503a72..00000000 --- a/LICENSE +++ /dev/null @@ -1,93 +0,0 @@ -Elastic License 2.0 - -URL: https://www.elastic.co/licensing/elastic-license - -## Acceptance - -By using the software, you agree to all of the terms and conditions below. - -## Copyright License - -The licensor grants you a non-exclusive, royalty-free, worldwide, -non-sublicensable, non-transferable license to use, copy, distribute, make -available, and prepare derivative works of the software, in each case subject to -the limitations and conditions below. - -## Limitations - -You may not provide the software to third parties as a hosted or managed -service, where the service provides users with access to any substantial set of -the features or functionality of the software. - -You may not move, change, disable, or circumvent the license key functionality -in the software, and you may not remove or obscure any functionality in the -software that is protected by the license key. - -You may not alter, remove, or obscure any licensing, copyright, or other notices -of the licensor in the software. Any use of the licensor’s trademarks is subject -to applicable law. - -## Patents - -The licensor grants you a license, under any patent claims the licensor can -license, or becomes able to license, to make, have made, use, sell, offer for -sale, import and have imported the software, in each case subject to the -limitations and conditions in this license. This license does not cover any -patent claims that you cause to be infringed by modifications or additions to -the software. If you or your company make any written claim that the software -infringes or contributes to infringement of any patent, your patent license for -the software granted under these terms ends immediately. If your company makes -such a claim, your patent license ends immediately for work on behalf of your -company. - -## Notices - -You must ensure that anyone who gets a copy of any part of the software from you -also gets a copy of these terms. - -If you modify the software, you must include in any modified copies of the -software prominent notices stating that you have modified the software. - -## No Other Rights - -These terms do not imply any licenses other than those expressly granted in -these terms. - -## Termination - -If you use the software in violation of these terms, such use is not licensed, -and your licenses will automatically terminate. If the licensor provides you -with a notice of your violation, and you cease all violation of this license no -later than 30 days after you receive that notice, your licenses will be -reinstated retroactively. However, if you violate these terms after such -reinstatement, any additional violation of these terms will cause your licenses -to terminate automatically and permanently. - -## No Liability - -*As far as the law allows, the software comes as is, without any warranty or -condition, and the licensor will not be liable to you for any damages arising -out of these terms or the use or nature of the software, under any kind of -legal claim.* - -## Definitions - -The **licensor** is the entity offering these terms, and the **software** is the -software the licensor makes available under these terms, including any portion -of it. - -**you** refers to the individual or entity agreeing to these terms. - -**your company** is any legal entity, sole proprietorship, or other kind of -organization that you work for, plus all organizations that have control over, -are under the control of, or are under common control with that -organization. **control** means ownership of substantially all the assets of an -entity, or the power to direct its management and policies by vote, contract, or -otherwise. Control can be direct or indirect. - -**your licenses** are all the licenses granted to you for the software under -these terms. - -**use** means anything you do with the software requiring one of your licenses. - -**trademark** means trademarks, service marks, and similar rights. \ No newline at end of file diff --git a/LICENSE.txt b/LICENSE.txt new file mode 100644 index 00000000..77e2f78b --- /dev/null +++ b/LICENSE.txt @@ -0,0 +1,7 @@ +Source code in this repository is covered by the KeyAuth License v1.0. + +KeyAuth License v1.0: +https://github.com/KeyAuth/KeyAuth-Source-Code/blob/main/LICENSE_KEYAUTH.txt + +No grant of any rights in the trademarks, service marks, or logos of KeyAuth is +made. diff --git a/LICENSE_KEYAUTH.txt b/LICENSE_KEYAUTH.txt new file mode 100644 index 00000000..3dfa7ce6 --- /dev/null +++ b/LICENSE_KEYAUTH.txt @@ -0,0 +1,179 @@ +KEYAUTH LICENSE AGREEMENT +Version 1.1, 27 February 2022 + +PLEASE CAREFULLY READ THIS KEYAUTH LICENSE AGREEMENT ("AGREEMENT"). THIS +AGREEMENT CONSTITUTES A LEGALLY BINDING AGREEMENT BETWEEN YOU AND NELSON +CYBERSECURITY LLC. ("OWNER OF KEYAUTH") AND GOVERNS YOUR USE OF THE COMMERCIAL MODULES (DEFINED +BELOW). BY COPYING OR USING THE COMMERCIAL MODULES, YOU AGREE TO THIS AGREEMENT. +IF YOU DO NOT AGREE WITH THIS AGREEMENT, YOU MAY NOT COPY OR USE THE COMMERCIAL +MODULES. IF YOU ARE COPYING OR USING THE COMMERCIAL MODULES ON BEHALF OF A LEGAL +ENTITY, YOU REPRESENT AND WARRANT THAT YOU HAVE AUTHORITY TO AGREE TO THIS +AGREEMENT ON BEHALF OF SUCH ENTITY. IF YOU DO NOT HAVE SUCH AUTHORITY, DO NOT +COPY OR USE THE COMMERCIAL MODULES IN ANY MANNER. + +This Agreement is entered into by and between Nelson Cybersecurity LLC and you, or the legal +entity on behalf of whom you are acting (as applicable, "You" or "Your"). + +1. DEFINITIONS + +"KeyAuth Software" means the KeyAuth server software, libraries, and +Commercial Modules. + +"Commercial Modules" means the modules designed to work with and enhance the +KeyAuth Software to which this Agreement is linked, referenced, or appended. + +2. LICENSES, RESTRICTIONS AND THIRD PARTY CODE + +2.1 Commercial Module License. Subject to Your compliance with this Agreement, +KeyAuth hereby grants to You a limited, non-exclusive, non-transferable, +royalty-free license to use the Commercial Modules for the sole purposes of +internal development and internal testing, and only in a non-production +environment. + +2.2 Reservation of Rights. As between KeyAuth and You, KeyAuth owns all +right, title and interest in and to the KeyAuth Software, and except as +expressly set forth in Sections 2.1, no other license to the KeyAuth Software +is granted to You under this Agreement, by implication, estoppel, or otherwise. + +2.3 Restrictions. You agree not to: (i) except as expressly permitted in +Section 2.1, sell, rent, lease, distribute, sublicense, loan or otherwise +transfer the Commercial Modules to any third party; (ii) alter or remove any +trademarks, service mark, and logo included with the Commercial Modules, or +(iii) use the Commercial Modules to create a competing product or service. +KeyAuth is not obligated to provide maintenance and support services for the +KeyAuth Software licensed under this Agreement. + +2.4 Third Party Software. The Commercial Modules may contain or be provided +with third party open source libraries, components, utilities and other open +source software (collectively, "Open Source Software"). Notwithstanding anything +to the contrary herein, use of the Open Source Software will be subject to the +license terms and conditions applicable to such Open Source Software. To the +extent any condition of this Agreement conflicts with any license to the Open +Source Software, the Open Source Software license will govern with respect to +such Open Source Software only. + +2.5 This Agreement does not grant any rights in the trademarks, service marks, or +logos of any Contributor. + +3. TERMINATION + +3.1 Termination. This Agreement will automatically terminate upon notice from +KeyAuth, which notice may be by email or posting in the location where the +Commercial Modules are made available. + +3.2 Effect of Termination. Upon any termination of this Agreement, for any +reason, You will promptly cease use of the Commercial Modules and destroy any +copies thereof. For the avoidance of doubt, termination of this Agreement will +not affect Your right to KeyAuth Software, other than the Commercial Modules, +made available pursuant to an Open Source Software license. + +3.3 Survival. Sections 1, 2.2 -2.4, 3.2, 3.3, 4, and 5 will survive any +termination of this Agreement. + +4. DISCLAIMER AND LIMITATION OF LIABILITY + +4.1 Disclaimer of Warranties. TO THE MAXIMUM EXTENT PERMITTED UNDER APPLICABLE +LAW, THE KEYAUTH SOFTWARE IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED REGARDING OR RELATING TO THE KEYAUTH SOFTWARE, INCLUDING +ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, +TITLE, AND NON-INFRINGEMENT. FURTHER, KEYAUTH DOES NOT WARRANT RESULTS OF USE +OR THAT THE KEYAUTH SOFTWARE WILL BE ERROR FREE OR THAT THE USE OF THE +KEYAUTH SOFTWARE WILL BE UNINTERRUPTED. + +4.2 Limitation of Liability. IN NO EVENT WILL KEYAUTH OR ITS LICENSORS BE +LIABLE TO YOU OR ANY THIRD PARTY UNDER THIS AGREEMENT FOR (I) ANY AMOUNTS IN +EXCESS OF US $25 OR (II) FOR ANY SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES OF +ANY KIND, INCLUDING FOR ANY LOSS OF PROFITS, LOSS OF USE, BUSINESS INTERRUPTION, +LOSS OF DATA, COST OF SUBSTITUTE GOODS OR SERVICES, WHETHER ALLEGED AS A BREACH +OF CONTRACT OR TORTIOUS CONDUCT, INCLUDING NEGLIGENCE, EVEN IF KEYAUTH HAS +BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + +5. MISCELLANEOUS + +5.1 Assignment. You may not assign or otherwise transfer this Agreement or any +rights or obligations hereunder, in whole or in part, whether by operation of +law or otherwise, to any third party without KEYAUTH's prior written consent. +Any purported transfer, assignment or delegation without such prior written +consent will be null and void and of no force or effect. KEYAUTH may assign +this Agreement to any successor to its business or assets to which this +Agreement relates, whether by merger, sale of assets, sale of stock, +reorganization or otherwise. Subject to this Section 5.1, this Agreement will be +binding upon and inure to the benefit of the parties hereto, and their +respective successors and permitted assigns. + +5.2 Entire Agreement; Modification; Waiver. This Agreement represents the +entire agreement between the parties, and supersedes all prior agreements and +understandings, written or oral, with respect to the matters covered by this +Agreement, and is not intended to confer upon any third party any rights or +remedies hereunder. You acknowledge that You have not entered in this Agreement +based on any representations other than those contained herein. No modification +of or amendment to this Agreement, nor any waiver of any rights under this +Agreement, will be effective unless in writing and signed by both parties. The +waiver of one breach or default or any delay in exercising any rights will not +constitute a waiver of any subsequent breach or default. + +5.3 Governing Law. This Agreement will in all respects be governed by the laws +of the State of Florida without reference to its principles of conflicts of +laws. The parties hereby agree that all disputes arising out of this Agreement +will be subject to the exclusive jurisdiction of and venue in the federal and +state courts within Orange County, Florida. You hereby consent to the +personal and exclusive jurisdiction and venue of these courts. The parties +hereby disclaim and exclude the application hereto of the United Nations +Convention on Contracts for the International Sale of Goods. + +5.4 Severability. If any provision of this Agreement is held invalid or +unenforceable under applicable law by a court of competent jurisdiction, it will +be replaced with the valid provision that most closely reflects the intent of +the parties and the remaining provisions of the Agreement will remain in full +force and effect. + +5.5 Relationship of the Parties. Nothing in this Agreement is to be construed +as creating an agency, partnership, or joint venture relationship between the +parties hereto. Neither party will have any right or authority to assume or +create any obligations or to make any representations or warranties on behalf of +any other party, whether express or implied, or to bind the other party in any +respect whatsoever. + +5.6 Notices. All notices permitted or required under this Agreement will be in +writing and will be deemed to have been given when delivered in person +(including by overnight courier), or three (3) business days after being mailed +by first class, registered or certified mail, postage prepaid, to the address of +the party specified in this Agreement or such other address as either party may +specify in writing. + +5.7 U.S. Government Restricted Rights. If Commercial Modules is being licensed +by the U.S. Government, the Commercial Modules is deemed to be "commercial +computer software" and "commercial computer documentation" developed exclusively +at private expense, and (a) if acquired by or on behalf of a civilian agency, +will be subject solely to the terms of this computer software license as +specified in 48 C.F.R. 12.212 of the Federal Acquisition Regulations and its +successors; and (b) if acquired by or on behalf of units of the Department of +Defense ("DOD") will be subject to the terms of this commercial computer +software license as specified in 48 C.F.R. 227.7202-2, DOD FAR Supplement and +its successors. + +5.8 Injunctive Relief. A breach or threatened breach by You of Section 2 may +cause irreparable harm for which damages at law may not provide adequate relief, +and therefore KEYAUTH will be entitled to seek injunctive relief in any +applicable jurisdiction without being required to post a bond. + +5.9 Export Law Assurances. You understand that the Commercial Modules is +subject to export control laws and regulations. You may not download or +otherwise export or re-export the Commercial Modules or any underlying +information or technology except in full compliance with all applicable laws and +regulations, in particular, but without limitation, United States export control +laws. None of the Commercial Modules or any underlying information or technology +may be downloaded or otherwise exported or re- exported: (a) into (or to a +national or resident of) any country to which the United States has embargoed +goods; or (b) to anyone on the U.S. Treasury Department's list of specially +designated nationals or the U.S. Commerce Department's list of prohibited +countries or debarred or denied persons or entities. You hereby agree to the +foregoing and represents and warrants that You are not located in, under control +of, or a national or resident of any such country or on any such list. + +5.10 Construction. The titles and section headings used in this Agreement are +for ease of reference only and will not be used in the interpretation or +construction of this Agreement. No rule of construction resolving any ambiguity +in favor of the non-drafting party will be applied hereto. The word "including", +when used herein, is illustrative rather than exclusive and means "including, +without limitation." diff --git a/README.md b/README.md index 6a8df115..9f5bd627 100644 --- a/README.md +++ b/README.md @@ -1,44 +1,22 @@ -# KeyAuth Source Code -> Please star :star2: - -> [!WARNING] -> AS OF JANUARY 29th, 2024 - THIS REPOSITORY IS NO LONGER BEING UPDATED! - -[KeyAuth](https://keyauth.win) is an open source authentication system with [cloud-hosted subscriptions](https://keyauth.win/app/?page=upgrade) available as well. +# KeyAuth-Source-Code +KeyAuth is an open source authentication system with cloud-hosted subscriptions available aswell https://keyauth.cc
*You're not allowed to sell KeyAuth. source made avaliable only for you to use* -To submit a suggestion or a bug, please go to https://keyauth.cc/app/?page=forms and submit a form! +View #suggestions and #bugs channel in Discord server if you want to suggest new feature or submit bug https://discord.gg/keyauth [![CodeFactor](https://www.codefactor.io/repository/github/keyauth/keyauth-source-code/badge)](https://www.codefactor.io/repository/github/keyauth/keyauth-source-code) -[![Telegram Chat](https://img.shields.io/endpoint?color=neon&style=flat-square&url=https%3A%2F%2Ftg.sumanjay.workers.dev%2Fkeyauth)](https://t.me/KeyAuth) +[![Discord](https://img.shields.io/discord/824397012685291520?label=Discord&cacheSeconds=3600)](https://discord.gg/UNk3MphscB) [![Twitter](https://img.shields.io/twitter/follow/KeyAuth?cacheSeconds=3600)](https://twitter.com/KeyAuth) -[![Screenshot](https://cdn.keyauth.cc/v3/imgs/Screenshot%20from%202025-07-04%2012-07-30.png)](https://keyauth.cc) +[![Screenshot](https://i.imgur.com/rige1nM.png)](https://keyauth.cc) ## Bugs ## -If the default example that isn't added to your software isn't functioning how it should, please go to https://keyauth.cc/app/?page=forms and submit a bug report in the `Report a Bug` modal. +If the default example not added to your software isn't functioning how it should, please join the Discord server https://discord.gg/keyauth and submit the issue in the `#bugs` channel. However, we do **NOT** provide support for adding KeyAuth to your project. If you can't figure this out you should use Google or YouTube to learn more about the programming language you want to sell a program in. -## Copyright License - -KeyAuth is licensed under **Elastic License 2.0** - -* You may not provide the software to third parties as a hosted or managed -service, where the service provides users with access to any substantial set of -the features or functionality of the software. - -* You may not move, change, disable, or circumvent the license key functionality -in the software, and you may not remove or obscure any functionality in the -software that is protected by the license key. - -* You may not alter, remove, or obscure any licensing, copyright, or other notices -of the licensor in the software. Any use of the licensor’s trademarks is subject -to applicable law. - -Thank you for your compliance, we work hard on the development of KeyAuth and do not appreciate our copyright being infringed. - ## Requirements ## - Web server (Apache or Nginx) @@ -46,12 +24,12 @@ Thank you for your compliance, we work hard on the development of KeyAuth and do - Redis - PHP -No setup support given to non-enterprise users. However for $79.99 you can purchase access to the source code of paid features (developer and seller plan features), setup support 1-on-1 with the owner of KeyAuth, and a tutorial video on how to host KeyAuth for 100% free forever (good preformance & secure also) +No setup support given to non-enterprise users. However for $79.99 you can purchase access to the source code of paid features (developer and seller plan features), setup support one-on-one with the Founder of KeyAuth, and a tutorial video on how to host KeyAuth for 100% free forever (good preformance & secure also) -Purchase enterprise today --> https://keyauth.win/app/?page=upgrade +Purchase enterprise today --> https://shop.keyauth.cc/product/6361c20e415e9 -## Updates ## +Some pages such as the API endpoint that upgrades users after they purchase a subscription have been omitted to prevent violation of the license (No Commercial Access Allowed) -https://keyauth.canny.io/changelog +## Updates ## -Looking for a Discord bot made by the KeyAuth & RestoreCord founder that you can use to backup your Discord members, server settings, and messages? Go to https://vaultcord.com +https://headwayapp.co/keyauth-changelog/ diff --git a/api/1.0/index.php b/api/1.0/index.php index 7c56d9a0..0c5f8eb8 100644 --- a/api/1.0/index.php +++ b/api/1.0/index.php @@ -1,37 +1,19 @@ getMessage()); - die(json_encode(array("success" => false, "message" => "Error: " . $errorMsg))); -}); - -if(empty($_POST['ownerid'])) { - die(json_encode(array("success" => false, "message" => "No OwnerID specified. Select app & copy code snippet from https://keyauth.cc/app/"))); -} - -if(empty($_POST['name'])) { - die(json_encode(array("success" => false, "message" => "No app name specified. Select app & copy code snippet from https://keyauth.cc/app/"))); -} - -if(strlen(hex2bin($_POST['ownerid'])) != 10) { - die(json_encode(array("success" => false, "message" => "OwnerID should be 10 characters long. Select app & copy code snippet from https://keyauth.cc/app/"))); +if (isset($_SERVER['HTTP_CDN_HOST'])) { // custom domains https://www.youtube.com/watch?v=a2SROFJ0eYc + $row = misc\cache\fetch('KeyAuthApp:' . misc\etc\sanitize($_SERVER['HTTP_CDN_HOST']), "SELECT * FROM `apps` WHERE `customDomainAPI` = '" . misc\etc\sanitize($_SERVER['HTTP_CDN_HOST']) . "'", 0); +} else { + $ownerid = misc\etc\sanitize(hex2bin($_POST['ownerid'])); // ownerid of account that owns application + $name = misc\etc\sanitize(hex2bin($_POST['name'])); // application name + $row = misc\cache\fetch('KeyAuthApp:' . $name . ':' . $ownerid, "SELECT * FROM `apps` WHERE `ownerid` = '$ownerid' AND `name` = '$name'", 0); } -$ownerid = misc\etc\sanitize(hex2bin($_POST['ownerid'])); // ownerid of account that owns application -$name = misc\etc\sanitize(hex2bin($_POST['name'])); // application name -$row = misc\cache\fetch('KeyAuthApp:' . $name . ':' . $ownerid, "SELECT * FROM `apps` WHERE `ownerid` = ? AND `name` = ?", [$ownerid, $name], 0); - if ($row == "not_found") { die("KeyAuth_Invalid"); } @@ -48,8 +30,6 @@ $appdisabled = $row['appdisabled']; $hashcheck = $row['hashcheck']; $serverhash = $row['hash']; -$sessionexpiry = $row['session']; -$forceHwid = $row['forceHwid']; $banned = $row['banned']; $owner = $row['owner']; @@ -66,31 +46,19 @@ $noactivesubs = $row['noactivesubs']; $hwidblacked = $row['hwidblacked']; $pausedsub = $row['pausedsub']; +$keyexpired = $row['keyexpired']; $vpnblocked = $row['vpnblocked']; $keybanned = $row['keybanned']; $userbanned = $row['userbanned']; $sessionunauthed = $row['sessionunauthed']; $hashcheckfail = $row['hashcheckfail']; - -// why using null coalescing operators? because if I add a field and it's not in redis cache, it'll be NULL -$loggedInMsg = $row['loggedInMsg'] ?? "Logged in!"; -$pausedApp = $row['pausedApp'] ?? "Application is currently paused, please wait for the developer to say otherwise."; -$unTooShort = $row['unTooShort'] ?? "Username too short, try longer one."; -$pwLeaked = $row['pwLeaked'] ?? "This password has been leaked in a data breach (not from us), please use a different one."; -$chatHitDelay = $row['chatHitDelay'] ?? "Chat slower, you've hit the delay limit"; -$minHwid = $row['minHwid'] ?? 20; +$sessionexpiry = $row['session']; +$killOtherSessions = $row['killOtherSessions']; if ($banned) { die(api\v1_0\Encrypt(json_encode(array( "success" => false, - "message" => "This application has been banned from KeyAuth.cc for violating terms." // yes we self promote to customers of those who break ToS. Should've followed terms :shrug: - )), $secret)); -} - -if ($_GET['host'] == "keyauth.business") { - die(api\v1_0\Encrypt(json_encode(array( - "success" => false, - "message" => "Please tell the developer of this program to use latest API domain. This domain is old, it will expire in a month." + "message" => "This application has been banned from KeyAuth.com for violating terms." // yes we self promote to customers of those who break ToS. Should've followed terms :shrug: )), $secret)); } @@ -99,13 +67,10 @@ $ip = api\shared\primary\getIp(); if ($vpnblock) { if (api\shared\primary\vpnCheck($ip)) { - $row = misc\cache\fetch('KeyAuthWhitelist:' . $secret . ':' . $ip, "SELECT 1 FROM `whitelist` WHERE `ip` = ? AND `app` = ?", [$ip, $secret], 0); - if ($row == "not_found") { - die(api\v1_0\Encrypt(json_encode(array( - "success" => false, - "message" => "$vpnblocked" - )), $secret)); - } + die(api\v1_0\Encrypt(json_encode(array( + "success" => false, + "message" => "$vpnblocked" + )), $secret)); } } @@ -119,7 +84,7 @@ if ($paused) { die(api\v1_0\Encrypt(json_encode(array( "success" => false, - "message" => "$pausedApp" + "message" => "Application is currently paused, please wait for the developer to say otherwise." )), $secret)); } @@ -139,7 +104,8 @@ if ($hashcheck) { if (strpos($serverhash, $hash) === false) { if (is_null($serverhash)) { - misc\mysql\query("UPDATE `apps` SET `hash` = ? WHERE `secret` = ?", [$hash, $secret]); + include_once (($_SERVER['DOCUMENT_ROOT'] == "/usr/share/nginx/html/panel" || $_SERVER['DOCUMENT_ROOT'] == "/usr/share/nginx/html/api") ? "/usr/share/nginx/html" : $_SERVER['DOCUMENT_ROOT']) . '/includes/connection.php'; // create connection with MySQL + mysqli_query($link, "UPDATE `apps` SET `hash` = '$hash' WHERE `secret` = '$secret'"); misc\cache\purge('KeyAuthApp:' . $name . ':' . $ownerid); // flush cache for application so new hash takes precedent } else { die(api\v1_0\Encrypt(json_encode(array( @@ -151,51 +117,30 @@ } $enckey = misc\etc\sanitize(api\v1_0\Decrypt($_POST['enckey'], $secret)); + $sessionid = misc\etc\generateRandomString(); + // session init + $time = time() + $sessionexpiry; + include_once (($_SERVER['DOCUMENT_ROOT'] == "/usr/share/nginx/html/panel" || $_SERVER['DOCUMENT_ROOT'] == "/usr/share/nginx/html/api") ? "/usr/share/nginx/html" : $_SERVER['DOCUMENT_ROOT']) . '/includes/connection.php'; // create connection with MySQL + mysqli_query($link, "INSERT INTO `sessions` (`id`, `app`, `expiry`, `enckey`,`ip`) VALUES ('$sessionid','$secret', '$time', '$enckey', '$ip')"); - $newSession = false; - $duplicateSession = misc\cache\select("KeyAuthSessionDupe:$secret:$ip"); - if($duplicateSession) { - $sessionid = $duplicateSession; - $updateSession = misc\cache\update('KeyAuthState:'.$secret.':'.$sessionid.'', array("enckey" => $enckey)); - if(!$updateSession) { - $sessionid = misc\etc\generateRandomString(); - $newSession = true; - } - } - else { - $sessionid = misc\etc\generateRandomString(); - $newSession = true; - } - - // $row = misc\cache\fetch('KeyAuthAppStats:' . $secret, "SELECT (SELECT COUNT(1) FROM `users` WHERE `app` = ?) AS 'numUsers', (SELECT COUNT(1) FROM `sessions` WHERE `app` = ? AND `validated` = 1 AND `expiry` > ?) AS 'numOnlineUsers', (SELECT COUNT(1) FROM `keys` WHERE `app` = ?) AS 'numKeys' FROM dual", [$secret, $secret, time(), $secret], 0, 3600); + $row = misc\cache\fetch('KeyAuthAppStats:' . $secret, "SELECT(select count(1) FROM `users` WHERE `app` = '$secret') AS 'numUsers',(select count(1) FROM `sessions` WHERE `app` = '$secret' AND `validated` = 1 AND `expiry` > " . time() . ") AS 'numOnlineUsers',(select count(1) FROM `keys` WHERE `app` = '$secret') AS 'numKeys';", 0, 1800); - $numUsers = "N/A - Use fetchStats() function in latest example"; - $numOnlineUsers = "N/A - Use fetchStats() function in latest example"; - $numKeys = "N/A - Use fetchStats() function in latest example"; + $numUsers = $row['numUsers']; + $numOnlineUsers = $row['numOnlineUsers']; + $numKeys = $row['numKeys']; - echo api\v1_0\Encrypt(json_encode(array( + die(api\v1_0\Encrypt(json_encode(array( "success" => true, "message" => "Initialized", "sessionid" => $sessionid, "appinfo" => array( - "numUsers" => "$numUsers", - "numOnlineUsers" => "$numOnlineUsers", - "numKeys" => "$numKeys", - "version" => "$currentver", + "numUsers" => $numUsers, + "numOnlineUsers" => $numOnlineUsers, + "numKeys" => $numKeys, + "version" => $currentver, "customerPanelLink" => "https://keyauth.cc/panel/$owner/$name/" ) - )), $secret); - - fastcgi_finish_request(); - - if($newSession) { - misc\cache\insert("KeyAuthState:$secret:$sessionid", serialize(array("credential" => NULL, "enckey" => $enckey, "validated" => 0)), $sessionexpiry); - $time = time() + $sessionexpiry; - misc\mysql\query("INSERT INTO `sessions` (`id`, `app`, `expiry`, `created_at`, `enckey`,`ip`) VALUES (?, ?, ?, ?, ?, ?)", [$sessionid, $secret, $time, time(), $enckey, $ip]); - $session = api\shared\primary\getSession($sessionid, $secret); - $enckey = $session["enckey"]; - misc\cache\insert("KeyAuthSessionDupe:$secret:$ip", $sessionid, $sessionexpiry); - } + )), $secret)); case 'register': // retrieve session info @@ -206,33 +151,16 @@ // Read in username $username = misc\etc\sanitize(api\v1_0\Decrypt($_POST['username'], $enckey)); - if(strlen($username) > 70) { - die(api\v1_0\Encrypt(json_encode(array( - "success" => false, - "message" => "Username must be shorter than 70 characters" - )), $enckey)); - } - // Read in license key $checkkey = misc\etc\sanitize(api\v1_0\Decrypt($_POST['key'], $enckey)); - if(strlen($checkkey) > 70) { - die(api\v1_0\Encrypt(json_encode(array( - "success" => false, - "message" => "Key must be shorter than 70 characters" - )), $enckey)); - } - // Read in password $password = misc\etc\sanitize(api\v1_0\Decrypt($_POST['pass'], $enckey)); - // Read in email - $email = misc\etc\sanitize(api\v1_0\Decrypt($_POST['email'], $enckey)); - // Read in hwid $hwid = misc\etc\sanitize(api\v1_0\Decrypt($_POST['hwid'], $enckey)); - $resp = api\v1_0\register($username, $checkkey, $password, $email, $hwid, $secret); + $resp = api\v1_0\register($username, $checkkey, $password, $hwid, $secret); switch ($resp) { case 'username_taken': die(api\v1_0\Encrypt(json_encode(array( @@ -247,12 +175,12 @@ case 'un_too_short': die(api\v1_0\Encrypt(json_encode(array( "success" => false, - "message" => "$unTooShort" + "message" => "Username too short, try longer one." )), $enckey)); case 'pw_leaked': die(api\v1_0\Encrypt(json_encode(array( "success" => false, - "message" => "$pwLeaked" + "message" => "This password has been leaked in a data breach (not from us), please use a different one." )), $enckey)); case 'key_already_used': die(api\v1_0\Encrypt(json_encode(array( @@ -261,8 +189,9 @@ )), $enckey)); case 'key_banned': if (strpos($keybanned, '{reason}') !== false) { - $query = misc\mysql\query("SELECT `banned` FROM `keys` WHERE `app` = ? AND `key` = ?", [$secret, $checkkey]); - $row = mysqli_fetch_array($query->result); + include_once (($_SERVER['DOCUMENT_ROOT'] == "/usr/share/nginx/html/panel" || $_SERVER['DOCUMENT_ROOT'] == "/usr/share/nginx/html/api") ? "/usr/share/nginx/html" : $_SERVER['DOCUMENT_ROOT']) . '/includes/connection.php'; // create connection with MySQL + $result = mysqli_query($link, "SELECT `banned` FROM `keys` WHERE `app` = '$secret' AND `key` = '$checkkey'"); + $row = mysqli_fetch_array($result); $reason = $row['banned']; $keybanned = str_replace("{reason}", $reason, $keybanned); } @@ -281,11 +210,16 @@ "message" => "$nosublevel" )), $enckey)); default: - misc\mysql\query("UPDATE `sessions` SET `credential` = ?,`validated` = 1 WHERE `id` = ? AND `app` = ?", [$username, $sessionid, $secret]); - misc\cache\update('KeyAuthState:'.$secret.':'.$sessionid.'', array("validated" => 1, "credential" => $username)); + include_once (($_SERVER['DOCUMENT_ROOT'] == "/usr/share/nginx/html/panel" || $_SERVER['DOCUMENT_ROOT'] == "/usr/share/nginx/html/api") ? "/usr/share/nginx/html" : $_SERVER['DOCUMENT_ROOT']) . '/includes/connection.php'; // create connection with MySQL + if ($killOtherSessions) { + mysqli_query($link, "DELETE FROM `sessions` WHERE `id` != '$sessionid' AND `credential` = '$username' AND `app` = '$secret'"); + misc\cache\purgePattern('KeyAuthState:' . $secret); + } + mysqli_query($link, "UPDATE `sessions` SET `credential` = '$username',`validated` = 1 WHERE `id` = '$sessionid' AND `app` = '$secret'"); + misc\cache\purge('KeyAuthState:' . $secret . ':' . $sessionid); die(api\v1_0\Encrypt(json_encode(array( "success" => true, - "message" => "$loggedInMsg", + "message" => "Logged in!", "info" => $resp )), $enckey)); } @@ -301,21 +235,22 @@ // Read in key $checkkey = misc\etc\sanitize(api\v1_0\Decrypt($_POST['key'], $enckey)); + include_once (($_SERVER['DOCUMENT_ROOT'] == "/usr/share/nginx/html/panel" || $_SERVER['DOCUMENT_ROOT'] == "/usr/share/nginx/html/api") ? "/usr/share/nginx/html" : $_SERVER['DOCUMENT_ROOT']) . '/includes/connection.php'; // create connection with MySQL // search for key - $query = misc\mysql\query("SELECT `banned`, `expires`, `status`, `level` FROM `keys` WHERE `key` = ? AND `app` = ?", [$checkkey, $secret]); + $result = mysqli_query($link, "SELECT `banned`, `expires`, `status`, `level` FROM `keys` WHERE `key` = '$checkkey' AND `app` = '$secret'"); // check if key exists - if ($query->num_rows < 1) { + if (mysqli_num_rows($result) < 1) { die(api\v1_0\Encrypt(json_encode(array( "success" => false, "message" => "$keynotfound" )), $enckey)); } // if key does exist - elseif ($query->num_rows > 0) { + elseif (mysqli_num_rows($result) > 0) { // get key info - while ($row = mysqli_fetch_array($query->result)) { + while ($row = mysqli_fetch_array($result)) { $expires = $row['expires']; $status = $row['status']; $level = $row['level']; @@ -331,52 +266,54 @@ } if (!is_null($banned)) { - if (strpos($keybanned, '{reason}') !== false) { - $keybanned = str_replace("{reason}", $banned, $keybanned); - } die(api\v1_0\Encrypt(json_encode(array( "success" => false, - "message" => "$keybanned" + "message" => "Key banned: {$banned}" )), $enckey)); } // add current time to key time $expiry = $expires + time(); - $query = misc\mysql\query("SELECT `name` FROM `subscriptions` WHERE `app` = ? AND `level` = ?", [$secret, $level]); - $subName = mysqli_fetch_array($query->result)['name']; + $result = mysqli_query($link, "SELECT `name` FROM `subscriptions` WHERE `app` = '$secret' AND `level` = '$level'"); + $subName = mysqli_fetch_array($result)['name']; - $resp = misc\user\extend($username, $subName, $expiry, 0, $secret); + $resp = misc\user\extend($username, $subName, $expiry, $secret); switch ($resp) { case 'missing': die(api\v1_0\Encrypt(json_encode(array( "success" => false, "message" => "$usernamenotfound" )), $enckey)); + break; case 'sub_missing': die(api\v1_0\Encrypt(json_encode(array( "success" => false, "message" => "$nosublevel" )), $enckey)); + break; case 'failure': die(api\v1_0\Encrypt(json_encode(array( "success" => false, "message" => "Failed to upgrade for some reason." )), $enckey)); + break; case 'success': // set key to used, and set usedby - misc\mysql\query("UPDATE `keys` SET `status` = 'Used', `usedon` = ?, `usedby` = ? WHERE `key` = ? AND `app` = ?", [time(), $username, $checkkey, $secret]); + mysqli_query($link, "UPDATE `keys` SET `status` = 'Used', `usedon` = '" . time() . "', `usedby` = '$username' WHERE `key` = '$checkkey' AND `app` = '$secret'"); misc\cache\purge('KeyAuthKeys:' . $secret . ':' . $checkkey); - misc\cache\purge('KeyAuthSubs:' . $secret . ':' . $username); + misc\cache\purge('KeyAuthSubs:' . $secret . ':' . $username); die(api\v1_0\Encrypt(json_encode(array( "success" => true, "message" => "Upgraded successfully" )), $enckey)); + break; default: die(api\v1_0\Encrypt(json_encode(array( "success" => false, "message" => "Unhandled Error! Contact us if you need help" )), $enckey)); + break; } } @@ -395,20 +332,6 @@ // Read in password $password = misc\etc\sanitize(api\v1_0\Decrypt($_POST['pass'], $enckey)); - if(strlen($hwid) < $minHwid && !is_null($hwid)) { - die(api\v1_0\Encrypt(json_encode(array( - "success" => false, - "message" => "HWID must be {$minHwid} or more characters, change this in app settings." - )), $enckey)); - } - - if($forceHwid && is_null($hwid)) { - die(api\v1_0\Encrypt(json_encode(array( - "success" => false, - "message" => "Force HWID is enabled, disable in app settings if you want to use blank HWIDs" - )), $enckey)); - } - $resp = api\v1_0\login($username, $password, $hwid, $secret, $hwidenabled); switch ($resp) { case 'un_not_found': @@ -423,8 +346,9 @@ )), $enckey)); case 'user_banned': if (strpos($userbanned, '{reason}') !== false) { - $query = misc\mysql\query("SELECT `banned` FROM `users` WHERE `app` = ? AND `username` = ?", [$secret, $username]); - $row = mysqli_fetch_array($query->result); + include_once (($_SERVER['DOCUMENT_ROOT'] == "/usr/share/nginx/html/panel" || $_SERVER['DOCUMENT_ROOT'] == "/usr/share/nginx/html/api") ? "/usr/share/nginx/html" : $_SERVER['DOCUMENT_ROOT']) . '/includes/connection.php'; // create connection with MySQL + $result = mysqli_query($link, "SELECT `banned` FROM `users` WHERE `app` = '$secret' AND `username` = '$username'"); + $row = mysqli_fetch_array($result); $reason = $row['banned']; $userbanned = str_replace("{reason}", $reason, $userbanned); } @@ -453,11 +377,16 @@ "message" => "$noactivesubs" )), $enckey)); default: - misc\mysql\query("UPDATE `sessions` SET `validated` = 1,`credential` = ? WHERE `id` = ? AND `app` = ?", [$username, $sessionid, $secret]); - misc\cache\update('KeyAuthState:'.$secret.':'.$sessionid.'', array("validated" => 1, "credential" => $username)); + include_once (($_SERVER['DOCUMENT_ROOT'] == "/usr/share/nginx/html/panel" || $_SERVER['DOCUMENT_ROOT'] == "/usr/share/nginx/html/api") ? "/usr/share/nginx/html" : $_SERVER['DOCUMENT_ROOT']) . '/includes/connection.php'; // create connection with MySQL + mysqli_query($link, "UPDATE `sessions` SET `validated` = 1,`credential` = '$username' WHERE `id` = '$sessionid' AND `app` = '$secret'"); + if ($killOtherSessions) { + mysqli_query($link, "DELETE FROM `sessions` WHERE `id` != '$sessionid' AND `credential` = '$username' AND `app` = '$secret'"); + misc\cache\purgePattern('KeyAuthState:' . $secret); + } + misc\cache\purge('KeyAuthState:' . $secret . ':' . $sessionid); die(api\v1_0\Encrypt(json_encode(array( "success" => true, - "message" => "$loggedInMsg", + "message" => "Logged in!", "info" => $resp )), $enckey)); } @@ -469,33 +398,13 @@ $enckey = $session["enckey"]; $checkkey = misc\etc\sanitize(api\v1_0\Decrypt($_POST['key'], $enckey)); - if(strlen($checkkey) > 70) { - die(api\v1_0\Encrypt(json_encode(array( - "success" => false, - "message" => "Key must be shorter than 70 characters" - )), $enckey)); - } - $hwid = misc\etc\sanitize(api\v1_0\Decrypt($_POST['hwid'], $enckey)); - if(strlen($hwid) < $minHwid && !is_null($hwid)) { - die(api\v1_0\Encrypt(json_encode(array( - "success" => false, - "message" => "HWID must be {$minHwid} or more characters, change this in app settings." - )), $enckey)); - } - - if($forceHwid && is_null($hwid)) { - die(api\v1_0\Encrypt(json_encode(array( - "success" => false, - "message" => "Force HWID is enabled, disable in app settings if you want to use blank HWIDs" - )), $enckey)); - } - $resp = api\v1_0\login($checkkey, $checkkey, $hwid, $secret, $hwidenabled); switch ($resp) { case 'un_not_found': break; // user not registered yet or user was deleted + case 'hwid_mismatch': die(api\v1_0\Encrypt(json_encode(array( "success" => false, @@ -503,8 +412,9 @@ )), $enckey)); case 'user_banned': if (strpos($userbanned, '{reason}') !== false) { - $query = misc\mysql\query("SELECT `banned` FROM `users` WHERE `app` = ? AND `username` = ?", [$secret, $checkkey]); - $row = mysqli_fetch_array($query->result); + include_once (($_SERVER['DOCUMENT_ROOT'] == "/usr/share/nginx/html/panel" || $_SERVER['DOCUMENT_ROOT'] == "/usr/share/nginx/html/api") ? "/usr/share/nginx/html" : $_SERVER['DOCUMENT_ROOT']) . '/includes/connection.php'; // create connection with MySQL + $result = mysqli_query($link, "SELECT `banned` FROM `users` WHERE `app` = '$secret' AND `username` = '$checkkey'"); + $row = mysqli_fetch_array($result); $reason = $row['banned']; $userbanned = str_replace("{reason}", $reason, $userbanned); } @@ -533,17 +443,22 @@ "message" => "$noactivesubs" )), $enckey)); default: - misc\mysql\query("UPDATE `sessions` SET `validated` = 1,`credential` = ? WHERE `id` = ?", [$checkkey, $sessionid]); - misc\cache\update('KeyAuthState:'.$secret.':'.$sessionid.'', array("validated" => 1, "credential" => $checkkey)); + include_once (($_SERVER['DOCUMENT_ROOT'] == "/usr/share/nginx/html/panel" || $_SERVER['DOCUMENT_ROOT'] == "/usr/share/nginx/html/api") ? "/usr/share/nginx/html" : $_SERVER['DOCUMENT_ROOT']) . '/includes/connection.php'; // create connection with MySQL + if ($killOtherSessions) { + mysqli_query($link, "DELETE FROM `sessions` WHERE `id` != '$sessionid' AND `credential` = '$checkkey' AND `app` = '$secret'"); + misc\cache\purgePattern('KeyAuthState:' . $secret); + } + mysqli_query($link, "UPDATE `sessions` SET `validated` = 1,`credential` = '$checkkey' WHERE `id` = '$sessionid'"); + misc\cache\purge('KeyAuthState:' . $secret . ':' . $sessionid); die(api\v1_0\Encrypt(json_encode(array( "success" => true, - "message" => "$loggedInMsg", + "message" => "Logged in!", "info" => $resp )), $enckey)); } // if login didn't work, attempt to register - $resp = api\v1_0\register($checkkey, $checkkey, $checkkey, NULL, $hwid, $secret); + $resp = api\v1_0\register($checkkey, $checkkey, $checkkey, $hwid, $secret); switch ($resp) { case 'username_taken': die(api\v1_0\Encrypt(json_encode(array( @@ -563,7 +478,7 @@ case 'pw_leaked': die(api\v1_0\Encrypt(json_encode(array( "success" => false, - "message" => "$pwLeaked" + "message" => "This password has been leaked in a data breach (not from us), please use a different one." )), $enckey)); case 'key_already_used': die(api\v1_0\Encrypt(json_encode(array( @@ -572,8 +487,9 @@ )), $enckey)); case 'key_banned': if (strpos($keybanned, '{reason}') !== false) { - $query = misc\mysql\query("SELECT `banned` FROM `keys` WHERE `app` = ? AND `key` = ?", [$secret, $checkkey]); - $row = mysqli_fetch_array($query->result); + include_once (($_SERVER['DOCUMENT_ROOT'] == "/usr/share/nginx/html/panel" || $_SERVER['DOCUMENT_ROOT'] == "/usr/share/nginx/html/api") ? "/usr/share/nginx/html" : $_SERVER['DOCUMENT_ROOT']) . '/includes/connection.php'; // create connection with MySQL + $result = mysqli_query($link, "SELECT `banned` FROM `keys` WHERE `app` = '$secret' AND `key` = '$checkkey'"); + $row = mysqli_fetch_array($result); $reason = $row['banned']; $keybanned = str_replace("{reason}", $reason, $keybanned); } @@ -592,11 +508,16 @@ "message" => "$nosublevel" )), $enckey)); default: - misc\mysql\query("UPDATE `sessions` SET `validated` = 1,`credential` = ? WHERE `id` = ?", [$checkkey, $sessionid]); - misc\cache\update('KeyAuthState:'.$secret.':'.$sessionid.'', array("validated" => 1, "credential" => $checkkey)); + include_once (($_SERVER['DOCUMENT_ROOT'] == "/usr/share/nginx/html/panel" || $_SERVER['DOCUMENT_ROOT'] == "/usr/share/nginx/html/api") ? "/usr/share/nginx/html" : $_SERVER['DOCUMENT_ROOT']) . '/includes/connection.php'; // create connection with MySQL + if ($killOtherSessions) { + mysqli_query($link, "DELETE FROM `sessions` WHERE `id` != '$sessionid' AND `credential` = '$checkkey' AND `app` = '$secret'"); + misc\cache\purgePattern('KeyAuthState:' . $secret); + } + mysqli_query($link, "UPDATE `sessions` SET `validated` = 1,`credential` = '$checkkey' WHERE `id` = '$sessionid'"); + misc\cache\purge('KeyAuthState:' . $secret . ':' . $sessionid); die(api\v1_0\Encrypt(json_encode(array( "success" => true, - "message" => "$loggedInMsg", + "message" => "Logged in!", "info" => $resp )), $enckey)); } @@ -605,7 +526,7 @@ $session = api\shared\primary\getSession($sessionid, $secret); $enckey = $session["enckey"]; - $rows = misc\cache\fetch('KeyAuthOnlineUsers:' . $secret, "SELECT DISTINCT CONCAT(LEFT(`credential`, 10), IF(LENGTH(`credential`) > 10, REPEAT('*', LENGTH(`credential`) - 10), '')) AS `credential` FROM `sessions` WHERE `validated` = 1 AND `app` = ?", [$secret], 1, 1800); + $rows = misc\cache\fetch('KeyAuthOnlineUsers:' . $secret, "SELECT DISTINCT `credential` FROM `sessions` WHERE `validated` = 1 AND `app` = '$secret'", 1, 1800); if ($rows == "not_found") { die(api\v1_0\Encrypt(json_encode(array( @@ -633,42 +554,11 @@ $var = misc\etc\sanitize(api\v1_0\Decrypt($_POST['var'], $enckey)); $data = misc\etc\sanitize(api\v1_0\Decrypt($_POST['data'], $enckey)); - if(is_null($var)) { - die(api\v1_0\Encrypt(json_encode(array( - "success" => false, - "message" => "No variable name provided" - )), $enckey)); - } + include_once (($_SERVER['DOCUMENT_ROOT'] == "/usr/share/nginx/html/panel" || $_SERVER['DOCUMENT_ROOT'] == "/usr/share/nginx/html/api") ? "/usr/share/nginx/html" : $_SERVER['DOCUMENT_ROOT']) . '/includes/connection.php'; // create connection with MySQL - if(is_null($data)) { - die(api\v1_0\Encrypt(json_encode(array( - "success" => false, - "message" => "No variable data provided" - )), $enckey)); - } - - if(strlen($data) > 500) { - die(api\v1_0\Encrypt(json_encode(array( - "success" => false, - "message" => "Variable data must be 500 characters or less" - )), $enckey)); - } - - $row = misc\cache\fetch('KeyAuthUserVar:' . $secret . ':' . $var . ':' . $session["credential"], "SELECT `data`, `readOnly` FROM `uservars` WHERE `name` = ? AND `user` = ? AND `app` = ?", [$var, $session["credential"], $secret], 0); + mysqli_query($link, "REPLACE INTO `uservars` (`name`, `data`, `user`, `app`) VALUES ('$var', '$data', '" . $session["credential"] . "', '$secret')"); - if ($row != "not_found") { - $readOnly = $row["readOnly"]; - if ($readOnly) { - die(api\v1_0\Encrypt(json_encode(array( - "success" => false, - "message" => "Variable is read only" - )), $enckey)); - } - } - - $query = misc\mysql\query("REPLACE INTO `uservars` (`name`, `data`, `user`, `app`) VALUES (?, ?, ?, ?)", [$var, $data, $session["credential"], $secret]); - - if ($query->affected_rows != 0) { + if (mysqli_affected_rows($link) != 0) { misc\cache\purge('KeyAuthUserVar:' . $secret . ':' . $var . ':' . $session["credential"]); die(api\v1_0\Encrypt(json_encode(array( "success" => true, @@ -693,7 +583,7 @@ $var = misc\etc\sanitize(api\v1_0\Decrypt($_POST['var'], $enckey)); - $row = misc\cache\fetch('KeyAuthUserVar:' . $secret . ':' . $var . ':' . $session["credential"], "SELECT `data`, `readOnly` FROM `uservars` WHERE `name` = ? AND `user` = ? AND `app` = ?", [$var, $session["credential"], $secret], 0); + $row = misc\cache\fetch('KeyAuthUserVar:' . $secret . ':' . $var . ':' . $session["credential"], "SELECT `data` FROM `uservars` WHERE `name` = '$var' AND `user` = '" . $session["credential"] . "' AND `app` = '$secret'", 0); if ($row == "not_found") { die(api\v1_0\Encrypt(json_encode(array( @@ -715,7 +605,7 @@ $enckey = $session["enckey"]; $varid = misc\etc\sanitize(api\v1_0\Decrypt($_POST['varid'], $enckey)); - $row = misc\cache\fetch('KeyAuthVar:' . $secret . ':' . $varid, "SELECT `msg`, `authed` FROM `vars` WHERE `varid` = ? AND `app` = ?", [$varid, $secret], 0); + $row = misc\cache\fetch('KeyAuthVar:' . $secret . ':' . $varid, "SELECT `msg`, `authed` FROM `vars` WHERE `varid` = '$varid' AND `app` = '$secret'", 0); if ($row == "not_found") { die(api\v1_0\Encrypt(json_encode(array( "success" => false, @@ -748,7 +638,7 @@ $hwid = misc\etc\sanitize(api\v1_0\Decrypt($_POST['hwid'], $enckey)); $ip = api\shared\primary\getIp(); - $row = misc\cache\fetch('KeyAuthBlacklist:' . $secret . ':' . $ip . ':' . $hwid, "SELECT 1 FROM `bans` WHERE (`hwid` = ? OR `ip` = ?) AND `app` = ?", [$hwid, $ip, $secret], 0); + $row = misc\cache\fetch('KeyAuthBlacklist:' . $secret . ':' . $ip . ':' . $hwid, "SELECT 1 FROM `bans` WHERE (`hwid` = '$hwid' OR `ip` = '$ip') AND `app` = '$secret'", 0); if ($row != "not_found") { die(api\v1_0\Encrypt(json_encode(array( @@ -774,9 +664,9 @@ } $channel = misc\etc\sanitize(api\v1_0\Decrypt($_POST['channel'], $enckey)); - $rows = misc\cache\fetch('KeyAuthChatMsgs:' . $secret . ':' . $channel, "SELECT `author`, `message`, `timestamp` FROM `chatmsgs` WHERE `channel` = ? AND `app` = ?", [$channel, $secret], 1); + $rows = misc\cache\fetch('KeyAuthChatMsgs:' . $secret . ':' . $channel, "SELECT `author`, `message`, `timestamp` FROM `chatmsgs` WHERE `channel` = '$channel' AND `app` = '$secret'", 1); - if ($rows == "not_found") { + if ($rows == "not_found") { $rows = []; } @@ -796,35 +686,36 @@ "message" => "$sessionunauthed" )), $enckey)); } + include_once (($_SERVER['DOCUMENT_ROOT'] == "/usr/share/nginx/html/panel" || $_SERVER['DOCUMENT_ROOT'] == "/usr/share/nginx/html/api") ? "/usr/share/nginx/html" : $_SERVER['DOCUMENT_ROOT']) . '/includes/connection.php'; // create connection with MySQL $channel = misc\etc\sanitize(api\v1_0\Decrypt($_POST['channel'], $enckey)); - $query = misc\mysql\query("SELECT `delay` FROM `chats` WHERE `name` = ? AND `app` = ?", [$channel, $secret]); + $result = mysqli_query($link, "SELECT `delay` FROM `chats` WHERE `name` = '$channel' AND `app` = '$secret'"); - if ($query->num_rows < 1) { + if (mysqli_num_rows($result) < 1) { die(api\v1_0\Encrypt(json_encode(array( "success" => false, "message" => "Chat channel not found" )), $enckey)); } - $row = mysqli_fetch_array($query->result); + $row = mysqli_fetch_array($result); $delay = $row['delay']; $credential = $session["credential"]; - $query = misc\mysql\query("SELECT `timestamp` FROM `chatmsgs` WHERE `author` = ? AND `channel` = ? AND `app` = ? ORDER BY `id` DESC LIMIT 1", [$credential, $channel, $secret]); + $result = mysqli_query($link, "SELECT `timestamp` FROM `chatmsgs` WHERE `author` = '$credential' AND `channel` = '$channel' AND `app` = '$secret' ORDER BY `id` DESC LIMIT 1"); - $row = mysqli_fetch_array($query->result); + $row = mysqli_fetch_array($result); $time = $row['timestamp']; if (time() - $time < $delay) { die(api\v1_0\Encrypt(json_encode(array( "success" => false, - "message" => "$chatHitDelay" + "message" => "Chat slower, you've hit the delay limit" )), $enckey)); } - $query = misc\mysql\query("SELECT `time` FROM `chatmutes` WHERE `user` = ? AND `app` = ?", [$credential, $secret]); - if ($query->num_rows != 0) { - $row = mysqli_fetch_array($query->result); + $result = mysqli_query($link, "SELECT `time` FROM `chatmutes` WHERE `user` = '$credential' AND `app` = '$secret'"); + if (mysqli_num_rows($result) != 0) { + $row = mysqli_fetch_array($result); $unmuted = $row["time"]; $unmuted = date("F j, Y, g:i a", $unmuted); die(api\v1_0\Encrypt(json_encode(array( @@ -834,32 +725,14 @@ } $message = misc\etc\sanitize(api\v1_0\Decrypt($_POST['message'], $enckey)); - - if (is_null($message)) { - die(api\v1_0\Encrypt(json_encode(array( - "success" => false, - "message" => "Message can't be blank" - )), $enckey)); - } - - if(strlen($message) > 2000) { - die(api\v1_0\Encrypt(json_encode(array( - "success" => false, - "message" => "Message too long!" - )), $enckey)); - } - - misc\mysql\query("INSERT INTO `chatmsgs` (`author`, `message`, `timestamp`, `channel`,`app`) VALUES (?, ?, ?, ?, ?)", [$credential, $message, time(), $channel, $secret]); - misc\mysql\query("DELETE FROM `chatmsgs` WHERE `app` = ? AND `channel` = ? AND `id` NOT IN ( SELECT `id` FROM ( SELECT `id` FROM `chatmsgs` WHERE `channel` = ? AND `app` = ? ORDER BY `id` DESC LIMIT 50) foo );", [$secret, $channel, $channel, $secret]); + mysqli_query($link, "INSERT INTO `chatmsgs` (`author`, `message`, `timestamp`, `channel`,`app`) VALUES ('$credential','$message','" . time() . "','$channel','$secret')"); + mysqli_query($link, "DELETE FROM `chatmsgs` WHERE `app` = '$secret' AND `channel` = '$channel' AND `id` NOT IN ( SELECT `id` FROM ( SELECT `id` FROM `chatmsgs` WHERE `channel` = '$channel' AND `app` = '$secret' ORDER BY `id` DESC LIMIT 20) foo );"); misc\cache\purge('KeyAuthChatMsgs:' . $secret . ':' . $channel); die(api\v1_0\Encrypt(json_encode(array( "success" => true, "message" => "Successfully sent chat message" )), $enckey)); case 'log': - // client isn't expecting a response body, just flush output right away so program can move on to rest of the code quicker - fastcgi_finish_request(); - // retrieve session info $sessionid = misc\etc\sanitize(hex2bin($_POST['sessionid'])); $session = api\shared\primary\getSession($sessionid, $secret); @@ -871,28 +744,11 @@ $msg = misc\etc\sanitize(api\v1_0\Decrypt($_POST['message'], $enckey)); - if(is_null($msg)) { - die(); - } - - if(strlen($msg) > 275) { - die("Log data too long"); - } - $pcuser = misc\etc\sanitize(api\v1_0\Decrypt($_POST['pcuser'], $enckey)); if (is_null($webhook)) { - $roleCheck = misc\cache\fetch('KeyAuthSellerCheck:' . $owner, "SELECT `role`,`expires` FROM `accounts` WHERE `username` = ?", [$owner], 0); - if($roleCheck['role'] == "tester") { - $query = misc\mysql\query("SELECT count(*) AS 'numLogs' FROM `logs` WHERE `logapp` = ?",[$secret]); - $row = mysqli_fetch_array($query->result); - $numLogs = $row["numLogs"]; - if($numLogs >= 20) { - die(); - } - } - - misc\mysql\query("INSERT INTO `logs` (`logdate`, `logdata`, `credential`, `pcuser`,`logapp`) VALUES (?, ?, NULLIF(?, ''), NULLIF(?, ''), ?)", [$currtime, $msg, $credential, $pcuser, $secret]); + include_once (($_SERVER['DOCUMENT_ROOT'] == "/usr/share/nginx/html/panel" || $_SERVER['DOCUMENT_ROOT'] == "/usr/share/nginx/html/api") ? "/usr/share/nginx/html" : $_SERVER['DOCUMENT_ROOT']) . '/includes/connection.php'; // create connection with MySQL + mysqli_query($link, "INSERT INTO `logs` (`logdate`, `logdata`, `credential`, `pcuser`,`logapp`) VALUES ('$currtime','$msg',NULLIF('$credential', ''),NULLIF('$pcuser', ''),'$secret')"); die(); } @@ -903,6 +759,13 @@ $ip = api\shared\primary\getIp(); $json_data = json_encode([ + // Username + "username" => "KeyAuth", + + // Avatar URL. + // Uncoment to replace image set in webhook + "avatar_url" => "https://cdn.keyauth.cc/front/assets/img/favicon.png", + // Embeds Array "embeds" => [ [ @@ -947,8 +810,7 @@ $enckey = $session["enckey"]; $webid = misc\etc\sanitize(api\v1_0\Decrypt($_POST['webid'], $enckey)); - - $row = misc\cache\fetch('KeyAuthWebhook:' . $secret . ':' . $webid, "SELECT `baselink`, `useragent`, `authed` FROM `webhooks` WHERE `webid` = ? AND `app` = ?", [$webid, $secret], 0); + $row = misc\cache\fetch('KeyAuthWebhook:' . $secret . ':' . $webid, "SELECT `baselink`, `useragent`, `authed` FROM `webhooks` WHERE `webid` = '$webid' AND `app` = '$secret'", 0); if ($row == "not_found") { die(api\v1_0\Encrypt(json_encode(array( "success" => false, @@ -1005,7 +867,7 @@ $fileid = misc\etc\sanitize(api\v1_0\Decrypt($_POST['fileid'], $enckey)); - $row = misc\cache\fetch('KeyAuthFile:' . $secret . ':' . $fileid, "SELECT `name`, `url`, `authed` FROM `files` WHERE `app` = ? AND `id` = ?", [$secret, $fileid], 0); + $row = misc\cache\fetch('KeyAuthFile:' . $secret . ':' . $fileid, "SELECT `name`, `url`, `authed` FROM `files` WHERE `app` = '$secret' AND `id` = '$fileid'", 0); if ($row == "not_found") { die(api\v1_0\Encrypt(json_encode(array( @@ -1028,8 +890,8 @@ )), $enckey)); } } - - ini_set('memory_limit', '-1'); + + ini_set('memory_limit', '-1'); $ch = curl_init($url); curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true); @@ -1064,25 +926,17 @@ )), $enckey)); } - $reason = misc\etc\sanitize($_POST['reason']) ?? "User banned from triggering ban function in the client"; - - if(strlen($reason) > 99) { - die(api\v1_0\Encrypt(json_encode(array( - "success" => false, - "message" => "Reason must be 99 characters or less" - )), $enckey)); - } - + include_once (($_SERVER['DOCUMENT_ROOT'] == "/usr/share/nginx/html/panel" || $_SERVER['DOCUMENT_ROOT'] == "/usr/share/nginx/html/api") ? "/usr/share/nginx/html" : $_SERVER['DOCUMENT_ROOT']) . '/includes/connection.php'; // create connection with MySQL $hwid = misc\etc\sanitize(api\v1_0\Decrypt($_POST['hwid'], $enckey)); if (!empty($hwid)) { - misc\blacklist\add($hwid, "Hardware ID", $secret); + misc\blacklist\add($hwid, "Hardware ID", $secret); } $ip = api\shared\primary\getIp(); - misc\blacklist\add($ip, "IP Address", $secret); + misc\blacklist\add($ip, "IP Address", $secret); - misc\mysql\query("UPDATE `users` SET `banned` = ? WHERE `username` = ? AND `app` = ?", [$reason, $credential, $secret]); + mysqli_query($link, "UPDATE `users` SET `banned` = 'User banned from triggering ban function in the client' WHERE `username` = '$credential'"); - if ($query->affected_rows != 0) { + if (mysqli_affected_rows($link) != 0) { misc\cache\purge('KeyAuthUser:' . $secret . ':' . $credential); die(api\v1_0\Encrypt(json_encode(array( "success" => true, @@ -1112,48 +966,9 @@ "message" => "Session is validated." )), $enckey)); } - case 'changeUsername': - // retrieve session info - $sessionid = misc\etc\sanitize(hex2bin($_POST['sessionid'])); - $session = api\shared\primary\getSession($sessionid, $secret); - $enckey = $session["enckey"]; - - if (!$session["validated"]) { - die(api\v1_0\Encrypt(json_encode(array( - "success" => false, - "message" => "$sessionunauthed" - )), $enckey)); - } - - $credential = $session["credential"]; - - $resp = misc\user\changeUsername($credential, $_POST['newUsername'], $secret); - switch ($resp) { - case 'already_used': - die(api\v1_0\Encrypt(json_encode(array( - "success" => false, - "message" => "Username already used!" - )), $enckey)); - case 'failure': - die(api\v1_0\Encrypt(json_encode(array( - "success" => false, - "message" => "Failed to change username!" - )), $enckey)); - case 'success': - misc\session\killSingular($sessionid, $secret); - die(api\v1_0\Encrypt(json_encode(array( - "success" => true, - "message" => "Successfully changed username, user logged out." - )), $enckey)); - default: - die(api\v1_0\Encrypt(json_encode(array( - "success" => false, - "message" => "Unhandled Error! Contact us if you need help" - )), $enckey)); - } default: die(json_encode(array( "success" => false, "message" => "Unhandled Type" ))); -} +} \ No newline at end of file diff --git a/api/1.1/index.php b/api/1.1/index.php index 40dd0e91..4bb6cd54 100644 --- a/api/1.1/index.php +++ b/api/1.1/index.php @@ -1,38 +1,19 @@ getMessage()); - die(json_encode(array("success" => false, "message" => "Error: " . $errorMsg))); -}); - -if(empty(($_POST['ownerid'] ?? $_GET['ownerid']))) { - die(json_encode(array("success" => false, "message" => "No OwnerID specified. Select app & copy code snippet from https://keyauth.cc/app/"))); -} - -if(empty(($_POST['name'] ?? $_GET['name']))) { - die(json_encode(array("success" => false, "message" => "No app name specified. Select app & copy code snippet from https://keyauth.cc/app/"))); +if (isset($_SERVER['HTTP_CDN_HOST'])) { // custom domains https://www.youtube.com/watch?v=a2SROFJ0eYc + $row = misc\cache\fetch('KeyAuthApp:' . misc\etc\sanitize($_SERVER['HTTP_CDN_HOST']), "SELECT * FROM `apps` WHERE `customDomainAPI` = '" . misc\etc\sanitize($_SERVER['HTTP_CDN_HOST']) . "'", 0); +} else { + $ownerid = misc\etc\sanitize($_POST['ownerid'] ?? $_GET['ownerid']); // ownerid of account that owns application + $name = misc\etc\sanitize($_POST['name'] ?? $_GET['name']); // application name + $row = misc\cache\fetch('KeyAuthApp:' . $name . ':' . $ownerid, "SELECT * FROM `apps` WHERE `ownerid` = '$ownerid' AND `name` = '$name'", 0); } -if(strlen(($_POST['ownerid'] ?? $_GET['ownerid'])) != 10) { - die(json_encode(array("success" => false, "message" => "OwnerID should be 10 characters long. Select app & copy code snippet from https://keyauth.cc/app/"))); -} - -$ownerid = misc\etc\sanitize($_POST['ownerid'] ?? $_GET['ownerid']); // ownerid of account that owns application -$name = misc\etc\sanitize($_POST['name'] ?? $_GET['name']); // application name -$row = misc\cache\fetch('KeyAuthApp:' . $name . ':' . $ownerid, "SELECT * FROM `apps` WHERE `ownerid` = ? AND `name` = ?", [$ownerid, $name], 0); - if ($row == "not_found") { die("KeyAuth_Invalid"); } @@ -49,8 +30,6 @@ $appdisabled = $row['appdisabled']; $hashcheck = $row['hashcheck']; $serverhash = $row['hash']; -$sessionexpiry = $row['session']; -$forceHwid = $row['forceHwid']; $banned = $row['banned']; $owner = $row['owner']; @@ -67,24 +46,19 @@ $noactivesubs = $row['noactivesubs']; $hwidblacked = $row['hwidblacked']; $pausedsub = $row['pausedsub']; +$keyexpired = $row['keyexpired']; $vpnblocked = $row['vpnblocked']; $keybanned = $row['keybanned']; $userbanned = $row['userbanned']; $sessionunauthed = $row['sessionunauthed']; $hashcheckfail = $row['hashcheckfail']; - -// why using null coalescing operators? because if I add a field and it's not in redis cache, it'll be NULL -$loggedInMsg = $row['loggedInMsg'] ?? "Logged in!"; -$pausedApp = $row['pausedApp'] ?? "Application is currently paused, please wait for the developer to say otherwise."; -$unTooShort = $row['unTooShort'] ?? "Username too short, try longer one."; -$pwLeaked = $row['pwLeaked'] ?? "This password has been leaked in a data breach (not from us), please use a different one."; -$chatHitDelay = $row['chatHitDelay'] ?? "Chat slower, you've hit the delay limit"; -$minHwid = $row['minHwid'] ?? 20; +$sessionexpiry = $row['session']; +$killOtherSessions = $row['killOtherSessions']; if ($banned) { die(json_encode(array( "success" => false, - "message" => "This application has been banned from KeyAuth.cc for violating terms." // yes we self promote to customers of those who break ToS. Should've followed terms :shrug: + "message" => "This application has been banned from KeyAuth.com for violating terms." // yes we self promote to customers of those who break ToS. Should've followed terms :shrug: ))); } @@ -93,13 +67,10 @@ $ip = api\shared\primary\getIp(); if ($vpnblock) { if (api\shared\primary\vpnCheck($ip)) { - $row = misc\cache\fetch('KeyAuthWhitelist:' . $secret . ':' . $ip, "SELECT 1 FROM `whitelist` WHERE `ip` = ? AND `app` = ?", [$ip, $secret], 0); - if ($row == "not_found") { - die(json_encode(array( - "success" => false, - "message" => "$vpnblocked" - ))); - } + die(json_encode(array( + "success" => false, + "message" => "$vpnblocked" + ))); } } @@ -113,12 +84,12 @@ if ($paused) { die(json_encode(array( "success" => false, - "message" => "$pausedApp" + "message" => "Application is currently paused, please wait for the developer to say otherwise." ))); } $ver = misc\etc\sanitize($_POST['ver'] ?? $_GET['ver']); - if (!empty($ver)) { + if (is_numeric($ver)) { if ($ver != $currentver) { // auto-update system die(json_encode(array( @@ -134,7 +105,8 @@ if ($hashcheck) { if (strpos($serverhash, $hash) === false) { if (is_null($serverhash)) { - misc\mysql\query("UPDATE `apps` SET `hash` = ? WHERE `secret` = ?", [$hash, $secret]); + include_once (($_SERVER['DOCUMENT_ROOT'] == "/usr/share/nginx/html/panel" || $_SERVER['DOCUMENT_ROOT'] == "/usr/share/nginx/html/api") ? "/usr/share/nginx/html" : $_SERVER['DOCUMENT_ROOT']) . '/includes/connection.php'; // create connection with MySQL + mysqli_query($link, "UPDATE `apps` SET `hash` = '$hash' WHERE `secret` = '$secret'"); misc\cache\purge('KeyAuthApp:' . $name . ':' . $ownerid); // flush cache for application so new hash takes precedent } else { die(json_encode(array( @@ -145,84 +117,61 @@ } } - $newSession = false; - $duplicateSession = misc\cache\select("KeyAuthSessionDupe:$secret:$ip"); - if($duplicateSession) { - $sessionid = $duplicateSession; - $updateSession = misc\cache\update('KeyAuthState:'.$secret.':'.$sessionid.'', array("validated" => 0)); - if(!$updateSession) { - $sessionid = misc\etc\generateRandomString(); - $newSession = true; - } - } - else { - $sessionid = misc\etc\generateRandomString(); - $newSession = true; + $enckey = NULL; + + $row = misc\cache\fetch('KeyAuthStateDuplicates:' . $secret . ':' . $ip, "SELECT `id`, `expiry` FROM `sessions` WHERE `app` = '$secret' AND `ip` = '$ip' AND `validated` = 0 AND `expiry` > " . time() . " LIMIT 1", 0); + if ($row != "not_found") { + $sessionid = $row['id']; + goto dupe; } - - // $row = misc\cache\fetch('KeyAuthAppStats:' . $secret, "SELECT (SELECT COUNT(1) FROM `users` WHERE `app` = ?) AS 'numUsers', (SELECT COUNT(1) FROM `sessions` WHERE `app` = ? AND `validated` = 1 AND `expiry` > ?) AS 'numOnlineUsers', (SELECT COUNT(1) FROM `keys` WHERE `app` = ?) AS 'numKeys' FROM dual", [$secret, $secret, time(), $secret], 0, 3600); - $numUsers = "N/A - Use fetchStats() function in latest example"; - $numOnlineUsers = "N/A - Use fetchStats() function in latest example"; - $numKeys = "N/A - Use fetchStats() function in latest example"; + $sessionid = misc\etc\generateRandomString(); + // session init + $time = time() + $sessionexpiry; + include_once (($_SERVER['DOCUMENT_ROOT'] == "/usr/share/nginx/html/panel" || $_SERVER['DOCUMENT_ROOT'] == "/usr/share/nginx/html/api") ? "/usr/share/nginx/html" : $_SERVER['DOCUMENT_ROOT']) . '/includes/connection.php'; // create connection with MySQL + mysqli_query($link, "INSERT INTO `sessions` (`id`, `app`, `expiry`, `enckey`, `ip`) VALUES ('$sessionid','$secret', '$time', '$enckey', '$ip')"); + misc\cache\purge('KeyAuthStateDuplicates:' . $secret . ':' . $ip); + + dupe: + + $row = misc\cache\fetch('KeyAuthAppStats:' . $secret, "SELECT(select count(1) FROM `users` WHERE `app` = '$secret') AS 'numUsers',(select count(1) FROM `sessions` WHERE `app` = '$secret' AND `validated` = 1 AND `expiry` > " . time() . ") AS 'numOnlineUsers',(select count(1) FROM `keys` WHERE `app` = '$secret') AS 'numKeys';", 0, 1800); + + $numUsers = $row['numUsers']; + $numOnlineUsers = $row['numOnlineUsers']; + $numKeys = $row['numKeys']; - echo json_encode(array( + die(json_encode(array( "success" => true, "message" => "Initialized", "sessionid" => $sessionid, "appinfo" => array( - "numUsers" => "$numUsers", - "numOnlineUsers" => "$numOnlineUsers", - "numKeys" => "$numKeys", - "version" => "$currentver", + "numUsers" => $numUsers, + "numOnlineUsers" => $numOnlineUsers, + "numKeys" => $numKeys, + "version" => $currentver, "customerPanelLink" => "https://keyauth.cc/panel/$owner/$name/" ) - )); - - fastcgi_finish_request(); - - if($newSession) { - misc\cache\insert("KeyAuthState:$secret:$sessionid", serialize(array("credential" => NULL, "enckey" => NULL, "validated" => 0)), $sessionexpiry); - $time = time() + $sessionexpiry; - misc\mysql\query("INSERT INTO `sessions` (`id`, `app`, `expiry`, `created_at`, `ip`) VALUES (?, ?, ?, ?, ?)", [$sessionid, $secret, $time, time(), $ip]); - misc\cache\insert("KeyAuthSessionDupe:$secret:$ip", $sessionid, $sessionexpiry); - } + ))); case 'register': // retrieve session info $sessionid = misc\etc\sanitize($_POST['sessionid'] ?? $_GET['sessionid']); $session = api\shared\primary\getSession($sessionid, $secret); + $enckey = $session["enckey"]; // Read in username $username = misc\etc\sanitize($_POST['username'] ?? $_GET['username']); - if(strlen($username) > 70) { - die(json_encode(array( - "success" => false, - "message" => "Username must be shorter than 70 characters" - ))); - } - // Read in license key $checkkey = misc\etc\sanitize($_POST['key'] ?? $_GET['key']); - if(strlen($checkkey) > 70) { - die(json_encode(array( - "success" => false, - "message" => "Key must be shorter than 70 characters" - ))); - } - // Read in password $password = misc\etc\sanitize($_POST['pass'] ?? $_GET['pass']); - // Read in email - $email = misc\etc\sanitize($_POST['email'] ?? $_GET['email']); - // Read in hwid $hwid = misc\etc\sanitize($_POST['hwid'] ?? $_GET['hwid']); - $resp = api\v1_0\register($username, $checkkey, $password, $email, $hwid, $secret); + $resp = api\v1_0\register($username, $checkkey, $password, $hwid, $secret); switch ($resp) { case 'username_taken': die(json_encode(array( @@ -237,12 +186,12 @@ case 'un_too_short': die(json_encode(array( "success" => false, - "message" => "$unTooShort" + "message" => "Username too short, try longer one." ))); case 'pw_leaked': die(json_encode(array( "success" => false, - "message" => "$pwLeaked" + "message" => "This password has been leaked in a data breach (not from us), please use a different one." ))); case 'key_already_used': die(json_encode(array( @@ -251,8 +200,9 @@ ))); case 'key_banned': if (strpos($keybanned, '{reason}') !== false) { - $query = misc\mysql\query("SELECT `banned` FROM `keys` WHERE `app` = ? AND `key` = ?", [$secret, $checkkey]); - $row = mysqli_fetch_array($query->result); + include_once (($_SERVER['DOCUMENT_ROOT'] == "/usr/share/nginx/html/panel" || $_SERVER['DOCUMENT_ROOT'] == "/usr/share/nginx/html/api") ? "/usr/share/nginx/html" : $_SERVER['DOCUMENT_ROOT']) . '/includes/connection.php'; // create connection with MySQL + $result = mysqli_query($link, "SELECT `banned` FROM `keys` WHERE `app` = '$secret' AND `key` = '$checkkey'"); + $row = mysqli_fetch_array($result); $reason = $row['banned']; $keybanned = str_replace("{reason}", $reason, $keybanned); } @@ -271,13 +221,19 @@ "message" => "$nosublevel" ))); default: - misc\mysql\query("UPDATE `sessions` SET `credential` = ?,`validated` = 1 WHERE `id` = ?", [$username, $sessionid]); - misc\cache\update('KeyAuthState:'.$secret.':'.$sessionid.'', array("validated" => 1, "credential" => $username)); + include_once (($_SERVER['DOCUMENT_ROOT'] == "/usr/share/nginx/html/panel" || $_SERVER['DOCUMENT_ROOT'] == "/usr/share/nginx/html/api") ? "/usr/share/nginx/html" : $_SERVER['DOCUMENT_ROOT']) . '/includes/connection.php'; // create connection with MySQL + if ($killOtherSessions) { + mysqli_query($link, "DELETE FROM `sessions` WHERE `id` != '$sessionid' AND `credential` = '$username' AND `app` = '$secret'"); + misc\cache\purgePattern('KeyAuthState:' . $secret); + } + mysqli_query($link, "UPDATE `sessions` SET `credential` = '$username',`validated` = 1 WHERE `id` = '$sessionid'"); + misc\cache\purge('KeyAuthState:' . $secret . ':' . $sessionid); $ip = api\shared\primary\getIp(); + misc\cache\purge('KeyAuthStateDuplicates:' . $secret . ':' . $ip); die(json_encode(array( "success" => true, - "message" => "$loggedInMsg", + "message" => "Logged in!", "info" => $resp ))); } @@ -285,6 +241,7 @@ // retrieve session info $sessionid = misc\etc\sanitize($_POST['sessionid'] ?? $_GET['sessionid']); $session = api\shared\primary\getSession($sessionid, $secret); + $enckey = $session["enckey"]; // Read in username $username = misc\etc\sanitize($_POST['username'] ?? $_GET['username']); @@ -292,12 +249,13 @@ // Read in key $checkkey = misc\etc\sanitize($_POST['key'] ?? $_GET['key']); + include_once (($_SERVER['DOCUMENT_ROOT'] == "/usr/share/nginx/html/panel" || $_SERVER['DOCUMENT_ROOT'] == "/usr/share/nginx/html/api") ? "/usr/share/nginx/html" : $_SERVER['DOCUMENT_ROOT']) . '/includes/connection.php'; // create connection with MySQL // search for key - $query = misc\mysql\query("SELECT `banned`, `expires`, `status`, `level` FROM `keys` WHERE `key` = ? AND `app` = ?", [$checkkey, $secret]); + $result = mysqli_query($link, "SELECT `banned`, `expires`, `status`, `level` FROM `keys` WHERE `key` = '$checkkey' AND `app` = '$secret'"); // check if key exists - if ($query->num_rows < 1) { + if (mysqli_num_rows($result) < 1) { die(json_encode(array( "success" => false, "message" => "$keynotfound" @@ -305,10 +263,10 @@ } // if key does exist - elseif ($query->num_rows > 0) { + elseif (mysqli_num_rows($result) > 0) { // get key info - while ($row = mysqli_fetch_array($query->result)) { + while ($row = mysqli_fetch_array($result)) { $expires = $row['expires']; $status = $row['status']; $level = $row['level']; @@ -324,52 +282,54 @@ } if (!is_null($banned)) { - if (strpos($keybanned, '{reason}') !== false) { - $keybanned = str_replace("{reason}", $banned, $keybanned); - } die(json_encode(array( "success" => false, - "message" => "$keybanned" + "message" => "Key banned: {$banned}" ))); } // add current time to key time $expiry = $expires + time(); - $query = misc\mysql\query("SELECT `name` FROM `subscriptions` WHERE `app` = ? AND `level` = ?", [$secret, $level]); - $subName = mysqli_fetch_array($query->result)['name']; + $result = mysqli_query($link, "SELECT `name` FROM `subscriptions` WHERE `app` = '$secret' AND `level` = '$level'"); + $subName = mysqli_fetch_array($result)['name']; - $resp = misc\user\extend($username, $subName, $expiry, 0, $secret); + $resp = misc\user\extend($username, $subName, $expiry, $secret); switch ($resp) { case 'missing': die(json_encode(array( "success" => false, "message" => "$usernamenotfound" ))); + break; case 'sub_missing': die(json_encode(array( "success" => false, "message" => "$nosublevel" ))); + break; case 'failure': die(json_encode(array( "success" => false, "message" => "Failed to upgrade for some reason." ))); + break; case 'success': // set key to used, and set usedby - misc\mysql\query("UPDATE `keys` SET `status` = 'Used', `usedon` = ?, `usedby` = ? WHERE `key` = ? AND `app` = ?", [time(), $username, $checkkey, $secret]); + mysqli_query($link, "UPDATE `keys` SET `status` = 'Used', `usedon` = '" . time() . "', `usedby` = '$username' WHERE `key` = '$checkkey'"); misc\cache\purge('KeyAuthKeys:' . $secret . ':' . $checkkey); - misc\cache\purge('KeyAuthSubs:' . $secret . ':' . $username); + misc\cache\purge('KeyAuthSubs:' . $secret . ':' . $username); die(json_encode(array( "success" => true, "message" => "Upgraded successfully" ))); + break; default: die(json_encode(array( "success" => false, "message" => "Unhandled Error! Contact us if you need help" ))); + break; } } @@ -377,6 +337,7 @@ // retrieve session info $sessionid = misc\etc\sanitize($_POST['sessionid'] ?? $_GET['sessionid']); $session = api\shared\primary\getSession($sessionid, $secret); + $enckey = $session["enckey"]; // Read in username $username = misc\etc\sanitize($_POST['username'] ?? $_GET['username']); @@ -389,21 +350,7 @@ // optional param for web loader $token = misc\etc\sanitize($_POST['token'] ?? $_GET['token']); - - if(strlen($hwid) < $minHwid && !is_null($hwid)) { - die(json_encode(array( - "success" => false, - "message" => "HWID must be {$minHwid} or more characters, change this in app settings." - ))); - } - - if($forceHwid && is_null($hwid)) { - die(json_encode(array( - "success" => false, - "message" => "Force HWID is enabled, disable in app settings if you want to use blank HWIDs" - ))); - } - + $resp = api\v1_0\login($username, $password, $hwid, $secret, $hwidenabled, $token); switch ($resp) { case 'un_not_found': @@ -418,8 +365,9 @@ ))); case 'user_banned': if (strpos($userbanned, '{reason}') !== false) { - $query = misc\mysql\query("SELECT `banned` FROM `users` WHERE `app` = ? AND `username` = ?", [$secret, $username]); - $row = mysqli_fetch_array($query->result); + include_once (($_SERVER['DOCUMENT_ROOT'] == "/usr/share/nginx/html/panel" || $_SERVER['DOCUMENT_ROOT'] == "/usr/share/nginx/html/api") ? "/usr/share/nginx/html" : $_SERVER['DOCUMENT_ROOT']) . '/includes/connection.php'; // create connection with MySQL + $result = mysqli_query($link, "SELECT `banned` FROM `users` WHERE `app` = '$secret' AND `username` = '$username'"); + $row = mysqli_fetch_array($result); $reason = $row['banned']; $userbanned = str_replace("{reason}", $reason, $userbanned); } @@ -448,13 +396,19 @@ "message" => "$noactivesubs" ))); default: - misc\mysql\query("UPDATE `sessions` SET `validated` = 1,`credential` = ? WHERE `id` = ?", [$username, $sessionid]); - misc\cache\update('KeyAuthState:'.$secret.':'.$sessionid.'', array("validated" => 1, "credential" => $username)); + include_once (($_SERVER['DOCUMENT_ROOT'] == "/usr/share/nginx/html/panel" || $_SERVER['DOCUMENT_ROOT'] == "/usr/share/nginx/html/api") ? "/usr/share/nginx/html" : $_SERVER['DOCUMENT_ROOT']) . '/includes/connection.php'; // create connection with MySQL + if ($killOtherSessions) { + mysqli_query($link, "DELETE FROM `sessions` WHERE `id` != '$sessionid' AND `credential` = '$username' AND `app` = '$secret'"); + misc\cache\purgePattern('KeyAuthState:' . $secret); + } + mysqli_query($link, "UPDATE `sessions` SET `validated` = 1,`credential` = '$username' WHERE `id` = '$sessionid'"); + misc\cache\purge('KeyAuthState:' . $secret . ':' . $sessionid); $ip = api\shared\primary\getIp(); + misc\cache\purge('KeyAuthStateDuplicates:' . $secret . ':' . $ip); die(json_encode(array( "success" => true, - "message" => "$loggedInMsg", + "message" => "Logged in!", "info" => $resp ))); } @@ -463,35 +417,16 @@ // retrieve session info $sessionid = misc\etc\sanitize($_POST['sessionid'] ?? $_GET['sessionid']); $session = api\shared\primary\getSession($sessionid, $secret); + $enckey = $session["enckey"]; $checkkey = misc\etc\sanitize($_POST['key'] ?? $_GET['key']); - if(strlen($checkkey) > 70) { - die(json_encode(array( - "success" => false, - "message" => "Key must be shorter than 70 characters" - ))); - } - $hwid = misc\etc\sanitize($_POST['hwid'] ?? $_GET['hwid']); - if(strlen($hwid) < $minHwid && !is_null($hwid)) { - die(json_encode(array( - "success" => false, - "message" => "HWID must be {$minHwid} or more characters, change this in app settings." - ))); - } - - if($forceHwid && is_null($hwid)) { - die(json_encode(array( - "success" => false, - "message" => "Force HWID is enabled, disable in app settings if you want to use blank HWIDs" - ))); - } - $resp = api\v1_0\login($checkkey, $checkkey, $hwid, $secret, $hwidenabled); switch ($resp) { case 'un_not_found': break; // user not registered yet or user was deleted + case 'hwid_mismatch': die(json_encode(array( "success" => false, @@ -499,8 +434,9 @@ ))); case 'user_banned': if (strpos($userbanned, '{reason}') !== false) { - $query = misc\mysql\query("SELECT `banned` FROM `users` WHERE `app` = ? AND `username` = ?", [$secret, $checkkey]); - $row = mysqli_fetch_array($query->result); + include_once (($_SERVER['DOCUMENT_ROOT'] == "/usr/share/nginx/html/panel" || $_SERVER['DOCUMENT_ROOT'] == "/usr/share/nginx/html/api") ? "/usr/share/nginx/html" : $_SERVER['DOCUMENT_ROOT']) . '/includes/connection.php'; // create connection with MySQL + $result = mysqli_query($link, "SELECT `banned` FROM `users` WHERE `app` = '$secret' AND `username` = '$checkkey'"); + $row = mysqli_fetch_array($result); $reason = $row['banned']; $userbanned = str_replace("{reason}", $reason, $userbanned); } @@ -529,19 +465,25 @@ "message" => "$noactivesubs" ))); default: - misc\mysql\query("UPDATE `sessions` SET `validated` = 1,`credential` = ? WHERE `id` = ?", [$checkkey, $sessionid]); - misc\cache\update('KeyAuthState:'.$secret.':'.$sessionid.'', array("validated" => 1, "credential" => $checkkey)); + include_once (($_SERVER['DOCUMENT_ROOT'] == "/usr/share/nginx/html/panel" || $_SERVER['DOCUMENT_ROOT'] == "/usr/share/nginx/html/api") ? "/usr/share/nginx/html" : $_SERVER['DOCUMENT_ROOT']) . '/includes/connection.php'; // create connection with MySQL + if ($killOtherSessions) { + mysqli_query($link, "DELETE FROM `sessions` WHERE `id` != '$sessionid' AND `credential` = '$checkkey' AND `app` = '$secret'"); + misc\cache\purgePattern('KeyAuthState:' . $secret); + } + mysqli_query($link, "UPDATE `sessions` SET `validated` = 1,`credential` = '$checkkey' WHERE `id` = '$sessionid'"); + misc\cache\purge('KeyAuthState:' . $secret . ':' . $sessionid); $ip = api\shared\primary\getIp(); + misc\cache\purge('KeyAuthStateDuplicates:' . $secret . ':' . $ip); die(json_encode(array( "success" => true, - "message" => "$loggedInMsg", + "message" => "Logged in!", "info" => $resp ))); } // if login didn't work, attempt to register - $resp = api\v1_0\register($checkkey, $checkkey, $checkkey, NULL, $hwid, $secret); + $resp = api\v1_0\register($checkkey, $checkkey, $checkkey, $hwid, $secret); switch ($resp) { case 'username_taken': die(json_encode(array( @@ -556,12 +498,12 @@ case 'un_too_short': die(json_encode(array( "success" => false, - "message" => "$unTooShort" + "message" => "Username too short, try longer one." ))); case 'pw_leaked': die(json_encode(array( "success" => false, - "message" => "$pwLeaked" + "message" => "This password has been leaked in a data breach (not from us), please use a different one." ))); case 'key_already_used': die(json_encode(array( @@ -570,8 +512,9 @@ ))); case 'key_banned': if (strpos($keybanned, '{reason}') !== false) { - $query = misc\mysql\query("SELECT `banned` FROM `keys` WHERE `app` = ? AND `key` = ?", [$secret, $checkkey]); - $row = mysqli_fetch_array($query->result); + include_once (($_SERVER['DOCUMENT_ROOT'] == "/usr/share/nginx/html/panel" || $_SERVER['DOCUMENT_ROOT'] == "/usr/share/nginx/html/api") ? "/usr/share/nginx/html" : $_SERVER['DOCUMENT_ROOT']) . '/includes/connection.php'; // create connection with MySQL + $result = mysqli_query($link, "SELECT `banned` FROM `keys` WHERE `app` = '$secret' AND `key` = '$checkkey'"); + $row = mysqli_fetch_array($result); $reason = $row['banned']; $keybanned = str_replace("{reason}", $reason, $keybanned); } @@ -590,13 +533,19 @@ "message" => "$nosublevel" ))); default: - misc\mysql\query("UPDATE `sessions` SET `validated` = 1,`credential` = ? WHERE `id` = ?", [$checkkey, $sessionid]); - misc\cache\update('KeyAuthState:'.$secret.':'.$sessionid.'', array("validated" => 1, "credential" => $checkkey)); + include_once (($_SERVER['DOCUMENT_ROOT'] == "/usr/share/nginx/html/panel" || $_SERVER['DOCUMENT_ROOT'] == "/usr/share/nginx/html/api") ? "/usr/share/nginx/html" : $_SERVER['DOCUMENT_ROOT']) . '/includes/connection.php'; // create connection with MySQL + if ($killOtherSessions) { + mysqli_query($link, "DELETE FROM `sessions` WHERE `id` != '$sessionid' AND `credential` = '$checkkey' AND `app` = '$secret'"); + misc\cache\purgePattern('KeyAuthState:' . $secret); + } + mysqli_query($link, "UPDATE `sessions` SET `validated` = 1,`credential` = '$checkkey' WHERE `id` = '$sessionid'"); + misc\cache\purge('KeyAuthState:' . $secret . ':' . $sessionid); $ip = api\shared\primary\getIp(); + misc\cache\purge('KeyAuthStateDuplicates:' . $secret . ':' . $ip); die(json_encode(array( "success" => true, - "message" => "$loggedInMsg", + "message" => "Logged in!", "info" => $resp ))); } @@ -604,7 +553,7 @@ $sessionid = misc\etc\sanitize($_POST['sessionid'] ?? $_GET['sessionid']); $session = api\shared\primary\getSession($sessionid, $secret); - $rows = misc\cache\fetch('KeyAuthOnlineUsers:' . $secret, "SELECT DISTINCT CONCAT(LEFT(`credential`, 10), IF(LENGTH(`credential`) > 10, REPEAT('*', LENGTH(`credential`) - 10), '')) AS `credential` FROM `sessions` WHERE `validated` = 1 AND `app` = ?", [$secret], 1, 1800); + $rows = misc\cache\fetch('KeyAuthOnlineUsers:' . $secret, "SELECT DISTINCT `credential` FROM `sessions` WHERE `validated` = 1 AND `app` = '$secret'", 1, 1800); if ($rows == "not_found") { die(json_encode(array( @@ -621,6 +570,7 @@ case 'setvar': $sessionid = misc\etc\sanitize($_POST['sessionid'] ?? $_GET['sessionid']); $session = api\shared\primary\getSession($sessionid, $secret); + $enckey = $session["enckey"]; if (!$session["validated"]) { die(json_encode(array( "success" => false, @@ -630,43 +580,10 @@ $var = misc\etc\sanitize($_POST['var'] ?? $_GET['var']); $data = misc\etc\sanitize($_POST['data'] ?? $_GET['data']); + include_once (($_SERVER['DOCUMENT_ROOT'] == "/usr/share/nginx/html/panel" || $_SERVER['DOCUMENT_ROOT'] == "/usr/share/nginx/html/api") ? "/usr/share/nginx/html" : $_SERVER['DOCUMENT_ROOT']) . '/includes/connection.php'; // create connection with MySQL + mysqli_query($link, "REPLACE INTO `uservars` (`name`, `data`, `user`, `app`) VALUES ('$var', '$data', '" . $session["credential"] . "', '$secret')"); - if(is_null($var)) { - die(json_encode(array( - "success" => true, - "message" => "No variable name provided" - ))); - } - - if(is_null($data)) { - die(json_encode(array( - "success" => true, - "message" => "No variable data provided" - ))); - } - - if(strlen($data) > 500) { - die(json_encode(array( - "success" => true, - "message" => "Variable data must be 500 characters or less" - ))); - } - - $row = misc\cache\fetch('KeyAuthUserVar:' . $secret . ':' . $var . ':' . $session["credential"], "SELECT `data`, `readOnly` FROM `uservars` WHERE `name` = ? AND `user` = ? AND `app` = ?", [$var, $session["credential"], $secret], 0); - - if ($row != "not_found") { - $readOnly = $row["readOnly"]; - if ($readOnly) { - die(json_encode(array( - "success" => true, - "message" => "Variable is read only" - ))); - } - } - - $query = misc\mysql\query("REPLACE INTO `uservars` (`name`, `data`, `user`, `app`) VALUES (?, ?, ?, ?)", [$var, $data, $session["credential"], $secret]); - - if ($query->affected_rows != 0) { + if (mysqli_affected_rows($link) != 0) { misc\cache\purge('KeyAuthUserVar:' . $secret . ':' . $var . ':' . $session["credential"]); die(json_encode(array( "success" => true, @@ -681,6 +598,7 @@ case 'getvar': $sessionid = misc\etc\sanitize($_POST['sessionid'] ?? $_GET['sessionid']); $session = api\shared\primary\getSession($sessionid, $secret); + $enckey = $session["enckey"]; if (!$session["validated"]) { die(json_encode(array( "success" => false, @@ -690,7 +608,7 @@ $var = misc\etc\sanitize($_POST['var'] ?? $_GET['var']); - $row = misc\cache\fetch('KeyAuthUserVar:' . $secret . ':' . $var . ':' . $session["credential"], "SELECT `data`, `readOnly` FROM `uservars` WHERE `name` = ? AND `user` = ? AND `app` = ?", [$var, $session["credential"], $secret], 0); + $row = misc\cache\fetch('KeyAuthUserVar:' . $secret . ':' . $var . ':' . $session["credential"], "SELECT `data` FROM `uservars` WHERE `name` = '$var' AND `user` = '" . $session["credential"] . "' AND `app` = '$secret'", 0); if ($row == "not_found") { die(json_encode(array( @@ -709,10 +627,11 @@ // retrieve session info $sessionid = misc\etc\sanitize($_POST['sessionid'] ?? $_GET['sessionid']); $session = api\shared\primary\getSession($sessionid, $secret); + $enckey = $session["enckey"]; $varid = misc\etc\sanitize($_POST['varid'] ?? $_GET['varid']); - $row = misc\cache\fetch('KeyAuthVar:' . $secret . ':' . $varid, "SELECT `msg`, `authed` FROM `vars` WHERE `varid` = ? AND `app` = ?", [$varid, $secret], 0); + $row = misc\cache\fetch('KeyAuthVar:' . $secret . ':' . $varid, "SELECT `msg`, `authed` FROM `vars` WHERE `varid` = '$varid' AND `app` = '$secret'", 0); if ($row == "not_found") { die(json_encode(array( @@ -742,11 +661,12 @@ // retrieve session info $sessionid = misc\etc\sanitize($_POST['sessionid'] ?? $_GET['sessionid']); $session = api\shared\primary\getSession($sessionid, $secret); + $enckey = $session["enckey"]; $hwid = misc\etc\sanitize($_POST['hwid'] ?? $_GET['hwid']); $ip = api\shared\primary\getIp(); - $row = misc\cache\fetch('KeyAuthBlacklist:' . $secret . ':' . $ip . ':' . $hwid, "SELECT 1 FROM `bans` WHERE (`hwid` = ? OR `ip` = ?) AND `app` = ?", [$hwid, $ip, $secret], 0); + $row = misc\cache\fetch('KeyAuthBlacklist:' . $secret . ':' . $ip . ':' . $hwid, "SELECT 1 FROM `bans` WHERE (`hwid` = '$hwid' OR `ip` = '$ip') AND `app` = '$secret'", 0); if ($row != "not_found") { die(json_encode(array( @@ -763,6 +683,7 @@ // retrieve session info $sessionid = misc\etc\sanitize($_POST['sessionid'] ?? $_GET['sessionid']); $session = api\shared\primary\getSession($sessionid, $secret); + $enckey = $session["enckey"]; if (!$session["validated"]) { die(json_encode(array( "success" => false, @@ -771,9 +692,9 @@ } $channel = misc\etc\sanitize($_POST['channel'] ?? $_GET['channel']); - $rows = misc\cache\fetch('KeyAuthChatMsgs:' . $secret . ':' . $channel, "SELECT `author`, `message`, `timestamp` FROM `chatmsgs` WHERE `channel` = ? AND `app` = ?", [$channel, $secret], 1); + $rows = misc\cache\fetch('KeyAuthChatMsgs:' . $secret . ':' . $channel, "SELECT `author`, `message`, `timestamp` FROM `chatmsgs` WHERE `channel` = '$channel' AND `app` = '$secret'", 1); - if ($rows == "not_found") { + if ($rows == "not_found") { $rows = []; } @@ -786,6 +707,7 @@ // retrieve session info $sessionid = misc\etc\sanitize($_POST['sessionid'] ?? $_GET['sessionid']); $session = api\shared\primary\getSession($sessionid, $secret); + $enckey = $session["enckey"]; if (!$session["validated"]) { die(json_encode(array( "success" => false, @@ -794,33 +716,34 @@ } $channel = misc\etc\sanitize($_POST['channel'] ?? $_GET['channel']); - $query = misc\mysql\query("SELECT `delay` FROM `chats` WHERE `name` = ? AND `app` = ?", [$channel, $secret]); + include_once (($_SERVER['DOCUMENT_ROOT'] == "/usr/share/nginx/html/panel" || $_SERVER['DOCUMENT_ROOT'] == "/usr/share/nginx/html/api") ? "/usr/share/nginx/html" : $_SERVER['DOCUMENT_ROOT']) . '/includes/connection.php'; // create connection with MySQL + $result = mysqli_query($link, "SELECT `delay` FROM `chats` WHERE `name` = '$channel' AND `app` = '$secret'"); - if ($query->num_rows < 1) { + if (mysqli_num_rows($result) < 1) { die(json_encode(array( "success" => false, "message" => "Chat channel not found" ))); } - $row = mysqli_fetch_array($query->result); + $row = mysqli_fetch_array($result); $delay = $row['delay']; $credential = $session["credential"]; - $query = misc\mysql\query("SELECT `timestamp` FROM `chatmsgs` WHERE `author` = ? AND `channel` = ? AND `app` = ? ORDER BY `id` DESC LIMIT 1", [$credential, $channel, $secret]); + $result = mysqli_query($link, "SELECT `timestamp` FROM `chatmsgs` WHERE `author` = '$credential' AND `channel` = '$channel' AND `app` = '$secret' ORDER BY `id` DESC LIMIT 1"); - $row = mysqli_fetch_array($query->result); + $row = mysqli_fetch_array($result); $time = $row['timestamp']; if (time() - $time < $delay) { die(json_encode(array( "success" => false, - "message" => "$chatHitDelay" + "message" => "Chat slower, you've hit the delay limit" ))); } - $query = misc\mysql\query("SELECT `time` FROM `chatmutes` WHERE `user` = ? AND `app` = ?", [$credential, $secret]); - if ($query->num_rows != 0) { - $row = mysqli_fetch_array($query->result); + $result = mysqli_query($link, "SELECT `time` FROM `chatmutes` WHERE `user` = '$credential' AND `app` = '$secret'"); + if (mysqli_num_rows($result) != 0) { + $row = mysqli_fetch_array($result); $unmuted = $row["time"]; $unmuted = date("F j, Y, g:i a", $unmuted); die(json_encode(array( @@ -830,35 +753,18 @@ } $message = misc\etc\sanitize($_POST['message'] ?? $_GET['message']); - - if (is_null($message)) { - die(json_encode(array( - "success" => false, - "message" => "Message can't be blank" - ))); - } - - if(strlen($message) > 2000) { - die(json_encode(array( - "success" => false, - "message" => "Message too long!" - ))); - } - - misc\mysql\query("INSERT INTO `chatmsgs` (`author`, `message`, `timestamp`, `channel`,`app`) VALUES (?, ?, ?, ?, ?)", [$credential, $message, time(), $channel, $secret]); - misc\mysql\query("DELETE FROM `chatmsgs` WHERE `app` = ? AND `channel` = ? AND `id` NOT IN ( SELECT `id` FROM ( SELECT `id` FROM `chatmsgs` WHERE `channel` = ? AND `app` = ? ORDER BY `id` DESC LIMIT 50) foo );", [$secret, $channel, $channel, $secret]); + mysqli_query($link, "INSERT INTO `chatmsgs` (`author`, `message`, `timestamp`, `channel`,`app`) VALUES ('$credential','$message','" . time() . "','$channel','$secret')"); + mysqli_query($link, "DELETE FROM `chatmsgs` WHERE `app` = '$secret' AND `channel` = '$channel' AND `id` NOT IN ( SELECT `id` FROM ( SELECT `id` FROM `chatmsgs` WHERE `channel` = '$channel' AND `app` = '$secret' ORDER BY `id` DESC LIMIT 20) foo );"); misc\cache\purge('KeyAuthChatMsgs:' . $secret . ':' . $channel); die(json_encode(array( "success" => true, "message" => "Successfully sent chat message" ))); case 'log': - // client isn't expecting a response body, just flush output right away so program can move on to rest of the code quicker - fastcgi_finish_request(); - // retrieve session info $sessionid = misc\etc\sanitize($_POST['sessionid'] ?? $_GET['sessionid']); $session = api\shared\primary\getSession($sessionid, $secret); + $enckey = $session["enckey"]; $credential = $session["credential"]; @@ -866,28 +772,11 @@ $msg = misc\etc\sanitize($_POST['message'] ?? $_GET['message']); - if(is_null($msg)) { - die(); - } - - if(strlen($msg) > 275) { - die("Log data too long"); - } - $pcuser = misc\etc\sanitize($_POST['pcuser'] ?? $_GET['pcuser']); if (is_null($webhook)) { - $roleCheck = misc\cache\fetch('KeyAuthSellerCheck:' . $owner, "SELECT `role`,`expires` FROM `accounts` WHERE `username` = ?", [$owner], 0); - if($roleCheck['role'] == "tester") { - $query = misc\mysql\query("SELECT count(*) AS 'numLogs' FROM `logs` WHERE `logapp` = ?",[$secret]); - $row = mysqli_fetch_array($query->result); - $numLogs = $row["numLogs"]; - if($numLogs >= 20) { - die(); - } - } - - misc\mysql\query("INSERT INTO `logs` (`logdate`, `logdata`, `credential`, `pcuser`,`logapp`) VALUES (?, ?, NULLIF(?, ''), NULLIF(?, ''), ?)", [$currtime, $msg, $credential, $pcuser, $secret]); + include_once (($_SERVER['DOCUMENT_ROOT'] == "/usr/share/nginx/html/panel" || $_SERVER['DOCUMENT_ROOT'] == "/usr/share/nginx/html/api") ? "/usr/share/nginx/html" : $_SERVER['DOCUMENT_ROOT']) . '/includes/connection.php'; // create connection with MySQL + mysqli_query($link, "INSERT INTO `logs` (`logdate`, `logdata`, `credential`, `pcuser`,`logapp`) VALUES ('$currtime','$msg',NULLIF('$credential', ''),NULLIF('$pcuser', ''),'$secret')"); die(); } @@ -898,6 +787,13 @@ $ip = api\shared\primary\getIp(); $json_data = json_encode([ + // Username + "username" => "KeyAuth", + + // Avatar URL. + // Uncoment to replace image set in webhook + "avatar_url" => "https://cdn.keyauth.cc/front/assets/img/favicon.png", + // Embeds Array "embeds" => [ [ @@ -941,9 +837,10 @@ // retrieve session info $sessionid = misc\etc\sanitize($_POST['sessionid'] ?? $_GET['sessionid']); $session = api\shared\primary\getSession($sessionid, $secret); + $enckey = $session["enckey"]; $webid = misc\etc\sanitize($_POST['webid'] ?? $_GET['webid']); - $row = misc\cache\fetch('KeyAuthWebhook:' . $secret . ':' . $webid, "SELECT `baselink`, `useragent`, `authed` FROM `webhooks` WHERE `webid` = ? AND `app` = ?", [$webid, $secret], 0); + $row = misc\cache\fetch('KeyAuthWebhook:' . $secret . ':' . $webid, "SELECT `baselink`, `useragent`, `authed` FROM `webhooks` WHERE `webid` = '$webid' AND `app` = '$secret'", 0); if ($row == "not_found") { die(json_encode(array( "success" => false, @@ -995,10 +892,11 @@ // retrieve session info $sessionid = misc\etc\sanitize($_POST['sessionid'] ?? $_GET['sessionid']); $session = api\shared\primary\getSession($sessionid, $secret); + $enckey = $session["enckey"]; $fileid = misc\etc\sanitize($_POST['fileid'] ?? $_GET['fileid']); - $row = misc\cache\fetch('KeyAuthFile:' . $secret . ':' . $fileid, "SELECT `name`, `url`, `authed` FROM `files` WHERE `app` = ? AND `id` = ?", [$secret, $fileid], 0); + $row = misc\cache\fetch('KeyAuthFile:' . $secret . ':' . $fileid, "SELECT `name`, `url`, `authed` FROM `files` WHERE `app` = '$secret' AND `id` = '$fileid'", 0); if ($row == "not_found") { die(json_encode(array( @@ -1021,8 +919,8 @@ ))); } } - - ini_set('memory_limit', '-1'); + + ini_set('memory_limit', '-1'); $ch = curl_init($url); curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true); @@ -1048,6 +946,7 @@ // retrieve session info $sessionid = misc\etc\sanitize($_POST['sessionid'] ?? $_GET['sessionid']); $session = api\shared\primary\getSession($sessionid, $secret); + $enckey = $session["enckey"]; $credential = $session["credential"]; if (!$session["validated"]) { @@ -1057,24 +956,16 @@ ))); } - $reason = misc\etc\sanitize($_POST['reason'] ?? $_GET['reason']) ?? "User banned from triggering ban function in the client"; - - if(strlen($reason) > 99) { - die(json_encode(array( - "success" => false, - "message" => "Reason must be 99 characters or less" - ))); - } - + include_once (($_SERVER['DOCUMENT_ROOT'] == "/usr/share/nginx/html/panel" || $_SERVER['DOCUMENT_ROOT'] == "/usr/share/nginx/html/api") ? "/usr/share/nginx/html" : $_SERVER['DOCUMENT_ROOT']) . '/includes/connection.php'; // create connection with MySQL $hwid = misc\etc\sanitize($_POST['hwid'] ?? $_GET['hwid']); if (!empty($hwid)) { misc\blacklist\add($hwid, "Hardware ID", $secret); } $ip = api\shared\primary\getIp(); - misc\blacklist\add($ip, "IP Address", $secret); + misc\blacklist\add($ip, "IP Address", $secret); - misc\mysql\query("UPDATE `users` SET `banned` = ? WHERE `username` = ? AND `app` = ?", [$reason, $credential, $secret]); - if ($query->affected_rows != 0) { + mysqli_query($link, "UPDATE `users` SET `banned` = 'User banned from triggering ban function in the client' WHERE `username` = '$credential'"); + if (mysqli_affected_rows($link) != 0) { misc\cache\purge('KeyAuthUser:' . $secret . ':' . $credential); die(json_encode(array( "success" => true, @@ -1090,6 +981,7 @@ // retrieve session info $sessionid = misc\etc\sanitize($_POST['sessionid'] ?? $_GET['sessionid']); $session = api\shared\primary\getSession($sessionid, $secret); + $enckey = $session["enckey"]; $credential = $session["credential"]; if (!$session["validated"]) { @@ -1103,43 +995,6 @@ "message" => "Session is validated." ))); } - case 'changeUsername': - $sessionid = misc\etc\sanitize($_POST['sessionid'] ?? $_GET['sessionid']); - $session = api\shared\primary\getSession($sessionid, $secret); - - if (!$session["validated"]) { - die(json_encode(array( - "success" => false, - "message" => "$sessionunauthed" - ))); - } - - $credential = $session["credential"]; - - $resp = misc\user\changeUsername($credential, $_POST['newUsername'] ?? $_GET['newUsername'], $secret); - switch ($resp) { - case 'already_used': - die(json_encode(array( - "success" => false, - "message" => "Username already used!" - ))); - case 'failure': - die(json_encode(array( - "success" => false, - "message" => "Failed to change username!" - ))); - case 'success': - misc\session\killSingular($sessionid, $secret); - die(json_encode(array( - "success" => true, - "message" => "Successfully changed username, user logged out." - ))); - default: - die(json_encode(array( - "success" => false, - "message" => "Unhandled Error! Contact us if you need help" - ))); - } default: die(json_encode(array( "success" => false, diff --git a/api/1.2/index.php b/api/1.2/index.php index 7c701e57..3a2a023f 100644 --- a/api/1.2/index.php +++ b/api/1.2/index.php @@ -1,42 +1,19 @@ getMessage()); - die(json_encode(array("success" => false, "message" => "Error: " . $errorMsg))); -}); - -if(empty(($_POST['ownerid'] ?? $_GET['ownerid']))) { - die(json_encode(array("success" => false, "message" => "No OwnerID specified. Select app & copy code snippet from https://keyauth.cc/app/"))); -} - -if(empty(($_POST['name'] ?? $_GET['name']))) { - die(json_encode(array("success" => false, "message" => "No app name specified. Select app & copy code snippet from https://keyauth.cc/app/"))); -} - -if(strlen(($_POST['ownerid'] ?? $_GET['ownerid'])) != 10) { - die(json_encode(array("success" => false, "message" => "OwnerID should be 10 characters long. Select app & copy code snippet from https://keyauth.cc/app/"))); -} - -if (misc\cache\rateLimit("KeyAuthAppLimit:" . ($_POST['ownerid'] ?? $_GET['ownerid']), 1, 60, 200)) { - die(json_encode(array("success" => false, "message" => "This application has sent too many requests. Try again in a minute."))); +if (isset($_SERVER['HTTP_CDN_HOST'])) { // custom domains https://www.youtube.com/watch?v=a2SROFJ0eYc + $row = misc\cache\fetch('KeyAuthApp:' . misc\etc\sanitize($_SERVER['HTTP_CDN_HOST']), "SELECT * FROM `apps` WHERE `customDomainAPI` = '" . misc\etc\sanitize($_SERVER['HTTP_CDN_HOST']) . "'", 0); +} else { + $ownerid = misc\etc\sanitize($_POST['ownerid'] ?? $_GET['ownerid']); // ownerid of account that owns application + $name = misc\etc\sanitize($_POST['name'] ?? $_GET['name']); // application name + $row = misc\cache\fetch('KeyAuthApp:' . $name . ':' . $ownerid, "SELECT * FROM `apps` WHERE `ownerid` = '$ownerid' AND `name` = '$name'", 0); } -$ownerid = misc\etc\sanitize($_POST['ownerid'] ?? $_GET['ownerid']); // ownerid of account that owns application -$name = misc\etc\sanitize($_POST['name'] ?? $_GET['name']); // application name -$row = misc\cache\fetch('KeyAuthApp:' . $name . ':' . $ownerid, "SELECT * FROM `apps` WHERE `ownerid` = ? AND `name` = ?", [$ownerid, $name], 0); - if ($row == "not_found") { die("KeyAuth_Invalid"); } @@ -53,10 +30,6 @@ $appdisabled = $row['appdisabled']; $hashcheck = $row['hashcheck']; $serverhash = $row['hash']; -$sessionexpiry = $row['session']; -$forceEncryption = $row['forceEncryption']; -$forceHwid = $row['forceHwid']; -$tokensystem = $row['tokensystem']; $banned = $row['banned']; $owner = $row['owner']; @@ -73,54 +46,25 @@ $noactivesubs = $row['noactivesubs']; $hwidblacked = $row['hwidblacked']; $pausedsub = $row['pausedsub']; +$keyexpired = $row['keyexpired']; $vpnblocked = $row['vpnblocked']; $keybanned = $row['keybanned']; $userbanned = $row['userbanned']; $sessionunauthed = $row['sessionunauthed']; $hashcheckfail = $row['hashcheckfail']; -$invalid_token = $row['tokeninvalid']; - -// why using null coalescing operators? because if I add a field and it's not in redis cache, it'll be NULL -$loggedInMsg = $row['loggedInMsg'] ?? "Logged in!"; -$pausedApp = $row['pausedApp'] ?? "Application is currently paused, please wait for the developer to say otherwise."; -$unTooShort = $row['unTooShort'] ?? "Username too short, try longer one."; -$pwLeaked = $row['pwLeaked'] ?? "This password has been leaked in a data breach (not from us), please use a different one."; -$chatHitDelay = $row['chatHitDelay'] ?? "Chat slower, you've hit the delay limit"; -$minHwid = $row['minHwid'] ?? 20; - -if($ownerid == "hTmfnZOYPe") { - $response = json_encode(array( - "success" => false, - "message" => "Jao é um golpista, prova aqui https://keyauth.cc/jao/" - )); - - $sig = hash_hmac('sha256', $response, $secret); - header("signature: {$sig}"); - - die($response); -} +$sessionexpiry = $row['session']; +$killOtherSessions = $row['killOtherSessions']; +$forceEncryption = $row['forceEncryption']; if ($banned) { die(json_encode(array( "success" => false, - "message" => "This application has been banned from KeyAuth.cc for violating terms." // yes we self promote to customers of those who break ToS. Should've followed terms :shrug: + "message" => "This application has been banned from KeyAuth.com for violating terms." // yes we self promote to customers of those who break ToS. Should've followed terms :shrug: ))); } switch ($_POST['type'] ?? $_GET['type']) { case 'init': - if(strlen($_POST['enckey']) > 35) { - $response = json_encode(array( - "success" => false, - "message" => "The paramater \"enckey\" is too long. Must be 35 characters or less." - )); - - $sig = hash_hmac('sha256', $response, $secret); - header("signature: {$sig}"); - - die($response); - } - if ($forceEncryption) { if (!isset($_POST['enckey']) && !isset($_GET['enckey'])) { $response = json_encode(array( @@ -137,18 +81,15 @@ $ip = api\shared\primary\getIp(); if ($vpnblock) { if (api\shared\primary\vpnCheck($ip)) { - $row = misc\cache\fetch('KeyAuthWhitelist:' . $secret . ':' . $ip, "SELECT 1 FROM `whitelist` WHERE `ip` = ? AND `app` = ?", [$ip, $secret], 0); - if ($row == "not_found") { - $response = json_encode(array( - "success" => false, - "message" => "$vpnblocked" - )); + $response = json_encode(array( + "success" => false, + "message" => "$vpnblocked" + )); - $sig = hash_hmac('sha256', $response, $secret); - header("signature: {$sig}"); + $sig = hash_hmac('sha256', $response, $secret); + header("signature: {$sig}"); - die($response); - } + die($response); } } @@ -167,7 +108,7 @@ if ($paused) { $response = json_encode(array( "success" => false, - "message" => "$pausedApp" + "message" => "Application is currently paused, please wait for the developer to say otherwise." )); $sig = hash_hmac('sha256', $response, $secret); @@ -176,93 +117,8 @@ die($response); } - if ($tokensystem) { - - list($token, $thash) = [misc\etc\sanitize($_POST["token"] ?? $_GET["token"]) , misc\etc\sanitize($_POST["thash"] ?? $_GET["thash"])]; - - if (!isset($token)) { - - $response = json_encode(array( - "success" => false, - "message" => "Token Must Be Provided" - )); - - $sig = hash_hmac('sha256', $response, $secret); - header("signature: {$sig}"); - - die($response); - } - - if (!isset($thash)) { - $response = json_encode(array( - "success" => false, - "message" => "Hash Must Be Provided" - )); - - $sig = hash_hmac('sha256', $response, $secret); - header("signature: {$sig}"); - - die($response); - } - - $verification = misc\token\checktoken("check_data", $token, $secret, null, $thash); - - switch ($verification) { - case str_contains($verification, 'token_blacklisted'): - $reason = str_ireplace("token_blacklisted, ", "", $verification); - $response = json_encode(array( - "success" => false, - "message" => "The Token Has Been Blacklisted For The Following Reason: " . $reason . " Contact Application Developer If This Is A Mistake" - )); - - $sig = hash_hmac('sha256', $response, $secret); - header("signature: {$sig}"); - - die($response); - case 'invalid_token': - - $response = json_encode(array( - "success" => false, - "message" => $invalid_token - )); - - $sig = hash_hmac('sha256', $response, $secret); - header("signature: {$sig}"); - - die($response); - - case 'hash_mismatch': - - $response = json_encode(array( - "success" => false, - "message" => "Token File Hashes Must Be The Same" - )); - - $sig = hash_hmac('sha256', $response, $secret); - header("signature: {$sig}"); - - die($response); - - case 'success': - break; - - default: - - $response = json_encode(array( - "success" => false, - "message" => "Unknown Error Occured" - )); - - $sig = hash_hmac('sha256', $response, $secret); - header("signature: {$sig}"); - - die($response); - - } - } - $ver = misc\etc\sanitize($_POST['ver'] ?? $_GET['ver']); - if (!empty($ver)) { + if (is_numeric($ver)) { if ($ver != $currentver) { // auto-update system $response = json_encode(array( @@ -283,7 +139,8 @@ if ($hashcheck) { if (strpos($serverhash, $hash) === false) { if (is_null($serverhash)) { - misc\mysql\query("UPDATE `apps` SET `hash` = ? WHERE `secret` = ?", [$hash, $secret]); + include_once (($_SERVER['DOCUMENT_ROOT'] == "/usr/share/nginx/html/panel" || $_SERVER['DOCUMENT_ROOT'] == "/usr/share/nginx/html/api") ? "/usr/share/nginx/html" : $_SERVER['DOCUMENT_ROOT']) . '/includes/connection.php'; // create connection with MySQL + mysqli_query($link, "UPDATE `apps` SET `hash` = '$hash' WHERE `secret` = '$secret'"); misc\cache\purge('KeyAuthApp:' . $name . ':' . $ownerid); // flush cache for application so new hash takes precedent } else { $response = json_encode(array( @@ -300,56 +157,46 @@ } $enckey = !is_null($_POST['enckey'] ?? $_GET['enckey']) ? misc\etc\sanitize($_POST['enckey'] ?? $_GET['enckey']) . "-" . $secret : NULL; - $newSession = false; - $duplicateSession = misc\cache\select("KeyAuthSessionDupe:$secret:$ip"); - if($duplicateSession) { - $sessionid = $duplicateSession; - - $updateSession = misc\cache\update('KeyAuthState:'.$secret.':'.$sessionid.'', array("validated" => 0, "enckey" => $enckey)); - if(!$updateSession) { - $sessionid = misc\etc\generateRandomString(); - $newSession = true; + $sessionid = misc\etc\generateRandomString(); + + if (is_null($enckey)) { + $row = misc\cache\fetch('KeyAuthStateDuplicates:' . $secret . ':' . $ip, "SELECT `id`, `expiry` FROM `sessions` WHERE `app` = '$secret' AND `ip` = '$ip' AND `validated` = 0 AND `expiry` > " . time() . " LIMIT 1", 0); + if ($row != "not_found") { + $sessionid = $row['id']; + goto dupe; } } - else { - $sessionid = misc\etc\generateRandomString(); - $newSession = true; - } + // session init + $time = time() + $sessionexpiry; + include_once (($_SERVER['DOCUMENT_ROOT'] == "/usr/share/nginx/html/panel" || $_SERVER['DOCUMENT_ROOT'] == "/usr/share/nginx/html/api") ? "/usr/share/nginx/html" : $_SERVER['DOCUMENT_ROOT']) . '/includes/connection.php'; // create connection with MySQL + mysqli_query($link, "INSERT INTO `sessions` (`id`, `app`, `expiry`, `enckey`, `ip`) VALUES ('$sessionid','$secret', '$time', '$enckey', '$ip')"); + misc\cache\purge('KeyAuthStateDuplicates:' . $secret . ':' . $ip); - // $row = misc\cache\fetch('KeyAuthAppStats:' . $secret, "SELECT (SELECT COUNT(1) FROM `users` WHERE `app` = ?) AS 'numUsers', (SELECT COUNT(1) FROM `sessions` WHERE `app` = ? AND `validated` = 1 AND `expiry` > ?) AS 'numOnlineUsers', (SELECT COUNT(1) FROM `keys` WHERE `app` = ?) AS 'numKeys' FROM dual", [$secret, $secret, time(), $secret], 0, 3600); + dupe: - $numUsers = "N/A - Use fetchStats() function in latest example"; - $numOnlineUsers = "N/A - Use fetchStats() function in latest example"; - $numKeys = "N/A - Use fetchStats() function in latest example"; + $row = misc\cache\fetch('KeyAuthAppStats:' . $secret, "SELECT(select count(1) FROM `users` WHERE `app` = '$secret') AS 'numUsers',(select count(1) FROM `sessions` WHERE `app` = '$secret' AND `validated` = 1 AND `expiry` > " . time() . ") AS 'numOnlineUsers',(select count(1) FROM `keys` WHERE `app` = '$secret') AS 'numKeys';", 0, 1800); + + $numUsers = $row['numUsers']; + $numOnlineUsers = $row['numOnlineUsers']; + $numKeys = $row['numKeys']; $resp = json_encode(array( "success" => true, "message" => "Initialized", "sessionid" => $sessionid, "appinfo" => array( - "numUsers" => "$numUsers", - "numOnlineUsers" => "$numOnlineUsers", - "numKeys" => "$numKeys", - "version" => "$currentver", + "numUsers" => $numUsers, + "numOnlineUsers" => $numOnlineUsers, + "numKeys" => $numKeys, + "version" => $currentver, "customerPanelLink" => "https://keyauth.cc/panel/$owner/$name/" - ), - "newSession" => $newSession, - "nonce" => misc\etc\generateRandomString(32) + ) )); $sig = !is_null($enckey) ? hash_hmac('sha256', $resp, $secret) : 'No encryption key supplied'; header("signature: {$sig}"); - echo $resp; - - fastcgi_finish_request(); - - if($newSession) { - misc\cache\insert("KeyAuthState:$secret:$sessionid", serialize(array("credential" => NULL, "enckey" => $enckey, "validated" => 0)), $sessionexpiry); - $time = time() + $sessionexpiry; - misc\mysql\query("INSERT INTO `sessions` (`id`, `app`, `expiry`, `created_at`, `enckey`, `ip`) VALUES (?, ?, ?, ?, NULLIF(?, ''), ?)", [$sessionid, $secret, $time, time(), $enckey, $ip]); - misc\cache\insert("KeyAuthSessionDupe:$secret:$ip", $sessionid, $sessionexpiry); - } + die($resp); case 'register': // retrieve session info @@ -360,45 +207,16 @@ // Read in username $username = misc\etc\sanitize($_POST['username'] ?? $_GET['username']); - if(strlen($username) > 70) { - $response = json_encode(array( - "success" => false, - "message" => "Username must be shorter than 70 characters" - )); - - $sig = !is_null($enckey) ? hash_hmac('sha256', $response, $enckey) : NULL; - header("signature: {$sig}"); - - die($response); - } - // Read in license key $checkkey = misc\etc\sanitize($_POST['key'] ?? $_GET['key']); - if(strlen($checkkey) > 70) { - $response = json_encode(array( - "success" => false, - "message" => "Key must be shorter than 70 characters" - )); - - $sig = !is_null($enckey) ? hash_hmac('sha256', $response, $enckey) : NULL; - header("signature: {$sig}"); - - die($response); - } - // Read in password $password = misc\etc\sanitize($_POST['pass'] ?? $_GET['pass']); - // Read in email - $email = misc\etc\sanitize($_POST['email'] ?? $_GET['email']); - // Read in hwid $hwid = misc\etc\sanitize($_POST['hwid'] ?? $_GET['hwid']); - $registerSuccess = false; - - $resp = api\v1_0\register($username, $checkkey, $password, $email, $hwid, $secret); + $resp = api\v1_0\register($username, $checkkey, $password, $hwid, $secret); switch ($resp) { case 'username_taken': $response = json_encode(array( @@ -415,13 +233,13 @@ case 'un_too_short': $response = json_encode(array( "success" => false, - "message" => "$unTooShort" + "message" => "Username too short, try longer one." )); break; case 'pw_leaked': $response = json_encode(array( "success" => false, - "message" => "$pwLeaked" + "message" => "This password has been leaked in a data breach (not from us), please use a different one." )); break; case 'key_already_used': @@ -431,9 +249,10 @@ )); break; case 'key_banned': + include_once (($_SERVER['DOCUMENT_ROOT'] == "/usr/share/nginx/html/panel" || $_SERVER['DOCUMENT_ROOT'] == "/usr/share/nginx/html/api") ? "/usr/share/nginx/html" : $_SERVER['DOCUMENT_ROOT']) . '/includes/connection.php'; // create connection with MySQL if (strpos($keybanned, '{reason}') !== false) { - $query = misc\mysql\query("SELECT `banned` FROM `keys` WHERE `app` = ? AND `key` = ?", [$secret, $checkkey]); - $row = mysqli_fetch_array($query->result); + $result = mysqli_query($link, "SELECT `banned` FROM `keys` WHERE `app` = '$secret' AND `key` = '$checkkey'"); + $row = mysqli_fetch_array($result); $reason = $row['banned']; $keybanned = str_replace("{reason}", $reason, $keybanned); } @@ -455,28 +274,27 @@ )); break; default: - $registerSuccess = true; + include_once (($_SERVER['DOCUMENT_ROOT'] == "/usr/share/nginx/html/panel" || $_SERVER['DOCUMENT_ROOT'] == "/usr/share/nginx/html/api") ? "/usr/share/nginx/html" : $_SERVER['DOCUMENT_ROOT']) . '/includes/connection.php'; // create connection with MySQL + if ($killOtherSessions) { + mysqli_query($link, "DELETE FROM `sessions` WHERE `id` != '$sessionid' AND `credential` = '$username' AND `app` = '$secret'"); + misc\cache\purgePattern('KeyAuthState:' . $secret); + } + mysqli_query($link, "UPDATE `sessions` SET `credential` = '$username',`validated` = 1 WHERE `id` = '$sessionid'"); + misc\cache\purge('KeyAuthState:' . $secret . ':' . $sessionid); + $ip = api\shared\primary\getIp(); + misc\cache\purge('KeyAuthStateDuplicates:' . $secret . ':' . $ip); $response = json_encode(array( "success" => true, - "message" => "$loggedInMsg", - "info" => $resp, - "nonce" => misc\etc\generateRandomString(32) + "message" => "Logged in!", + "info" => $resp )); break; } $sig = !is_null($enckey) ? hash_hmac('sha256', $response, $enckey) : NULL; header("signature: {$sig}"); - echo $response; - - fastcgi_finish_request(); - - if ($registerSuccess) { - misc\cache\update('KeyAuthState:'.$secret.':'.$sessionid.'', array("validated" => 1, "credential" => $username)); - misc\mysql\query("UPDATE `sessions` SET `credential` = ?,`validated` = 1 WHERE `id` = ?", [$username, $sessionid]); - } - die(); + die($response); case 'upgrade': // retrieve session info $sessionid = misc\etc\sanitize($_POST['sessionid'] ?? $_GET['sessionid']); @@ -489,12 +307,13 @@ // Read in key $checkkey = misc\etc\sanitize($_POST['key'] ?? $_GET['key']); + include_once (($_SERVER['DOCUMENT_ROOT'] == "/usr/share/nginx/html/panel" || $_SERVER['DOCUMENT_ROOT'] == "/usr/share/nginx/html/api") ? "/usr/share/nginx/html" : $_SERVER['DOCUMENT_ROOT']) . '/includes/connection.php'; // create connection with MySQL // search for key - $query = misc\mysql\query("SELECT `banned`, `expires`, `status`, `level` FROM `keys` WHERE `key` = ? AND `app` = ?", [$checkkey, $secret]); + $result = mysqli_query($link, "SELECT `banned`, `expires`, `status`, `level` FROM `keys` WHERE `key` = '$checkkey' AND `app` = '$secret'"); // check if key exists - if ($query->num_rows < 1) { + if (mysqli_num_rows($result) < 1) { $response = json_encode(array( "success" => false, "message" => "$keynotfound" @@ -507,10 +326,10 @@ } // if key does exist - elseif ($query->num_rows > 0) { + elseif (mysqli_num_rows($result) > 0) { // get key info - while ($row = mysqli_fetch_array($query->result)) { + while ($row = mysqli_fetch_array($result)) { $expires = $row['expires']; $status = $row['status']; $level = $row['level']; @@ -531,12 +350,9 @@ } if (!is_null($banned)) { - if (strpos($keybanned, '{reason}') !== false) { - $keybanned = str_replace("{reason}", $banned, $keybanned); - } $response = json_encode(array( "success" => false, - "message" => "$keybanned" + "message" => "Key banned: {$banned}" )); $sig = !is_null($enckey) ? hash_hmac('sha256', $response, $enckey) : NULL; @@ -548,10 +364,10 @@ // add current time to key time $expiry = $expires + time(); - $query = misc\mysql\query("SELECT `name` FROM `subscriptions` WHERE `app` = ? AND `level` = ?", [$secret, $level]); - $subName = mysqli_fetch_array($query->result)['name']; + $result = mysqli_query($link, "SELECT `name` FROM `subscriptions` WHERE `app` = '$secret' AND `level` = '$level'"); + $subName = mysqli_fetch_array($result)['name']; - $resp = misc\user\extend($username, $subName, $expiry, 0, $secret); + $resp = misc\user\extend($username, $subName, $expiry, $secret); switch ($resp) { case 'missing': $response = json_encode(array( @@ -573,13 +389,12 @@ break; case 'success': // set key to used, and set usedby - misc\mysql\query("UPDATE `keys` SET `status` = 'Used', `usedon` = ?, `usedby` = ? WHERE `key` = ? AND `app` = ?", [time(), $username, $checkkey, $secret]); + mysqli_query($link, "UPDATE `keys` SET `status` = 'Used', `usedon` = '" . time() . "', `usedby` = '$username' WHERE `key` = '$checkkey'"); misc\cache\purge('KeyAuthKeys:' . $secret . ':' . $checkkey); - misc\cache\purge('KeyAuthSubs:' . $secret . ':' . $username); + misc\cache\purge('KeyAuthSubs:' . $secret . ':' . $username); $response = json_encode(array( "success" => true, - "message" => "Upgraded successfully", - "nonce" => misc\etc\generateRandomString(32) + "message" => "Upgraded successfully" )); break; default: @@ -589,10 +404,12 @@ )); break; } - $sig = !is_null($enckey) ? hash_hmac('sha256', $response, $enckey) : 'No encryption key supplied'; - header("signature: {$sig}"); + if (isset($response)) { + $sig = !is_null($enckey) ? hash_hmac('sha256', $response, $enckey) : 'No encryption key supplied'; + header("signature: {$sig}"); - die($response); + die($response); + } } case 'login': // retrieve session info @@ -612,30 +429,6 @@ // optional param for web loader $token = misc\etc\sanitize($_POST['token'] ?? $_GET['token']); - if(strlen($hwid) < $minHwid && !is_null($hwid)) { - $response = json_encode(array( - "success" => false, - "message" => "HWID must be {$minHwid} or more characters, change this in app settings." - )); - - $sig = !is_null($enckey) ? hash_hmac('sha256', $response, $enckey) : NULL; - header("signature: {$sig}"); - - die($response); - } - - if($forceHwid && is_null($hwid)) { - $response = json_encode(array( - "success" => false, - "message" => "Force HWID is enabled, disable in app settings if you want to use blank HWIDs" - )); - - $sig = !is_null($enckey) ? hash_hmac('sha256', $response, $enckey) : NULL; - header("signature: {$sig}"); - - die($response); - } - $resp = api\v1_0\login($username, $password, $hwid, $secret, $hwidenabled, $token); switch ($resp) { case 'un_not_found': @@ -652,8 +445,9 @@ break; case 'user_banned': if (strpos($userbanned, '{reason}') !== false) { - $query = misc\mysql\query("SELECT `banned` FROM `users` WHERE `app` = ? AND `username` = ?", [$secret, $username]); - $row = mysqli_fetch_array($query->result); + include_once (($_SERVER['DOCUMENT_ROOT'] == "/usr/share/nginx/html/panel" || $_SERVER['DOCUMENT_ROOT'] == "/usr/share/nginx/html/api") ? "/usr/share/nginx/html" : $_SERVER['DOCUMENT_ROOT']) . '/includes/connection.php'; // create connection with MySQL + $result = mysqli_query($link, "SELECT `banned` FROM `users` WHERE `app` = '$secret' AND `username` = '$username'"); + $row = mysqli_fetch_array($result); $reason = $row['banned']; $userbanned = str_replace("{reason}", $reason, $userbanned); } @@ -687,22 +481,28 @@ )); break; default: - misc\mysql\query("UPDATE `sessions` SET `validated` = 1,`credential` = ? WHERE `id` = ?", [$username, $sessionid]); - misc\cache\update('KeyAuthState:'.$secret.':'.$sessionid.'', array("validated" => 1, "credential" => $username)); + include_once (($_SERVER['DOCUMENT_ROOT'] == "/usr/share/nginx/html/panel" || $_SERVER['DOCUMENT_ROOT'] == "/usr/share/nginx/html/api") ? "/usr/share/nginx/html" : $_SERVER['DOCUMENT_ROOT']) . '/includes/connection.php'; // create connection with MySQL + if ($killOtherSessions) { + mysqli_query($link, "DELETE FROM `sessions` WHERE `id` != '$sessionid' AND `credential` = '$username' AND `app` = '$secret'"); + misc\cache\purgePattern('KeyAuthState:' . $secret); + } + mysqli_query($link, "UPDATE `sessions` SET `validated` = 1,`credential` = '$username' WHERE `id` = '$sessionid'"); + misc\cache\purge('KeyAuthState:' . $secret . ':' . $sessionid); $ip = api\shared\primary\getIp(); + misc\cache\purge('KeyAuthStateDuplicates:' . $secret . ':' . $ip); $response = json_encode(array( "success" => true, - "message" => "$loggedInMsg", - "info" => $resp, - "nonce" => misc\etc\generateRandomString(32) + "message" => "Logged in!", + "info" => $resp )); - break; } - $sig = !is_null($enckey) ? hash_hmac('sha256', $response, $enckey) : 'No encryption key supplied'; - header("signature: {$sig}"); + if (isset($response)) { + $sig = !is_null($enckey) ? hash_hmac('sha256', $response, $enckey) : 'No encryption key supplied'; + header("signature: {$sig}"); - die($response); + die($response); + } case 'license': // retrieve session info $sessionid = misc\etc\sanitize($_POST['sessionid'] ?? $_GET['sessionid']); @@ -710,44 +510,8 @@ $enckey = $session["enckey"]; $checkkey = misc\etc\sanitize($_POST['key'] ?? $_GET['key']); - if(strlen($checkkey) > 70) { - $response = json_encode(array( - "success" => false, - "message" => "Key must be shorter than 70 characters" - )); - - $sig = !is_null($enckey) ? hash_hmac('sha256', $response, $enckey) : NULL; - header("signature: {$sig}"); - - die($response); - } - $hwid = misc\etc\sanitize($_POST['hwid'] ?? $_GET['hwid']); - if(strlen($hwid) < $minHwid && !is_null($hwid)) { - $response = json_encode(array( - "success" => false, - "message" => "HWID must be {$minHwid} or more characters, change this in app settings." - )); - - $sig = !is_null($enckey) ? hash_hmac('sha256', $response, $enckey) : NULL; - header("signature: {$sig}"); - - die($response); - } - - if($forceHwid && is_null($hwid)) { - $response = json_encode(array( - "success" => false, - "message" => "Force HWID is enabled, disable in app settings if you want to use blank HWIDs" - )); - - $sig = !is_null($enckey) ? hash_hmac('sha256', $response, $enckey) : NULL; - header("signature: {$sig}"); - - die($response); - } - $resp = api\v1_0\login($checkkey, $checkkey, $hwid, $secret, $hwidenabled); switch ($resp) { @@ -762,8 +526,9 @@ break; case 'user_banned': if (strpos($userbanned, '{reason}') !== false) { - $query = misc\mysql\query("SELECT `banned` FROM `users` WHERE `app` = ? AND `username` = ?", [$secret, $checkkey]); - $row = mysqli_fetch_array($query->result); + include_once (($_SERVER['DOCUMENT_ROOT'] == "/usr/share/nginx/html/panel" || $_SERVER['DOCUMENT_ROOT'] == "/usr/share/nginx/html/api") ? "/usr/share/nginx/html" : $_SERVER['DOCUMENT_ROOT']) . '/includes/connection.php'; // create connection with MySQL + $result = mysqli_query($link, "SELECT `banned` FROM `users` WHERE `app` = '$secret' AND `username` = '$checkkey'"); + $row = mysqli_fetch_array($result); $reason = $row['banned']; $userbanned = str_replace("{reason}", $reason, $userbanned); } @@ -797,15 +562,20 @@ )); break; default: - misc\mysql\query("UPDATE `sessions` SET `validated` = 1,`credential` = ? WHERE `id` = ?", [$checkkey, $sessionid]); - misc\cache\update('KeyAuthState:'.$secret.':'.$sessionid.'', array("validated" => 1, "credential" => $checkkey)); + include_once (($_SERVER['DOCUMENT_ROOT'] == "/usr/share/nginx/html/panel" || $_SERVER['DOCUMENT_ROOT'] == "/usr/share/nginx/html/api") ? "/usr/share/nginx/html" : $_SERVER['DOCUMENT_ROOT']) . '/includes/connection.php'; // create connection with MySQL + if ($killOtherSessions) { + mysqli_query($link, "DELETE FROM `sessions` WHERE `id` != '$sessionid' AND `credential` = '$checkkey' AND `app` = '$secret'"); + misc\cache\purgePattern('KeyAuthState:' . $secret); + } + mysqli_query($link, "UPDATE `sessions` SET `validated` = 1,`credential` = '$checkkey' WHERE `id` = '$sessionid'"); + misc\cache\purge('KeyAuthState:' . $secret . ':' . $sessionid); $ip = api\shared\primary\getIp(); + misc\cache\purge('KeyAuthStateDuplicates:' . $secret . ':' . $ip); $response = json_encode(array( "success" => true, - "message" => "$loggedInMsg", - "info" => $resp, - "nonce" => misc\etc\generateRandomString(32) + "message" => "Logged in!", + "info" => $resp )); break; } @@ -817,7 +587,7 @@ } // if login didn't work, attempt to register - $resp = api\v1_0\register($checkkey, $checkkey, $checkkey, NULL, $hwid, $secret); + $resp = api\v1_0\register($checkkey, $checkkey, $checkkey, $hwid, $secret); switch ($resp) { case 'username_taken': $response = json_encode(array( @@ -834,13 +604,13 @@ case 'un_too_short': $response = json_encode(array( "success" => false, - "message" => "$unTooShort" + "message" => "Username too short, try longer one." )); break; case 'pw_leaked': $response = json_encode(array( "success" => false, - "message" => "$pwLeaked" + "message" => "This password has been leaked in a data breach (not from us), please use a different one." )); break; case 'key_already_used': @@ -851,8 +621,9 @@ break; case 'key_banned': if (strpos($keybanned, '{reason}') !== false) { - $query = misc\mysql\query("SELECT `banned` FROM `keys` WHERE `app` = ? AND `key` = ?", [$secret, $checkkey]); - $row = mysqli_fetch_array($query->result); + include_once (($_SERVER['DOCUMENT_ROOT'] == "/usr/share/nginx/html/panel" || $_SERVER['DOCUMENT_ROOT'] == "/usr/share/nginx/html/api") ? "/usr/share/nginx/html" : $_SERVER['DOCUMENT_ROOT']) . '/includes/connection.php'; // create connection with MySQL + $result = mysqli_query($link, "SELECT `banned` FROM `keys` WHERE `app` = '$secret' AND `key` = '$checkkey'"); + $row = mysqli_fetch_array($result); $reason = $row['banned']; $keybanned = str_replace("{reason}", $reason, $keybanned); } @@ -874,106 +645,34 @@ )); break; default: - misc\mysql\query("UPDATE `sessions` SET `validated` = 1,`credential` = ? WHERE `id` = ?", [$checkkey, $sessionid]); - misc\cache\update('KeyAuthState:'.$secret.':'.$sessionid.'', array("validated" => 1, "credential" => $checkkey)); + include_once (($_SERVER['DOCUMENT_ROOT'] == "/usr/share/nginx/html/panel" || $_SERVER['DOCUMENT_ROOT'] == "/usr/share/nginx/html/api") ? "/usr/share/nginx/html" : $_SERVER['DOCUMENT_ROOT']) . '/includes/connection.php'; // create connection with MySQL + if ($killOtherSessions) { + mysqli_query($link, "DELETE FROM `sessions` WHERE `id` != '$sessionid' AND `credential` = '$checkkey' AND `app` = '$secret'"); + misc\cache\purgePattern('KeyAuthState:' . $secret); + } + mysqli_query($link, "UPDATE `sessions` SET `validated` = 1,`credential` = '$checkkey' WHERE `id` = '$sessionid'"); + misc\cache\purge('KeyAuthState:' . $secret . ':' . $sessionid); + + $ip = api\shared\primary\getIp(); + misc\cache\purge('KeyAuthStateDuplicates:' . $secret . ':' . $ip); $response = json_encode(array( "success" => true, - "message" => "$loggedInMsg", - "info" => $resp, - "nonce" => misc\etc\generateRandomString(32) + "message" => "Logged in!", + "info" => $resp )); } - $sig = !is_null($enckey) ? hash_hmac('sha256', $response, $enckey) : 'No encryption key supplied'; - header("signature: {$sig}"); - - die($response); - case 'forgot': - $sessionid = misc\etc\sanitize($_POST['sessionid'] ?? $_GET['sessionid']); - $session = api\shared\primary\getSession($sessionid, $secret); - $enckey = $session["enckey"]; - - $un = misc\etc\sanitize($_POST['username'] ?? $_GET['username']); - $email = strtolower(misc\etc\sanitize($_POST['email'] ?? $_GET['email'])); - - $row = misc\cache\fetch('KeyAuthUser:' . $secret . ':' . $un, "SELECT * FROM `users` WHERE `username` = ? AND `app` = ?", [$un, $secret], 0); - if ($row == "not_found") { - $response = json_encode(array( - "success" => false, - "message" => "No user found with that username!" - )); + if (isset($response)) { $sig = !is_null($enckey) ? hash_hmac('sha256', $response, $enckey) : 'No encryption key supplied'; header("signature: {$sig}"); die($response); } - - $emailHashed = $row['email']; - - if (sha1($email) != $emailHashed) { - if(is_null($emailHashed)) { - $response = json_encode(array( - "success" => false, - "message" => "Email address not provided during register, ask developer to edit your account and change email." - )); - } - else { - $response = json_encode(array( - "success" => false, - "message" => "Email address doesn't match!" - )); - } - } else { - $algos = array( - 'ripemd128', - 'md5', - 'md4', - 'tiger128,4', - 'haval128,3', - 'haval128,4', - 'haval128,5' - ); - $emailSecret = hash($algos[array_rand($algos)], misc\etc\generateRandomString()); - - misc\mysql\query("INSERT INTO `resetUsers` (`secret`, `email`, `username`, `app`, `time`) VALUES (?, SHA1(?), ?, ?, ?)", [$emailSecret, $email, $un, $secret, time()]); - - $body = '
-

Hello '.$un.',

-

You recently requested to reset your password for the software '.$name.'. Use the button below to reset it. The link is only valid for the next 24 hours.

- - - - - - -

Thanks, -
The KeyAuth team

-
'; - misc\email\send($un, $email, $body, "KeyAuth - Password Reset for {$name}"); - $response = json_encode(array( - "success" => true, - "message" => "Successfully sent email to change password.", - "nonce" => misc\etc\generateRandomString(32) - )); - } - - $sig = !is_null($enckey) ? hash_hmac('sha256', $response, $enckey) : 'No encryption key supplied'; - header("signature: {$sig}"); - - die($response); case 'fetchOnline': $sessionid = misc\etc\sanitize($_POST['sessionid'] ?? $_GET['sessionid']); $session = api\shared\primary\getSession($sessionid, $secret); $enckey = $session["enckey"]; - $rows = misc\cache\fetch('KeyAuthOnlineUsers:' . $secret, "SELECT DISTINCT CONCAT(LEFT(`credential`, 10), IF(LENGTH(`credential`) > 10, REPEAT('*', LENGTH(`credential`) - 10), '')) AS `credential` FROM `sessions` WHERE `validated` = 1 AND `app` = ?", [$secret], 1, 1800); + $rows = misc\cache\fetch('KeyAuthOnlineUsers:' . $secret, "SELECT DISTINCT `credential` FROM `sessions` WHERE `validated` = 1 AND `app` = '$secret'", 1, 1800); if ($rows == "not_found") { $response = json_encode(array( @@ -981,47 +680,19 @@ "message" => "No online users found!" )); } - else { - $response = json_encode(array( - "success" => true, - "message" => "Successfully fetched online users.", - "users" => $rows, - "nonce" => misc\etc\generateRandomString(32) - )); - } - - $sig = !is_null($enckey) ? hash_hmac('sha256', $response, $enckey) : 'No encryption key supplied'; - header("signature: {$sig}"); - - die($response); - case 'fetchStats': - $sessionid = misc\etc\sanitize($_POST['sessionid'] ?? $_GET['sessionid']); - $session = api\shared\primary\getSession($sessionid, $secret); - $enckey = $session["enckey"]; - - $row = misc\cache\fetch('KeyAuthAppStats:' . $secret, "SELECT (SELECT COUNT(1) FROM `users` WHERE `app` = ?) AS 'numUsers', (SELECT COUNT(1) FROM `sessions` WHERE `app` = ? AND `validated` = 1 AND `expiry` > ?) AS 'numOnlineUsers', (SELECT COUNT(1) FROM `keys` WHERE `app` = ?) AS 'numKeys' FROM dual", [$secret, $secret, time(), $secret], 0, 3600); - - $numUsers = $row['numUsers']; - $numOnlineUsers = $row['numOnlineUsers']; - $numKeys = $row['numKeys']; $response = json_encode(array( "success" => true, - "message" => "Successfully fetched stats", - "appinfo" => array( - "numUsers" => "$numUsers", - "numOnlineUsers" => "$numOnlineUsers", - "numKeys" => "$numKeys", - "version" => "$currentver", - "customerPanelLink" => "https://keyauth.cc/panel/$owner/$name/" - ), - "nonce" => misc\etc\generateRandomString(32) + "message" => "Successfully fetched online users.", + "users" => $rows )); - - $sig = !is_null($enckey) ? hash_hmac('sha256', $response, $enckey) : 'No encryption key supplied'; - header("signature: {$sig}"); - - die($response); + + if (isset($response)) { + $sig = !is_null($enckey) ? hash_hmac('sha256', $response, $enckey) : 'No encryption key supplied'; + header("signature: {$sig}"); + + die($response); + } case 'setvar': $sessionid = misc\etc\sanitize($_POST['sessionid'] ?? $_GET['sessionid']); $session = api\shared\primary\getSession($sessionid, $secret); @@ -1040,60 +711,14 @@ $var = misc\etc\sanitize($_POST['var'] ?? $_GET['var']); $data = misc\etc\sanitize($_POST['data'] ?? $_GET['data']); + include_once (($_SERVER['DOCUMENT_ROOT'] == "/usr/share/nginx/html/panel" || $_SERVER['DOCUMENT_ROOT'] == "/usr/share/nginx/html/api") ? "/usr/share/nginx/html" : $_SERVER['DOCUMENT_ROOT']) . '/includes/connection.php'; // create connection with MySQL + mysqli_query($link, "REPLACE INTO `uservars` (`name`, `data`, `user`, `app`) VALUES ('$var', '$data', '" . $session["credential"] . "', '$secret')"); - if(is_null($var)) { - $response = json_encode(array( - "success" => true, - "message" => "No variable name provided" - )); - $sig = !is_null($enckey) ? hash_hmac('sha256', $response, $enckey) : 'No encryption key supplied'; - header("signature: {$sig}"); - die($response); - } - - if(is_null($data)) { - $response = json_encode(array( - "success" => true, - "message" => "No variable data provided" - )); - $sig = !is_null($enckey) ? hash_hmac('sha256', $response, $enckey) : 'No encryption key supplied'; - header("signature: {$sig}"); - die($response); - } - - if(strlen($data) > 500) { - $response = json_encode(array( - "success" => true, - "message" => "Variable data must be 500 characters or less" - )); - $sig = !is_null($enckey) ? hash_hmac('sha256', $response, $enckey) : 'No encryption key supplied'; - header("signature: {$sig}"); - die($response); - } - - $row = misc\cache\fetch('KeyAuthUserVar:' . $secret . ':' . $var . ':' . $session["credential"], "SELECT `data`, `readOnly` FROM `uservars` WHERE `name` = ? AND `user` = ? AND `app` = ?", [$var, $session["credential"], $secret], 0); - - if ($row != "not_found") { - $readOnly = $row["readOnly"]; - if ($readOnly) { - $response = json_encode(array( - "success" => false, - "message" => "Variable is read only" - )); - $sig = !is_null($enckey) ? hash_hmac('sha256', $response, $enckey) : 'No encryption key supplied'; - header("signature: {$sig}"); - die($response); - } - } - - $query = misc\mysql\query("REPLACE INTO `uservars` (`name`, `data`, `user`, `app`) VALUES (?, ?, ?, ?)", [$var, $data, $session["credential"], $secret]); - - if ($query->affected_rows != 0) { + if (mysqli_affected_rows($link) != 0) { misc\cache\purge('KeyAuthUserVar:' . $secret . ':' . $var . ':' . $session["credential"]); $response = json_encode(array( "success" => true, - "message" => "Successfully set variable", - "nonce" => misc\etc\generateRandomString(32) + "message" => "Successfully set variable" )); $sig = !is_null($enckey) ? hash_hmac('sha256', $response, $enckey) : 'No encryption key supplied'; @@ -1108,7 +733,6 @@ "success" => false, "message" => "Failed to set variable" )); - die($response); } case 'getvar': $sessionid = misc\etc\sanitize($_POST['sessionid'] ?? $_GET['sessionid']); @@ -1128,7 +752,7 @@ $var = misc\etc\sanitize($_POST['var'] ?? $_GET['var']); - $row = misc\cache\fetch('KeyAuthUserVar:' . $secret . ':' . $var . ':' . $session["credential"], "SELECT `data`, `readOnly` FROM `uservars` WHERE `name` = ? AND `user` = ? AND `app` = ?", [$var, $session["credential"], $secret], 0); + $row = misc\cache\fetch('KeyAuthUserVar:' . $secret . ':' . $var . ':' . $session["credential"], "SELECT `data` FROM `uservars` WHERE `name` = '$var' AND `user` = '" . $session["credential"] . "' AND `app` = '$secret'", 0); if ($row == "not_found") { $response = json_encode(array( @@ -1146,8 +770,7 @@ $response = json_encode(array( "success" => true, "message" => "Successfully retrieved variable", - "response" => $data, - "nonce" => misc\etc\generateRandomString(32) + "response" => $data )); $sig = !is_null($enckey) ? hash_hmac('sha256', $response, $enckey) : 'No encryption key supplied'; header("signature: {$sig}"); @@ -1161,7 +784,7 @@ $varid = misc\etc\sanitize($_POST['varid'] ?? $_GET['varid']); - $row = misc\cache\fetch('KeyAuthVar:' . $secret . ':' . $varid, "SELECT `msg`, `authed` FROM `vars` WHERE `varid` = ? AND `app` = ?", [$varid, $secret], 0); + $row = misc\cache\fetch('KeyAuthVar:' . $secret . ':' . $varid, "SELECT `msg`, `authed` FROM `vars` WHERE `varid` = '$varid' AND `app` = '$secret'", 0); if ($row == "not_found") { $response = json_encode(array( @@ -1193,8 +816,7 @@ } $response = json_encode(array( "success" => true, - "message" => "$msg", - "nonce" => misc\etc\generateRandomString(32) + "message" => "$msg" )); $sig = !is_null($enckey) ? hash_hmac('sha256', $response, $enckey) : 'No encryption key supplied'; header("signature: {$sig}"); @@ -1209,13 +831,12 @@ $hwid = misc\etc\sanitize($_POST['hwid'] ?? $_GET['hwid']); $ip = api\shared\primary\getIp(); - $row = misc\cache\fetch('KeyAuthBlacklist:' . $secret . ':' . $ip . ':' . $hwid, "SELECT 1 FROM `bans` WHERE (`hwid` = ? OR `ip` = ?) AND `app` = ?", [$hwid, $ip, $secret], 0); + $row = misc\cache\fetch('KeyAuthBlacklist:' . $secret . ':' . $ip . ':' . $hwid, "SELECT 1 FROM `bans` WHERE (`hwid` = '$hwid' OR `ip` = '$ip') AND `app` = '$secret'", 0); if ($row != "not_found") { $response = json_encode(array( "success" => true, - "message" => "Client is blacklisted", - "nonce" => misc\etc\generateRandomString(32) + "message" => "Client is blacklisted" )); $sig = !is_null($enckey) ? hash_hmac('sha256', $response, $enckey) : 'No encryption key supplied'; header("signature: {$sig}"); @@ -1248,17 +869,16 @@ } $channel = misc\etc\sanitize($_POST['channel'] ?? $_GET['channel']); - $rows = misc\cache\fetch('KeyAuthChatMsgs:' . $secret . ':' . $channel, "SELECT `author`, `message`, `timestamp` FROM `chatmsgs` WHERE `channel` = ? AND `app` = ?", [$channel, $secret], 1); + $rows = misc\cache\fetch('KeyAuthChatMsgs:' . $secret . ':' . $channel, "SELECT `author`, `message`, `timestamp` FROM `chatmsgs` WHERE `channel` = '$channel' AND `app` = '$secret'", 1); - if ($rows == "not_found") { + if ($rows == "not_found") { $rows = []; } $response = json_encode(array( "success" => true, "message" => "Successfully retrieved chat messages", - "messages" => $rows, - "nonce" => misc\etc\generateRandomString(32) + "messages" => $rows )); $sig = !is_null($enckey) ? hash_hmac('sha256', $response, $enckey) : 'No encryption key supplied'; header("signature: {$sig}"); @@ -1281,9 +901,10 @@ } $channel = misc\etc\sanitize($_POST['channel'] ?? $_GET['channel']); - $query = misc\mysql\query("SELECT `delay` FROM `chats` WHERE `name` = ? AND `app` = ?", [$channel, $secret]); + include_once (($_SERVER['DOCUMENT_ROOT'] == "/usr/share/nginx/html/panel" || $_SERVER['DOCUMENT_ROOT'] == "/usr/share/nginx/html/api") ? "/usr/share/nginx/html" : $_SERVER['DOCUMENT_ROOT']) . '/includes/connection.php'; // create connection with MySQL + $result = mysqli_query($link, "SELECT `delay` FROM `chats` WHERE `name` = '$channel' AND `app` = '$secret'"); - if ($query->num_rows < 1) { + if (mysqli_num_rows($result) < 1) { $response = json_encode(array( "success" => false, "message" => "Chat channel not found" @@ -1294,18 +915,18 @@ die($response); } - $row = mysqli_fetch_array($query->result); + $row = mysqli_fetch_array($result); $delay = $row['delay']; $credential = $session["credential"]; - $query = misc\mysql\query("SELECT `timestamp` FROM `chatmsgs` WHERE `author` = ? AND `channel` = ? AND `app` = ? ORDER BY `id` DESC LIMIT 1", [$credential, $channel, $secret]); + $result = mysqli_query($link, "SELECT `timestamp` FROM `chatmsgs` WHERE `author` = '$credential' AND `channel` = '$channel' AND `app` = '$secret' ORDER BY `id` DESC LIMIT 1"); - $row = mysqli_fetch_array($query->result); + $row = mysqli_fetch_array($result); $time = $row['timestamp']; if (time() - $time < $delay) { $response = json_encode(array( "success" => false, - "message" => "$chatHitDelay" + "message" => "Chat slower, you've hit the delay limit" )); $sig = !is_null($enckey) ? hash_hmac('sha256', $response, $enckey) : 'No encryption key supplied'; header("signature: {$sig}"); @@ -1313,9 +934,9 @@ die($response); } - $query = misc\mysql\query("SELECT `time` FROM `chatmutes` WHERE `user` = ? AND `app` = ?", [$credential, $secret]); - if ($query->num_rows != 0) { - $row = mysqli_fetch_array($query->result); + $result = mysqli_query($link, "SELECT `time` FROM `chatmutes` WHERE `user` = '$credential' AND `app` = '$secret'"); + if (mysqli_num_rows($result) != 0) { + $row = mysqli_fetch_array($result); $unmuted = $row["time"]; $unmuted = date("F j, Y, g:i a", $unmuted); $response = json_encode(array( @@ -1329,45 +950,18 @@ } $message = misc\etc\sanitize($_POST['message'] ?? $_GET['message']); - - if (is_null($message)) { - $response = json_encode(array( - "success" => false, - "message" => "Message can't be blank" - )); - $sig = !is_null($enckey) ? hash_hmac('sha256', $response, $enckey) : 'No encryption key supplied'; - header("signature: {$sig}"); - - die($response); - } - - if(strlen($message) > 2000) { - $response = json_encode(array( - "success" => false, - "message" => "Message too long!" - )); - $sig = !is_null($enckey) ? hash_hmac('sha256', $response, $enckey) : 'No encryption key supplied'; - header("signature: {$sig}"); - - die($response); - } - - misc\mysql\query("INSERT INTO `chatmsgs` (`author`, `message`, `timestamp`, `channel`,`app`) VALUES (?, ?, ?, ?, ?)", [$credential, $message, time(), $channel, $secret]); - misc\mysql\query("DELETE FROM `chatmsgs` WHERE `app` = ? AND `channel` = ? AND `id` NOT IN ( SELECT `id` FROM ( SELECT `id` FROM `chatmsgs` WHERE `channel` = ? AND `app` = ? ORDER BY `id` DESC LIMIT 50) foo );", [$secret, $channel, $channel, $secret]); + mysqli_query($link, "INSERT INTO `chatmsgs` (`author`, `message`, `timestamp`, `channel`,`app`) VALUES ('$credential','$message','" . time() . "','$channel','$secret')"); + mysqli_query($link, "DELETE FROM `chatmsgs` WHERE `app` = '$secret' AND `channel` = '$channel' AND `id` NOT IN ( SELECT `id` FROM ( SELECT `id` FROM `chatmsgs` WHERE `channel` = '$channel' AND `app` = '$secret' ORDER BY `id` DESC LIMIT 20) foo );"); misc\cache\purge('KeyAuthChatMsgs:' . $secret . ':' . $channel); $response = json_encode(array( "success" => true, - "message" => "Successfully sent chat message", - "nonce" => misc\etc\generateRandomString(32) + "message" => "Successfully sent chat message" )); $sig = !is_null($enckey) ? hash_hmac('sha256', $response, $enckey) : 'No encryption key supplied'; header("signature: {$sig}"); die($response); case 'log': - // client isn't expecting a response body, just flush output right away so program can move on to rest of the code quicker - fastcgi_finish_request(); - // retrieve session info $sessionid = misc\etc\sanitize($_POST['sessionid'] ?? $_GET['sessionid']); $session = api\shared\primary\getSession($sessionid, $secret); @@ -1379,28 +973,11 @@ $msg = misc\etc\sanitize($_POST['message'] ?? $_GET['message']); - if(is_null($msg)) { - die("No log data specified"); - } - - if(strlen($msg) > 275) { - die("Log data too long"); - } - $pcuser = misc\etc\sanitize($_POST['pcuser'] ?? $_GET['pcuser']); if (is_null($webhook)) { - $roleCheck = misc\cache\fetch('KeyAuthSellerCheck:' . $owner, "SELECT `role`,`expires` FROM `accounts` WHERE `username` = ?", [$owner], 0); - if($roleCheck['role'] == "tester") { - $query = misc\mysql\query("SELECT count(*) AS 'numLogs' FROM `logs` WHERE `logapp` = ?",[$secret]); - $row = mysqli_fetch_array($query->result); - $numLogs = $row["numLogs"]; - if($numLogs >= 20) { - die(); - } - } - - misc\mysql\query("INSERT INTO `logs` (`logdate`, `logdata`, `credential`, `pcuser`,`logapp`) VALUES (?, ?, NULLIF(?, ''), NULLIF(?, ''), ?)", [$currtime, $msg, $credential, $pcuser, $secret]); + include_once (($_SERVER['DOCUMENT_ROOT'] == "/usr/share/nginx/html/panel" || $_SERVER['DOCUMENT_ROOT'] == "/usr/share/nginx/html/api") ? "/usr/share/nginx/html" : $_SERVER['DOCUMENT_ROOT']) . '/includes/connection.php'; // create connection with MySQL + mysqli_query($link, "INSERT INTO `logs` (`logdate`, `logdata`, `credential`, `pcuser`,`logapp`) VALUES ('$currtime','$msg',NULLIF('$credential', ''),NULLIF('$pcuser', ''),'$secret')"); die(); } @@ -1411,6 +988,13 @@ $ip = api\shared\primary\getIp(); $json_data = json_encode([ + // Username + "username" => "KeyAuth", + + // Avatar URL. + // Uncoment to replace image set in webhook + "avatar_url" => "https://cdn.keyauth.cc/front/assets/img/favicon.png", + // Embeds Array "embeds" => [ [ @@ -1457,7 +1041,7 @@ $enckey = $session["enckey"]; $webid = misc\etc\sanitize($_POST['webid'] ?? $_GET['webid']); - $row = misc\cache\fetch('KeyAuthWebhook:' . $secret . ':' . $webid, "SELECT `baselink`, `useragent`, `authed` FROM `webhooks` WHERE `webid` = ? AND `app` = ?", [$webid, $secret], 0); + $row = misc\cache\fetch('KeyAuthWebhook:' . $secret . ':' . $webid, "SELECT `baselink`, `useragent`, `authed` FROM `webhooks` WHERE `webid` = '$webid' AND `app` = '$secret'", 0); if ($row == "not_found") { $response = json_encode(array( "success" => false, @@ -1511,8 +1095,7 @@ $resp = json_encode(array( "success" => true, "message" => "Webhook request successful", - "response" => "$response", - "nonce" => misc\etc\generateRandomString(32) + "response" => "$response" )); $sig = !is_null($enckey) ? hash_hmac('sha256', $resp, $enckey) : 'No encryption key supplied'; header("signature: {$sig}"); @@ -1526,7 +1109,7 @@ $fileid = misc\etc\sanitize($_POST['fileid'] ?? $_GET['fileid']); - $row = misc\cache\fetch('KeyAuthFile:' . $secret . ':' . $fileid, "SELECT `name`, `url`, `authed` FROM `files` WHERE `app` = ? AND `id` = ?", [$secret, $fileid], 0); + $row = misc\cache\fetch('KeyAuthFile:' . $secret . ':' . $fileid, "SELECT `name`, `url`, `authed` FROM `files` WHERE `app` = '$secret' AND `id` = '$fileid'", 0); if ($row == "not_found") { $response = json_encode(array( @@ -1559,8 +1142,8 @@ die($response); } } - - ini_set('memory_limit', '-1'); + + ini_set('memory_limit', '-1'); $ch = curl_init($url); curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true); @@ -1584,8 +1167,7 @@ $response = json_encode(array( "success" => true, "message" => "File download successful", - "contents" => "$contents", - "nonce" => misc\etc\generateRandomString(32) + "contents" => "$contents" )); $sig = !is_null($enckey) ? hash_hmac('sha256', $response, $enckey) : 'No encryption key supplied'; header("signature: {$sig}"); @@ -1611,20 +1193,7 @@ die($response); } - $reason = misc\etc\sanitize($_POST['reason'] ?? $_GET['reason']) ?? "User banned from triggering ban function in the client"; - - if(strlen($reason) > 99) { - $response = json_encode(array( - "success" => false, - "message" => "Reason must be 99 characters or less" - )); - - $sig = !is_null($enckey) ? hash_hmac('sha256', $response, $enckey) : 'No encryption key supplied'; - header("signature: {$sig}"); - - die($response); - } - + include_once (($_SERVER['DOCUMENT_ROOT'] == "/usr/share/nginx/html/panel" || $_SERVER['DOCUMENT_ROOT'] == "/usr/share/nginx/html/api") ? "/usr/share/nginx/html" : $_SERVER['DOCUMENT_ROOT']) . '/includes/connection.php'; // create connection with MySQL $hwid = misc\etc\sanitize($_POST['hwid'] ?? $_GET['hwid']); if (!empty($hwid)) { misc\blacklist\add($hwid, "Hardware ID", $secret); @@ -1632,13 +1201,12 @@ $ip = api\shared\primary\getIp(); misc\blacklist\add($ip, "IP Address", $secret); - misc\mysql\query("UPDATE `users` SET `banned` = ? WHERE `username` = ? AND `app` = ?", [$reason, $credential, $secret]); - if ($query->affected_rows != 0) { + mysqli_query($link, "UPDATE `users` SET `banned` = 'User banned from triggering ban function in the client' WHERE `username` = '$credential'"); + if (mysqli_affected_rows($link) != 0) { misc\cache\purge('KeyAuthUser:' . $secret . ':' . $credential); $response = json_encode(array( "success" => true, - "message" => "Successfully Banned User", - "nonce" => misc\etc\generateRandomString(32) + "message" => "Successfully Banned User" )); $sig = !is_null($enckey) ? hash_hmac('sha256', $response, $enckey) : 'No encryption key supplied'; header("signature: {$sig}"); @@ -1673,275 +1241,16 @@ } else { $response = json_encode(array( "success" => true, - "message" => "Session is validated.", - "nonce" => misc\etc\generateRandomString(32) - )); - $sig = !is_null($enckey) ? hash_hmac('sha256', $response, $enckey) : 'No encryption key supplied'; - header("signature: {$sig}"); - - die($response); - } - case 'changeUsername': - $sessionid = misc\etc\sanitize($_POST['sessionid'] ?? $_GET['sessionid']); - $session = api\shared\primary\getSession($sessionid, $secret); - $enckey = $session["enckey"]; - - if (!$session["validated"]) { - $response = json_encode(array( - "success" => false, - "message" => "$sessionunauthed" + "message" => "Session is validated." )); $sig = !is_null($enckey) ? hash_hmac('sha256', $response, $enckey) : 'No encryption key supplied'; header("signature: {$sig}"); die($response); } - - $credential = $session["credential"]; - - $resp = misc\user\changeUsername($credential, $_POST['newUsername'] ?? $_GET['newUsername'], $secret); - switch ($resp) { - case 'already_used': - $response = json_encode(array( - "success" => false, - "message" => "Username already used!" - )); - break; - case 'failure': - $response = json_encode(array( - "success" => false, - "message" => "Failed to change username!" - )); - break; - case 'success': - misc\session\killSingular($sessionid, $secret); - $response = json_encode(array( - "success" => true, - "message" => "Successfully changed username, user logged out.", - "nonce" => misc\etc\generateRandomString(32) - )); - break; - default: - $response = json_encode(array( - "success" => false, - "message" => "Unhandled Error! Contact us if you need help" - )); - break; - } - $sig = !is_null($enckey) ? hash_hmac('sha256', $response, $enckey) : 'No encryption key supplied'; - header("signature: {$sig}"); - - die($response); - case 'logout': - $sessionid = misc\etc\sanitize($_POST['sessionid'] ?? $_GET['sessionid']); - $session = api\shared\primary\getSession($sessionid, $secret); - $enckey = $session["enckey"]; - misc\session\killSingular($sessionid, $secret); - $response = json_encode(array( - "success" => true, - "message" => "Successfully logged out.", - "nonce" => misc\etc\generateRandomString(32) - )); - $sig = !is_null($enckey) ? hash_hmac('sha256', $response, $enckey) : 'No encryption key supplied'; - header("signature: {$sig}"); - - die($response); - case '2faenable': - - list($sessionid, $code) = [misc\etc\sanitize($_POST['sessionid'] ?? $_GET['sessionid']), misc\etc\sanitize($_POST["code"] ?? $_GET["code"])]; - $session = api\shared\primary\getSession($sessionid, $secret); - $enckey = $session["enckey"]; - - if (!$session["validated"]) { - $response = json_encode(array( - "success" => false, - "message" => "$sessionunauthed" - )); - $sig = !is_null($enckey) ? hash_hmac('sha256', $response, $enckey) : 'No encryption key supplied'; - header("signature: {$sig}"); - - die($response); - } - - $row = misc\cache\fetch('KeyAuthUser:' . $secret . ':' . $session["credential"], "SELECT * FROM `users` WHERE `username` = ? AND `app` = ?", [$session["credential"], $secret], 0); - - if ($row["2fa"]) { - - $response = json_encode(array( - "success" => false, - "message" => "2fa is already enabled on this account" - )); - - $sig = !is_null($enckey) ? hash_hmac('sha256', $response, $enckey) : 'No encryption key supplied'; - header("signature: {$sig}"); - - die($response); - - } - - include_once '../../auth/GoogleAuthenticator.php'; - - $_2fa = new GoogleAuthenticator(); - - if (empty($code) || is_null($code)) { - - $secret_code = $_2fa->createSecret(); - - misc\cache\insert('KeyAuthTwoFactorAuthentication:' . $session["credential"], $secret_code, 300); - - $qrcode = str_replace(urlencode("https://chart.googleapis.com/chart?chs=200x200&chld=M|0&cht=qr&chl="), " ", $_2fa->getQRCodeGoogleUrl($session["credential"], $secret_code, 'KeyAuth')); - - $response = json_encode(array( - "success" => true, - "2fa" => array( - "secret_code" => $secret_code, - "QRCode" => "otpauth://totp/" . $session["credential"] . "?secret=" . $secret_code . "&issuer=KeyAuth" - ) - )); - - $sig = !is_null($enckey) ? hash_hmac('sha256', $response, $enckey) : 'No encryption key supplied'; - header("signature: {$sig}"); - - die($response); - - } - else { - - $secret_code = misc\cache\select('KeyAuthTwoFactorAuthentication:' . $session["credential"]); - - if (!$secret_code) { - - $response = json_encode(array( - "success" => true, - "message" => "2fa session has expired" - )); - - $sig = !is_null($enckey) ? hash_hmac('sha256', $response, $enckey) : 'No encryption key supplied'; - header("signature: {$sig}"); - - die($response); - - } - - if ($_2fa->verifyCode($secret_code, $code, 2)) { - - misc\mysql\query("UPDATE `users` SET `2fa` = ?, `googleAuthCode` = ? WHERE `app` = ? AND `username` = ?", [1, $secret_code, $secret, $session["credential"]]); - misc\cache\purge('KeyAuthUser:' . $secret . ':' . $session["credential"]); - misc\cache\purge('KeyAuthTwoFactorAuthentication: ' . $session["credential"]); - - $response = json_encode(array( - "success" => true, - "message" => "2fa successfully activated" - )); - - $sig = !is_null($enckey) ? hash_hmac('sha256', $response, $enckey) : 'No encryption key supplied'; - header("signature: {$sig}"); - - die($response); - - } - else { - - $response = json_encode(array( - "success" => true, - "message" => "Invalid code please try again" - )); - - $sig = !is_null($enckey) ? hash_hmac('sha256', $response, $enckey) : 'No encryption key supplied'; - header("signature: {$sig}"); - - die($response); - - } - - } - case '2fadisable': - - list($sessionid, $code) = [misc\etc\sanitize($_POST['sessionid'] ?? $_GET['sessionid']), misc\etc\sanitize($_POST["code"] ?? $_GET["code"])]; - - if (empty($code) || is_null($code)) { - - $response = json_encode(array( - "success" => false, - "message" => "Please provide the 2fa code to disable 2fa" - )); - - $sig = !is_null($enckey) ? hash_hmac('sha256', $response, $enckey) : 'No encryption key supplied'; - header("signature: {$sig}"); - - die($response); - - } - - $session = api\shared\primary\getSession($sessionid, $secret); - $enckey = $session["enckey"]; - - if (!$session["validated"]) { - $response = json_encode(array( - "success" => false, - "message" => "$sessionunauthed" - )); - $sig = !is_null($enckey) ? hash_hmac('sha256', $response, $enckey) : 'No encryption key supplied'; - header("signature: {$sig}"); - - die($response); - } - - $row = misc\cache\fetch('KeyAuthUser:' . $secret . ':' . $session["credential"], "SELECT * FROM `users` WHERE `username` = ? AND `app` = ?", [$session["credential"], $secret], 0); - - if (!$row["2fa"]) { - - $response = json_encode(array( - "success" => false, - "message" => "2fa is not enabled on this account" - )); - - $sig = !is_null($enckey) ? hash_hmac('sha256', $response, $enckey) : 'No encryption key supplied'; - header("signature: {$sig}"); - - die($response); - - } - - include_once '../../auth/GoogleAuthenticator.php'; - - $_2fa = new GoogleAuthenticator(); - - $secret_code = $row["googleAuthCode"]; - - if ($_2fa->verifyCode($secret_code, $code, 2)) { - - misc\mysql\query("UPDATE `users` SET `2fa` = ?, `googleAuthCode` = ? WHERE `app` = ? AND `username` = ?", [0, NULL, $secret, $row["username"]]); - misc\cache\purge('KeyAuthUser:' . $secret . ':' . $session["credential"]); - - $response = json_encode(array( - "success" => true, - "message" => "2fa successfully activated" - )); - - $sig = !is_null($enckey) ? hash_hmac('sha256', $response, $enckey) : 'No encryption key supplied'; - header("signature: {$sig}"); - - die($response); - - } - else { - - $response = json_encode(array( - "success" => true, - "message" => "Invalid code please try again" - )); - - $sig = !is_null($enckey) ? hash_hmac('sha256', $response, $enckey) : 'No encryption key supplied'; - header("signature: {$sig}"); - - die($response); - - } - - default: - die(json_encode(array( - "success" => false, - "message" => "The value inputted for type paramater was not found" - ))); - } + default: + die(json_encode(array( + "success" => false, + "message" => "The value inputted for type paramater was not found" + ))); +} diff --git a/api/dashboard/webauthn.php b/api/dashboard/webauthn.php deleted file mode 100644 index 161e7be4..00000000 --- a/api/dashboard/webauthn.php +++ /dev/null @@ -1,191 +0,0 @@ - getCreateArgs - * | - * navigator.credentials.create <-------------' - * | - * '-------------------------> processCreate - * | - * alert ok or fail <----------------' - * - * ------------------------------------------------------------ - * - * VALIDATION - * - * window.fetch ------------------> getGetArgs - * | - * navigator.credentials.get <----------------' - * | - * '-------------------------> processGet - * | - * alert ok or fail <----------------' - * - * ------------------------------------------------------------ - */ -include '../../includes/misc/autoload.phtml'; -require_once '../../vendor/lbuchs/webauthn/src/WebAuthn.php'; -try { - // read get argument and post body - $fn = filter_input(INPUT_GET, 'fn'); - if(empty($fn)) { - die("Can't access directly"); - } - $post = trim(file_get_contents('php://input')); - $userId = bin2hex(openssl_random_pseudo_bytes(10)); - if ($post) { - $post = json_decode($post); - } - - session_start(); - // Formats - $formats = array(); - $formats[] = 'none'; - - $rpId = $_SERVER['HTTP_HOST']; - - // cross-platform: true, if type internal is not allowed - // false, if only internal is allowed - // null, if internal and cross-platform is allowed - $crossPlatformAttachment = null; - - - // new Instance of the server library. - // make sure that $rpId is the domain name. - $WebAuthn = new lbuchs\WebAuthn\WebAuthn('KeyAuth', $rpId, $formats); - - // ------------------------------------ - // request for create arguments - // ------------------------------------ - - if ($fn === 'getCreateArgs') { - $createArgs = $WebAuthn->getCreateArgs($userId, $_SESSION['username'], "", 20, 0, "discouraged", $crossPlatformAttachment); - - header('Content-Type: application/json'); - print(json_encode($createArgs)); - - // save challange to session. you have to deliver it to processGet later. - $_SESSION['challenge'] = $WebAuthn->getChallenge(); - - - - // ------------------------------------ - // request for get arguments - // ------------------------------------ - - } else if ($fn === 'getGetArgs') { - $ids = array(); - - // load registrations from session stored there by processCreate. - - $query = misc\mysql\query("SELECT * FROM `securityKeys` WHERE `username` = ?", [$_SESSION['pendingUsername']]); - if ($query->num_rows > 0) { - while ($row = mysqli_fetch_array($query->result)) { - $ids[] = base64_decode($row["credentialId"]); - } - } - - if (count($ids) === 0) { - throw new Exception('No security key registrations found for this user!'); - } - - $getArgs = $WebAuthn->getGetArgs($ids, 20, 1, 1, 1, 1, 0); - - header('Content-Type: application/json'); - print(json_encode($getArgs)); - - // save challange to session. you have to deliver it to processGet later. - $_SESSION['challenge'] = $WebAuthn->getChallenge(); - - - - // ------------------------------------ - // process create - // ------------------------------------ - - } else if ($fn === 'processCreate') { - $clientDataJSON = base64_decode($post->clientDataJSON); - $attestationObject = base64_decode($post->attestationObject); - $challenge = $_SESSION['challenge']; - - // processCreate returns data to be stored for future logins. - $data = $WebAuthn->processCreate($clientDataJSON, $attestationObject, $challenge, 0, false, false); - - unset($_SESSION['challenge']); // disgard challenge array from session file, no longer needed - - $name = misc\etc\sanitize($_GET['name']); - - misc\mysql\query("INSERT INTO `securityKeys` (`username`, `name`, `credentialId`, `credentialPublicKey`) VALUES (?, ?, ?, ?)", [$_SESSION['username'], $name, base64_encode($data->credentialId), $data->credentialPublicKey]); - misc\mysql\query("UPDATE `accounts` SET `securityKey` = 1 WHERE `username` = ?", [$_SESSION['username']]); - - $return = new stdClass(); - $return->success = true; - $return->msg = 'registration success.'; - - header('Content-Type: application/json'); - print(json_encode($return)); - - - - // ------------------------------------ - // proccess get - // ------------------------------------ - - } else if ($fn === 'processGet') { - $clientDataJSON = base64_decode($post->clientDataJSON); - $authenticatorData = base64_decode($post->authenticatorData); - $signature = base64_decode($post->signature); - $userHandle = base64_decode($post->userHandle); - $id = base64_decode($post->id); - $challenge = $_SESSION['challenge']; - $credentialPublicKey = null; - - // looking up correspondending public key of the credential id - // you should also validate that only ids of the given user name - // are taken for the login. - - $query = misc\mysql\query("SELECT * FROM `securityKeys` WHERE `username` = ?", [$_SESSION['pendingUsername']]); - if ($query->num_rows > 0) { - while ($row = mysqli_fetch_array($query->result)) { - if(base64_decode($row["credentialId"]) === $id) { - $credentialPublicKey = $row["credentialPublicKey"]; - break; - } - } - } - - if ($credentialPublicKey === null) { - throw new Exception('This security key wasn\'t found!'); - } - - // process the get request. throws WebAuthnException if it fails - $WebAuthn->processGet($clientDataJSON, $authenticatorData, $signature, $credentialPublicKey, $challenge, null, 0); - - unset($_SESSION['challenge']); // disgard challenge array from session file, no longer needed - $_SESSION['username'] = $_SESSION['pendingUsername']; - unset($_SESSION['pendingUsername']); - - $return = new stdClass(); - $return->success = true; - - header('Content-Type: application/json'); - print(json_encode($return)); - } - -} catch (Throwable $ex) { - $return = new stdClass(); - $return->success = false; - $return->msg = $ex->getMessage(); - - header('Content-Type: application/json'); - print(json_encode($return)); -} \ No newline at end of file diff --git a/api/index.php b/api/index.php index be080288..72c4e065 100644 --- a/api/index.php +++ b/api/index.php @@ -1,3 +1,3 @@ getMessage()); - die("Error: " . $errorMsg); -}); - if (session_status() === PHP_SESSION_NONE) { - session_start(); + session_start(); } -if ($_SESSION['role'] == "Reseller") { - die("Resellers can't access this."); +if($_SESSION['role'] == "Reseller") { + die("Resellers can't access this."); } -if (!isset($_SESSION['app'])) { - die("Application not selected."); +if(!isset($_SESSION['app'])) { + die("Application not selected."); } -if (isset($_POST['draw'])) { - - // credits to https://makitweb.com/datatables-ajax-pagination-with-search-and-sort-php/ - - $draw = intval($_POST['draw']); - $row = intval($_POST['start']); - $rowperpage = intval($_POST['length']); // Rows display per page - $columnIndex = misc\etc\sanitize($_POST['order'][0]['column']); // Column index - $columnName = misc\etc\sanitize($_POST['columns'][$columnIndex]['data']); // Column name - $columnSortOrder = misc\etc\sanitize($_POST['order'][0]['dir']); // asc or desc - $searchValue = misc\etc\sanitize($_POST['search']['value']); // Search value - - // whitelist certain column names and sort orders to prevent SQL injection - if (!in_array($columnName, array("type"))) { - die("Column name is not whitelisted."); - } - - if (!in_array($columnSortOrder, array("desc", "asc"))) { - die("Column sort order is not whitelisted."); - } - - if (!is_null($searchValue)) { - $query = misc\mysql\query("select * from `bans` WHERE (`ip` like ? or `hwid` like ? or `type` like ? ) and app = ? order by `" . $columnName . "` " . $columnSortOrder . " limit " . $row . "," . $rowperpage, ["%" . $searchValue . "%", "%" . $searchValue . "%", "%" . $searchValue . "%", $_SESSION['app']]); - } - else { - $query = misc\mysql\query("select * from `bans` WHERE app = ? order by `" . $columnName . "` " . $columnSortOrder . " limit " . $row . "," . $rowperpage, [$_SESSION['app']]); - } - - $data = array(); - - while ($row = mysqli_fetch_assoc($query->result)) { - $data[] = array( - "data" => '' . ($row["hwid"] ?? $row["ip"]) . '', - "type" => $row["type"], - "actions" => - '
- -
- -
- - - - - -
', - ); - } - - ## Response - $response = array( - "draw" => intval($draw), - "aaData" => $data - ); +if(isset($_POST['draw']) ) { + + // credits to https://makitweb.com/datatables-ajax-pagination-with-search-and-sort-php/ + + $draw = misc\etc\sanitize($_POST['draw']); + $row = misc\etc\sanitize($_POST['start']); + $rowperpage = misc\etc\sanitize($_POST['length']); // Rows display per page + $columnIndex = misc\etc\sanitize($_POST['order'][0]['column']); // Column index + $searchValue = misc\etc\sanitize($_POST['search']['value']); // Search value + + ## Search + $searchQuery = " "; + if($searchValue != ''){ + $searchQuery = " and (`ip` like '%".$searchValue."%' or + `hwid` like '%".$searchValue."%' or + `type` like'%".$searchValue."%' ) "; + } + + ## Total number of records without filtering + $sel = mysqli_query($link,"select count(1) as allcount from `bans` where app = '".$_SESSION['app']."'"); + $records = mysqli_fetch_assoc($sel); + $totalRecords = $records['allcount']; + + ## Total number of record with filtering + $sel = mysqli_query($link,"select count(1) as allcount from `bans` WHERE 1 ".$searchQuery." and app = '".$_SESSION['app']."'"); + $records = mysqli_fetch_assoc($sel); + $totalRecordwithFilter = $records['allcount']; + + ## Fetch records + $empQuery = "select * from `bans` WHERE 1 ".$searchQuery." and app = '".$_SESSION['app']."' limit ".$row.",".$rowperpage; + // echo $empQuery; + $empRecords = mysqli_query($link, $empQuery); + $data = array(); + + while ($row = mysqli_fetch_assoc($empRecords)) { + $data[] = array( + "data"=>$row["hwid"] ?? $row["ip"], + "type"=>$row["type"], + "actions"=>'
', + ); + } + + ## Response + $response = array( + "draw" => intval($draw), + "iTotalRecords" => $totalRecords, + "iTotalDisplayRecords" => $totalRecordwithFilter, + "aaData" => $data + ); + + die(json_encode($response)); - die(json_encode($response)); } -die("Request not from datatables, aborted."); +die("Request not from datatables, aborted."); \ No newline at end of file diff --git a/app/download-types.php b/app/download-types.php deleted file mode 100644 index fdb3a75c..00000000 --- a/app/download-types.php +++ /dev/null @@ -1,169 +0,0 @@ - array(), - "subscription" => array() - ) - ); - - $jsondata = json_decode($jsonarray); - - $userquery = misc\mysql\query("SELECT * FROM `users` WHERE `app` = ?", [$_SESSION['app']]); - - while ($row = mysqli_fetch_array($userquery->result)) { - - $userjson = array( - "username" => $row["username"], - "email" => $row["email"], - "password" => $row["password"], - "hwid" => $row["hwid"], - "banned" => $row["banned"], - "ip" => $row["ip"] - ); - - array_push($jsondata->users, $userjson); - } - - $subscriptionquery = misc\mysql\query("SELECT * FROM `subs` WHERE `app` = ? ", [$_SESSION['app']]); - - while ($row = mysqli_fetch_array($subscriptionquery->result)) { - - $subjson = array( - "user" => $row["user"], - "subscription" => "default", - "expiry" => $row["expiry"] - ); - - array_push($jsondata->subscription, $subjson); - } - - $newjson = json_encode($jsondata); - - header('Content-Description: File Transfer'); - header('Content-Type: application/octet-stream'); - header('Content-Disposition: attachment; filename="KeyAuthUsers.json"'); - header('Expires: 0'); - header('Cache-Control: must-revalidate'); - header('Pragma: public'); - header('Content-Length: ' . strlen($newjson)); - - - die($newjson); - case 'licenses': - $query = misc\mysql\query("SELECT * FROM `keys` WHERE `app` = ?",[$_SESSION['app']]); - - // Create an array to hold the keys - $keysArray = array(); - - while ($row = mysqli_fetch_array($query->result)) { - // Add each key to the array - $keysArray[] = array( - "key" => $row['key'], - "level" => $row['level'], - "expiry" => $row['expires'] / 86400 - ); - } - - // Convert the array to a JSON string - $jsonData = json_encode($keysArray); - - header('Content-Description: File Transfer'); - header('Content-Type: application/json'); // Set the content type to JSON - header('Content-Disposition: attachment; filename="KeyAuthKeys.json"'); - header('Expires: 0'); - header('Cache-Control: must-revalidate'); - header('Pragma: public'); - header('Content-Length: ' . strlen($jsonData)); - - echo $jsonData; - - die($stringData); - case 'logs': - $jsonarray = json_encode( - array( - "logs" => array() - ) - ); - - $jsondata = json_decode($jsonarray); - - $userlogquery = misc\mysql\query("SELECT * FROM `logs` WHERE `logapp` = ?", [$_SESSION['app']]); - - while ($row = mysqli_fetch_array($userlogquery->result)) { - - $userlogjson = array( - "logdate" => $row["logdate"], - "logdata" => $row["logdata"], - "credential" => $row["credential"], - "pcuser" => $row["pcuser"] - ); - - array_push($jsondata->logs, $userlogjson); - } - - - $newjson = json_encode($jsondata); - - header('Content-Description: File Transfer'); - header('Content-Type: application/octet-stream'); - header('Content-Disposition: attachment; filename="KeyAuthUserLogs.json"'); - header('Expires: 0'); - header('Cache-Control: must-revalidate'); - header('Pragma: public'); - header('Content-Length: ' . strlen($newjson)); - - - die($newjson); - case 'auditLog': - $jsonarray = json_encode( - array( - "auditLog" => array() - ) - ); - - $jsondata = json_decode($jsonarray); - - $userquery = misc\mysql\query("SELECT * FROM `auditLog` WHERE `app` = ?", [$_SESSION['app']]); - - while ($row = mysqli_fetch_array($userquery->result)) { - - $userjson = array( - "id" => $row["id"], - "user" => $row["user"], - "event" => $row["event"], - "time" => $row["time"], - ); - - array_push($jsondata->auditLog, $userjson); - } - - - $newjson = json_encode($jsondata); - - header('Content-Description: File Transfer'); - header('Content-Type: application/octet-stream'); - header('Content-Disposition: attachment; filename="KeyAuthAuditLogs.json"'); - header('Expires: 0'); - header('Cache-Control: must-revalidate'); - header('Pragma: public'); - header('Content-Length: ' . strlen($newjson)); - - die($newjson); - default: - echo 'Invalid Type or Type does not Exist'; -} diff --git a/app/index.php b/app/index.php index 017960dd..d403e921 100644 --- a/app/index.php +++ b/app/index.php @@ -1,7 +1,10 @@ getMessage()); - \dashboard\primary\error($errorMsg); -}); - $username = $_SESSION['username']; -$query = misc\mysql\query("SELECT * FROM `accounts` WHERE `username` = ?",[$username]); -$row = mysqli_fetch_array($query->result); +($result = mysqli_query($link, "SELECT * FROM `accounts` WHERE `username` = '$username'")) or die(mysqli_error($link)); +$row = mysqli_fetch_array($result); $banned = $row['banned']; $lastreset = $row['lastreset']; -if (!is_null($banned) || $_SESSION['logindate'] < $lastreset || $query->num_rows < 1) { +if (!is_null($banned) || $_SESSION['logindate'] < $lastreset || mysqli_num_rows($result) < 1) { echo ""; session_destroy(); exit(); } $role = $row['role']; -$permissions = $row['permissions']; $admin = $row['admin']; -$staff = $row['staff']; -$formBanned = $row['formBanned']; $twofactor = $row['twofactor']; $_SESSION['role'] = $role; $expires = $row['expires']; -if (in_array($role, array("developer", "seller"))) { +if (in_array($role, array( + "developer", + "seller" +))) { $_SESSION['timeleft'] = dashboard\primary\expireCheck($username, $expires); } if (!$_SESSION['app']) // no app selected yet { - $query = misc\mysql\query("SELECT `secret`, `name`, `banned`, `sellerkey` FROM `apps` WHERE `owner` = ? AND `ownerid` = ?",[$_SESSION['username'], $_SESSION['ownerid']]); // select all apps where owner is current user - if ($query->num_rows == 1) // if the user only owns one app, load that app (they can still change app after it's loaded) + $result = mysqli_query($link, "SELECT * FROM `apps` WHERE `owner` = '" . $_SESSION['username'] . "'"); // select all apps where owner is current user + if (mysqli_num_rows($result) == 1) // if the user only owns one app, load that app (they can still change app after it's loaded) { - $row = mysqli_fetch_array($query->result); + $row = mysqli_fetch_array($result); $_SESSION['name'] = $row["name"]; $_SESSION["selectedApp"] = $row["name"]; $_SESSION['app'] = $row["secret"]; - $_SESSION['sellerkey'] = $row["sellerkey"]; } } + + ?> - - - - - - - - - - - - - + + Keyauth - Open Source Auth + + + + + + + + + + + + - - - - - - - - - + - -
-
-
- -
-
- - Loading taking a while? Please - feel free to return. - -
- - - -
-
- - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/layout/_footer.php b/app/layout/_footer.php new file mode 100644 index 00000000..59822134 --- /dev/null +++ b/app/layout/_footer.php @@ -0,0 +1,16 @@ + + + \ No newline at end of file diff --git a/app/layout/_loader.php b/app/layout/_loader.php new file mode 100644 index 00000000..7187055a --- /dev/null +++ b/app/layout/_loader.php @@ -0,0 +1,9 @@ + +
+ Logo +
+ + Loading... +
+
+ \ No newline at end of file diff --git a/app/layout/_scrolltop.php b/app/layout/_scrolltop.php new file mode 100644 index 00000000..a9d0a557 --- /dev/null +++ b/app/layout/_scrolltop.php @@ -0,0 +1,14 @@ + +
+ + + + + + + + +
+ \ No newline at end of file diff --git a/app/layout/aside.php b/app/layout/aside.php deleted file mode 100644 index f78d9d5a..00000000 --- a/app/layout/aside.php +++ /dev/null @@ -1,190 +0,0 @@ - - - - -
diff --git a/app/layout/aside/_base.php b/app/layout/aside/_base.php new file mode 100644 index 00000000..e32e62e6 --- /dev/null +++ b/app/layout/aside/_base.php @@ -0,0 +1,53 @@ + + + +
+ + + + + +
+ + + + + +
+ + +
+ \ No newline at end of file diff --git a/app/layout/aside/_menu.php b/app/layout/aside/_menu.php new file mode 100644 index 00000000..8c4a0889 --- /dev/null +++ b/app/layout/aside/_menu.php @@ -0,0 +1,281 @@ + + + + + + + + + + + + +
+ + + + +
+ + + + \ No newline at end of file diff --git a/app/layout/aside/resellermenu.php b/app/layout/aside/resellermenu.php new file mode 100644 index 00000000..2ce25076 --- /dev/null +++ b/app/layout/aside/resellermenu.php @@ -0,0 +1,72 @@ + + + + + + + + + + + + +
+ + + + +
+ + + + \ No newline at end of file diff --git a/app/layout/breadcrumb.php b/app/layout/breadcrumb.php deleted file mode 100644 index 924b92f6..00000000 --- a/app/layout/breadcrumb.php +++ /dev/null @@ -1,22 +0,0 @@ - diff --git a/app/layout/footer.php b/app/layout/footer.php deleted file mode 100644 index 0d0603fa..00000000 --- a/app/layout/footer.php +++ /dev/null @@ -1,17 +0,0 @@ - diff --git a/app/layout/header/_base.php b/app/layout/header/_base.php new file mode 100644 index 00000000..8ba6ae19 --- /dev/null +++ b/app/layout/header/_base.php @@ -0,0 +1,52 @@ + +
+ +
+ +
+
+ + + + + + + + +
+
+ + +
+ + Logo + +
+ + +
+ +
+ + + +
+ + +
+ + + +
+ +
+ +
+ +
+ \ No newline at end of file diff --git a/app/layout/header/_menu.php b/app/layout/header/_menu.php new file mode 100644 index 00000000..9b1c19d4 --- /dev/null +++ b/app/layout/header/_menu.php @@ -0,0 +1,31 @@ + + +
+ + + +
+ \ No newline at end of file diff --git a/app/layout/master.php b/app/layout/master.php index 7abcf05f..0b5a8cb1 100644 --- a/app/layout/master.php +++ b/app/layout/master.php @@ -1,39 +1,39 @@ - - -
- - - - - - -
-
- - -
- - + + + +
+ +
+ + + + +
+ + + + +
+ + + + +
+ + + +
+ +
+ + + + +
+
+
+ + + \ No newline at end of file diff --git a/app/layout/page-title/_default.php b/app/layout/page-title/_default.php new file mode 100644 index 00000000..c80c5499 --- /dev/null +++ b/app/layout/page-title/_default.php @@ -0,0 +1,13 @@ + + +
+ +

+ + +

+ +
+ \ No newline at end of file diff --git a/app/layout/profile.php b/app/layout/profile.php deleted file mode 100644 index c03531da..00000000 --- a/app/layout/profile.php +++ /dev/null @@ -1,92 +0,0 @@ -num_rows > 0) { - while ($row_ = mysqli_fetch_array($query->result)) { - $acclogs = $row_['acclogs']; - $expiry = $row_["expires"]; - $emailVerify = $row_["emailVerify"]; - } -} - -if ($_SERVER['REQUEST_METHOD'] === 'POST') { - if (isset($_POST['logout'])) { - session_destroy(); - header('Location: /login'); - exit; - } -} - -?> - -
-
- - -
- -
-
-
- " alt="profile image" /> - -
- -
- - - " . strtoupper($role) . " PLAN

"; - ?> - - '', - 'developer' => '', - 'seller' => '', - 'Reseller' => '', - 'Manager' => '', - 'default' => '' - }; - echo $display; - - if ($role === 'developer' || $role === 'seller') { - echo ''; - } - ?> -
-
-
diff --git a/app/layout/toolbars/_toolbar-1.php b/app/layout/toolbars/_toolbar-1.php new file mode 100644 index 00000000..651d46ba --- /dev/null +++ b/app/layout/toolbars/_toolbar-1.php @@ -0,0 +1,11 @@ + +
+ +
+ + + + +
+ +
\ No newline at end of file diff --git a/app/layout/topbar.php b/app/layout/topbar.php deleted file mode 100644 index 978bce8d..00000000 --- a/app/layout/topbar.php +++ /dev/null @@ -1,133 +0,0 @@ - - - diff --git a/app/layout/topbar/_base.php b/app/layout/topbar/_base.php new file mode 100644 index 00000000..a3ff6596 --- /dev/null +++ b/app/layout/topbar/_base.php @@ -0,0 +1,49 @@ + +
+ +
+

+
+ +
+ + +
+ + + + + + + + +
+
+ + + + + + + + +
+
+ +
+ \ No newline at end of file diff --git a/app/layout/topbar/partials/_user-menu.php b/app/layout/topbar/partials/_user-menu.php new file mode 100644 index 00000000..4d8b78a2 --- /dev/null +++ b/app/layout/topbar/partials/_user-menu.php @@ -0,0 +1,43 @@ + + + \ No newline at end of file diff --git a/app/license-download.php b/app/license-download.php new file mode 100644 index 00000000..7b23efce --- /dev/null +++ b/app/license-download.php @@ -0,0 +1,49 @@ +getMessage()); -}); - if (session_status() === PHP_SESSION_NONE) { - session_start(); + session_start(); } if ($_SESSION['role'] == "Reseller") { - die("Resellers can't access this."); + die("Resellers can't access this."); } if (!isset($_SESSION['app'])) { - dashboard\primary\error("Application not selected"); - die("Application not selected."); + die("Application not selected."); } if (isset($_POST['draw'])) { - // credits to https://makitweb.com/datatables-ajax-pagination-with-search-and-sort-php/ - - $draw = intval($_POST['draw']); - $row = intval($_POST['start']); - $rowperpage = intval($_POST['length']); // Rows display per page - $columnIndex = misc\etc\sanitize($_POST['order'][0]['column']); // Column index - $columnName = misc\etc\sanitize($_POST['columns'][$columnIndex]['data']); // Column name - $columnSortOrder = misc\etc\sanitize($_POST['order'][0]['dir']); // asc or desc - $searchValue = misc\etc\sanitize($_POST['search']['value']); // Search value - - // whitelist certain column names and sort orders to prevent SQL injection - if (!in_array($columnName, array("key", "gendate", "genby", "expires", "note", "usedon", "usedby", "status"))) { - die("Column name is not whitelisted."); - } - - if (!in_array($columnSortOrder, array("desc", "asc"))) { - die("Column sort order is not whitelisted."); - } - - if (!is_null($searchValue)) { - $query = misc\mysql\query("select * from `keys` WHERE (`key` like ? or `note` like ? or `genby` like ? or `usedby` like ? ) and app = ? order by `" . $columnName . "` " . $columnSortOrder . " limit " . $row . "," . $rowperpage, ["%" . $searchValue . "%", "%" . $searchValue . "%", "%" . $searchValue . "%", "%" . $searchValue . "%", $_SESSION['app']]); - } - else { - $query = misc\mysql\query("select * from `keys` WHERE app = ? order by `" . $columnName . "` " . $columnSortOrder . " limit " . $row . "," . $rowperpage, [$_SESSION['app']]); - } - - $data = array(); - - while ($row = mysqli_fetch_assoc($query->result)) { - - ## If only one or two keys exists then we will use custom margin to fix the bugging menu - $banBtns = ""; - if ($row['status'] == "Banned") { - $banBtns = ''; - } else { - $banBtns = ''; - } - - $MarginManager = ""; - if ($query->num_rows < 2) { - $MarginManager = "margin-bottom: 20px;"; - } else { - $MarginManager = "margin-bottom: 0px;"; - } - - $data[] = array( - "key" => $row['key'], - "gendate" => '
', - "genby" => $row['genby'], - "expires" => timeconversion($row["expires"]), - "note" => $row['note'] ?? 'N/A', - "usedon" => (!is_null($row["usedon"])) ? '
' : 'N/A', - "usedby" => ($row["usedby"] == $row['key']) ? 'Same as key' : $row["usedby"] ?? 'N/A', - "status" => '' . $row['status'] . '', - - "actions" => ' -
- -
- -
    -
  • - -
  • -
  • - ' . $banBtns . ' -
  • -
  • - -
  • -
-
- - -
- ', - ); - } - - ## Response - $response = array( - "draw" => intval($draw), - "aaData" => $data - ); - - die(json_encode($response)); + // credits to https://makitweb.com/datatables-ajax-pagination-with-search-and-sort-php/ + + $draw = misc\etc\sanitize($_POST['draw']); + $row = misc\etc\sanitize($_POST['start']); + $rowperpage = misc\etc\sanitize($_POST['length']); // Rows display per page + $columnIndex = misc\etc\sanitize($_POST['order'][0]['column']); // Column index + $columnName = misc\etc\sanitize($_POST['columns'][$columnIndex]['data']); // Column name + $columnSortOrder = misc\etc\sanitize($_POST['order'][0]['dir']); // asc or desc + $searchValue = misc\etc\sanitize($_POST['search']['value']); // Search value + + ## Search + $searchQuery = " "; + if ($searchValue != '') { + $searchQuery = " and (`key` like '%" . $searchValue . "%' or + `note` like '%" . $searchValue . "%' or + `genby` like'%" . $searchValue . "%' or + `usedby` like'%" . $searchValue . "%' ) "; + } + + ## Total number of records without filtering + $sel = mysqli_query($link, "select count(1) as allcount from `keys` where app = '" . $_SESSION['app'] . "'"); + $records = mysqli_fetch_assoc($sel); + $totalRecords = $records['allcount']; + + ## Total number of record with filtering + $sel = mysqli_query($link, "select count(1) as allcount from `keys` WHERE 1 " . $searchQuery . " and app = '" . $_SESSION['app'] . "'"); + $records = mysqli_fetch_assoc($sel); + $totalRecordwithFilter = $records['allcount']; + + ## Fetch records + $empQuery = "select * from `keys` WHERE 1 " . $searchQuery . " and app = '" . $_SESSION['app'] . "' order by `" . $columnName . "` " . $columnSortOrder . " limit " . $row . "," . $rowperpage; + // echo $empQuery; + $empRecords = mysqli_query($link, $empQuery); + + $data = array(); + + while ($row = mysqli_fetch_assoc($empRecords)) { + + ## If only one or two keys exists then we will use custom margin to fix the bugging menu + $banBtns = ""; + if ($row['status'] == "Banned") { $banBtns = ''; } else { $banBtns = 'Ban'; } + + $MarginManager = ""; + if ($totalRecordwithFilter < 2) { $MarginManager = "margin-bottom: 20px;"; } else { $MarginManager = "margin-bottom: 0px;"; } + + $data[] = array( + "key" => $row['key'], + "gendate" => '
', + "genby" => $row['genby'], + "expires" => ($row["expires"] / 86400) . ' Day(s)', + "note" => $row['note'] ?? 'N/A', + "usedon" => (!is_null($row["usedon"])) ? '
' : 'N/A', + "usedby" => ($row["usedby"] == $row['key']) ? 'Same as key' : $row["usedby"] ?? 'N/A', + "status" => '', + "actions" => '
', + ); + } + + ## Response + $response = array( + "draw" => intval($draw), + "iTotalRecords" => $totalRecords, + "iTotalDisplayRecords" => $totalRecordwithFilter, + "aaData" => $data + ); + + die(json_encode($response)); } die("Request not from datatables, aborted."); diff --git a/app/log-fetch.php b/app/log-fetch.php index f89fc052..fde22b47 100644 --- a/app/log-fetch.php +++ b/app/log-fetch.php @@ -1,75 +1,74 @@ getMessage()); -}); - if (session_status() === PHP_SESSION_NONE) { - session_start(); + session_start(); } -if ($_SESSION['role'] == "Reseller") { - die("Resellers can't access this."); +if($_SESSION['role'] == "Reseller") { + die("Resellers can't access this."); } -if (!isset($_SESSION['app'])) { - dashboard\primary\error("Application not selected"); - die("Application not selected."); +if(!isset($_SESSION['app'])) { + die("Application not selected."); } -if (isset($_POST['draw'])) { - - // credits to https://makitweb.com/datatables-ajax-pagination-with-search-and-sort-php/ - - $draw = intval($_POST['draw']); - $row = intval($_POST['start']); - $rowperpage = intval($_POST['length']); // Rows display per page - $columnIndex = misc\etc\sanitize($_POST['order'][0]['column']); // Column index - $columnName = misc\etc\sanitize($_POST['columns'][$columnIndex]['data']); // Column name - $columnSortOrder = misc\etc\sanitize($_POST['order'][0]['dir']); // asc or desc - $searchValue = misc\etc\sanitize($_POST['search']['value']); // Search value - - // whitelist certain column names and sort orders to prevent SQL injection - if (!in_array($columnName, array("logdate", "logdata", "credential", "pcuser"))) { - die("Column name is not whitelisted."); - } - - if (!in_array($columnSortOrder, array("desc", "asc"))) { - die("Column sort order is not whitelisted."); - } - - if (!is_null($searchValue)) { - $query = misc\mysql\query("select * from `logs` WHERE (`logdata` like ? or `credential` like ? or `pcuser` like ? ) and logapp = ? order by `" . $columnName . "` " . $columnSortOrder . " limit " . $row . "," . $rowperpage, ["%" . $searchValue . "%", "%" . $searchValue . "%", "%" . $searchValue . "%", $_SESSION['app']]); - } - else { - $query = misc\mysql\query("select * from `logs` WHERE logapp = ? order by `" . $columnName . "` " . $columnSortOrder . " limit " . $row . "," . $rowperpage, [$_SESSION['app']]); - } - - $data = array(); - - while ($row = mysqli_fetch_assoc($query->result)) { - $data[] = array( - "logdate" => '
', - "logdata" => $row['logdata'], - "credential" => $row['credential'] ?? 'N/A', - "pcuser" => $row['pcuser'] ?? 'N/A', - ); - } - - ## Response - $response = array( - "draw" => intval($draw), - "aaData" => $data - ); +if(isset($_POST['draw']) ) { + + // credits to https://makitweb.com/datatables-ajax-pagination-with-search-and-sort-php/ + + $draw = misc\etc\sanitize($_POST['draw']); + $row = misc\etc\sanitize($_POST['start']); + $rowperpage = misc\etc\sanitize($_POST['length']); // Rows display per page + $columnIndex = misc\etc\sanitize($_POST['order'][0]['column']); // Column index + $columnName = misc\etc\sanitize($_POST['columns'][$columnIndex]['data']); // Column name + $columnSortOrder = misc\etc\sanitize($_POST['order'][0]['dir']); // asc or desc + $searchValue = misc\etc\sanitize($_POST['search']['value']); // Search value + + ## Search + $searchQuery = " "; + if($searchValue != ''){ + $searchQuery = " and (`logdata` like '%".$searchValue."%' or + `credential` like '%".$searchValue."%' or + `pcuser` like'%".$searchValue."%' ) "; + } + + ## Total number of records without filtering + $sel = mysqli_query($link,"select count(1) as allcount from `logs` where logapp = '".$_SESSION['app']."'"); + $records = mysqli_fetch_assoc($sel); + $totalRecords = $records['allcount']; + + ## Total number of record with filtering + $sel = mysqli_query($link,"select count(1) as allcount from `logs` WHERE 1 ".$searchQuery." and logapp = '".$_SESSION['app']."'"); + $records = mysqli_fetch_assoc($sel); + $totalRecordwithFilter = $records['allcount']; + + ## Fetch records + $empQuery = "select * from `logs` WHERE 1 ".$searchQuery." and logapp = '".$_SESSION['app']."' order by `".$columnName."` ".$columnSortOrder." limit ".$row.",".$rowperpage; + // echo $empQuery; + $empRecords = mysqli_query($link, $empQuery); + $data = array(); + + while ($row = mysqli_fetch_assoc($empRecords)) { + $data[] = array( + "logdate"=>'
', + "logdata"=>$row['logdata'], + "credential"=>$row['credential'] ?? 'N/A', + "pcuser"=>$row['pcuser'] ?? 'N/A', + ); + } + + ## Response + $response = array( + "draw" => intval($draw), + "iTotalRecords" => $totalRecords, + "iTotalDisplayRecords" => $totalRecordwithFilter, + "aaData" => $data + ); + + die(json_encode($response)); - die(json_encode($response)); } -die("Request not from datatables, aborted."); +die("Request not from datatables, aborted."); \ No newline at end of file diff --git a/app/pages/account-logs.php b/app/pages/account-logs.php index 2f9dde55..ca03282b 100644 --- a/app/pages/account-logs.php +++ b/app/pages/account-logs.php @@ -1,53 +1,60 @@ -
-
-
- -

Account Logs

-

View the event history of your account.

-
-
- -
- - - - - - - - - - result)) - { - $rows[] = $r; - } - - foreach ($rows as $row) - { - ?> - - - - - - - - -
DateIPUser-Agent
- -
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
DateIP AddressUser Agent
+ +
+ +
+ \ No newline at end of file diff --git a/app/pages/account-settings.php b/app/pages/account-settings.php index 3c0f7ec0..dadb1c0c 100644 --- a/app/pages/account-settings.php +++ b/app/pages/account-settings.php @@ -1,494 +1,458 @@ that's the only thing you need on this page."); } - $twofactor = $row['twofactor']; - require_once '../auth/GoogleAuthenticator.php'; $gauth = new GoogleAuthenticator(); -if ($row["googleAuthCode"] == NULL) -{ +if ($row["googleAuthCode"] == NULL) { $code_2factor = $gauth->createSecret(); - misc\mysql\query("UPDATE `accounts` SET `googleAuthCode` = ? WHERE `username` = ?", [$code_2factor, $_SESSION['username']]); -} -else -{ + $integrate_code = mysqli_query($link, "UPDATE `accounts` SET `googleAuthCode` = '$code_2factor' WHERE `username` = '" . $_SESSION['username'] . "'") or die(mysqli_error($link)); +} else { $code_2factor = $row["googleAuthCode"]; } - $google_QR_Code = $gauth->getQRCodeGoogleUrl($_SESSION['username'], $code_2factor, 'KeyAuth'); +?> + -$query = misc\mysql\query("SELECT * FROM `accounts` WHERE `username` = ?", [$_SESSION['username']]); -if ($query->num_rows > 0) -{ - while ($row = mysqli_fetch_array($query->result)) - { - $acclogs = $row['acclogs']; - $expiry = $row["expires"]; - $emailVerify = $row["emailVerify"]; + +
+ + + + 0) { + while ($row = mysqli_fetch_array($result)) { + $acclogs = $row['acclogs']; + $expiry = $row["expires"]; + $emailVerify = $row["emailVerify"]; + } } -} -if (isset($_POST['updatesettings'])) - { + if (isset($_POST['updatesettings'])) { $pfp = misc\etc\sanitize($_POST['pfp']); $acclogs = misc\etc\sanitize($_POST['acclogs']); $emailVerify = misc\etc\sanitize($_POST['emailVerify']); - misc\mysql\query("UPDATE `accounts` SET `acclogs` = ? WHERE `username` = ?", [$acclogs, $_SESSION['username']]); - - if ($acclogs == 0) - { - misc\mysql\query("DELETE FROM `acclogs` WHERE `username` = ?", [$_SESSION['username']]); // delete all account logs + mysqli_query($link, "UPDATE `accounts` SET `acclogs` = '$acclogs' WHERE `username` = '" . $_SESSION['username'] . "'"); + if ($acclogs == 0) { + mysqli_query($link, "DELETE FROM `acclogs` WHERE `username` = '" . $_SESSION['username'] . "'"); // delete all account logs } - - misc\mysql\query("UPDATE `accounts` SET `emailVerify` = ? WHERE `username` = ?", [$emailVerify, $_SESSION['username']]); - if (isset($_POST['pfp']) && trim($_POST['pfp']) != '') - { + mysqli_query($link, "UPDATE `accounts` SET `emailVerify` = '$emailVerify' WHERE `username` = '" . $_SESSION['username'] . "'"); + if (isset($_POST['pfp']) && trim($_POST['pfp']) != '') { if (!filter_var($pfp, FILTER_VALIDATE_URL)) { dashboard\primary\error("Invalid Url For Profile Image!"); - echo ""; - return; - } - if (strpos($pfp, "file:///") !== false) { - dashboard\primary\error("Url must start with https://"); - echo ""; return; } $_SESSION['img'] = $pfp; - misc\mysql\query("UPDATE `accounts` SET `img` = ? WHERE `username` = ?", [$pfp, $_SESSION['username']]); + mysqli_query($link, "UPDATE `accounts` SET `img` = '$pfp' WHERE `username` = '" . $_SESSION['username'] . "'"); } dashboard\primary\success("Updated Account Settings!"); } - if (isset($_POST['submit_code'])) - { - $code = misc\etc\sanitize($_POST['scan_code1'] . ($_POST['scan_code2']) . ($_POST['scan_code3']) . ($_POST['scan_code4']) . ($_POST['scan_code5']) . ($_POST['scan_code6'])); + if (isset($_POST['submit_code'])) { - $query = misc\mysql\query("SELECT `googleAuthCode` from `accounts` WHERE `username` = ?", [$_SESSION['username']]); + if (empty($_POST['scan_code'])) { + dashboard\primary\error("You must fill in all the fields!"); + } + + $code = misc\etc\sanitize($_POST['scan_code']); + + $user_result = mysqli_query($link, "SELECT * from `accounts` WHERE `username` = '" . $_SESSION['username'] . "'") or die(mysqli_error($link)); + + while ($row = mysqli_fetch_array($user_result)) { - while ($row = mysqli_fetch_array($query->result)) - { $secret_code = $row['googleAuthCode']; } $checkResult = $gauth->verifyCode($secret_code, $code, 2); - if ($checkResult) - { - $query = misc\mysql\query("UPDATE `accounts` SET `twofactor` = '1' WHERE `username` = ?", [$_SESSION['username']]); - if ($query->affected_rows > 0) - { - echo ""; + if ($checkResult) { + $enable_2factor = mysqli_query($link, "UPDATE `accounts` SET `twofactor` = '1' WHERE `username` = '" . $_SESSION['username'] . "'") or die(mysqli_error($link)); + if ($enable_2factor) { dashboard\primary\success("Two-factor security has been successfully activated on your account!"); - dashboard\primary\wh_log($logwebhook, "{$username} has enabled 2FA", $webhookun); - } - else - { - echo ""; - dashboard\primary\wh_log($logwebhook, "{$username} has disabled 2FA", $webhookun); - dashboard\primary\success("Two-factor security has been successfully disabled on your account!"); + } else { + dashboard\primary\error("There was a problem trying to activate security on your account!"); } - } - else - { - dashboard\primary\error("Invalid 2FA code! Make sure your device time settings are synced."); + } else { + dashboard\primary\error("The code entered is incorrect"); } } - if (isset($_POST['submit_code_disable'])) - { - $code = misc\etc\sanitize($_POST['scan_code1'] . ($_POST['scan_code2']) . ($_POST['scan_code2']) . ($_POST['scan_code3']) . ($_POST['scan_code4']) . ($_POST['scan_code5'])); + if (isset($_POST['submit_code_disable'])) { - $query = misc\mysql\query("SELECT `googleAuthCode` from `accounts` WHERE `username` = ?", [$_SESSION['username']]); + if (empty($_POST['scan_code'])) { + dashboard\primary\error("You must fill in all the fields!"); + } + + $code = misc\etc\sanitize($_POST['scan_code']); + + $user_result = mysqli_query($link, "SELECT * from `accounts` WHERE `username` = '" . $_SESSION['username'] . "'") or die(mysqli_error($link)); - while ($row = mysqli_fetch_array($query->result)) - { + while ($row = mysqli_fetch_array($user_result)) { $secret_code = $row['googleAuthCode']; } $checkResult = $gauth->verifyCode($secret_code, $code, 2); - if ($checkResult) - { - $query = misc\mysql\query("UPDATE `accounts` SET `twofactor` = '0', `googleAuthCode` = NULL WHERE `username` = ?", [$_SESSION['username']]); - - if ($query->affected_rows > 0) - { - dashboard\primary\success("Successfully disabled 2FA!"); - } - else - { - dashboard\primary\error("Failed to disable 2FA!"); + if ($checkResult) { + $enable_2factor = mysqli_query($link, "UPDATE `accounts` SET `twofactor` = '0' WHERE `username` = '" . $_SESSION['username'] . "'") or die(mysqli_error($link)); + + if ($enable_2factor) { + dashboard\primary\success("Two-factor security has been successfully disabled on your account!"); + } else { + dashboard\primary\error("There was a problem trying to activate security on your account!"); } - } - else - { - dashboard\primary\error("Invalid 2FA code! Make sure your device time settings are synced."); + } else { + dashboard\primary\error("The code entered is incorrect"); } } - if (isset($_POST['deleteWebauthn'])) - { - $name = misc\etc\sanitize($_POST['deleteWebauthn']); + ?> - $query = misc\mysql\query("DELETE FROM `securityKeys` WHERE `name` = ? AND `username` = ?", [$name, $_SESSION['username']]); +
- if ($query->affected_rows > 0) - { - $query = misc\mysql\query("SELECT 1 FROM `securityKeys` WHERE `username` = ?", [$_SESSION['username']]); - if ($query->num_rows == 0) - { - misc\mysql\query("UPDATE `accounts` SET `securityKey` = 0 WHERE `username` = ?", [$_SESSION['username']]); - } - dashboard\primary\success("Successfully deleted security key"); - } - else - { - dashboard\primary\error("Failed to delete security key!"); - } - } +
-?> +
+ +
+
+ +
+ + + +
+ + + +
+ +
+
+ +
+ + + +
+ + + +
+ +
+
+ +
+ + + +
+ + + +
+ +
+
-
-
-
- -

Account Settings

-

Manage your account.

-
-
-
-
- -
-
- - +
-
- - +
-
-
- -
+
+ +
+ + + +
+ +
Change password here + https://' . ($_SERVER['HTTP_HOST'] ?? $_SERVER['SERVER_NAME']) . '/forgot/'; ?> +
+ +
- -
- " - readonly> -
- - -
- Free Forever " - autocomplete="on" readonly> - - - - +
+ +
+ + + +
+ + + +
+
+
+ +
+ + + +
+ +
Change email here + https://' . ($_SERVER['HTTP_HOST'] ?? $_SERVER['SERVER_NAME']) . '/changeEmail/'; ?> +
+ +
- - -
- -
+
- - +
- Enable 2FA'; - } else { - echo 'Disable 2FA'; - } - ?> - - - - - Change Password - - - Change Email - - - Change Username - - - Delete Account - - - - - - -