Mercurial > Pritunl-Fake-API
diff www/index.php @ 0:b51518614818 default tip
New Files
author | Pluto <meokcin@gmail.com> |
---|---|
date | Tue, 03 Sep 2024 15:57:25 +0800 |
parents | |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/www/index.php Tue Sep 03 15:57:25 2024 +0800 @@ -0,0 +1,187 @@ +<?php +// Author: simonmicro 2023 + +// Config +$minVersionNumber = 1003235044068; +$minVersionName = '1.32.3504.68'; +$minVersionIgnored = false; // use this to ignore the min version check - used for the public endpoint to avoid breaking too many clients at once +$licenseCosts = 42; // insert here any price you want - "0" is a special value, which also breaks the UI ;) + +header('Access-Control-Allow-Origin: *'); //Allow access from everywhere... +$code = 200; // Assuming everything is fine for now + +// Check if a ".ignoreMinVersion" file exists +if(!$minVersionIgnored && file_exists('.ignoreMinVersion')) { + $minVersionIgnored = true; // If so, we ignore the min version check +} + +// Parse body (if possible) +$body = json_decode(file_get_contents('php://input')); +$clientVersion = isset($body->version) ? $body->version : null; + +// Fake API +$result = null; +if (version_compare(PHP_VERSION, '8.0.0', '<')) { + $result = array('error_msg' => 'This API only supports PHP 8 or higher.'); + $code = 500; +} else if(isset($_GET['path'])) { + $path = trim($_GET['path'], ' /'); + $pathParts = explode('/', $path); + if(count($pathParts) > 0 && $pathParts[0] == 'healthz') { + $result = 'OK'; + } else if(count($pathParts) > 0 && $pathParts[0] == 'notification') { + // Any notification/[version] will be answered here + $msg = 'Fake API endpoint for v' . $minVersionName . ' active and reachable (contacted at ' . date('r') . ').'; + if(intval($pathParts[1]) < $minVersionNumber) { + $msg .= ' Please update your Pritunl instance to a newer version as this endpoint may not compatible anymore.'; + } + $result = array( + 'message' => $msg, + 'vpn' => false, // idk + 'www' => false // idk + ); + } else if(count($pathParts) > 0 && $pathParts[0] == 'auth') { + $result = array('error_msg' => 'Sorry, but SSO is currently not supported.'); + $code = 401; // Let Pritunl fail, without 500 codes (it will show 405) + } else if(count($pathParts) > 0 && $pathParts[0] == 'ykwyhd') { + // The "you-know-what-you-have-done" endpoint -> used as dummy url target + $result = array('detail' => 'You know what you have done.'); + } else if(!$minVersionIgnored && $clientVersion != null && $clientVersion < $minVersionNumber) { + // Check if the instance is too old for us (for now following operators) + $result = array('error_msg' => 'This API supports v' . $minVersionName . ' (' . $minVersionNumber . ') or higher.'); + $code = 473; + } else if(count($pathParts) > 0 && $pathParts[0] == 'subscription') { + // The following only works with the body containing the desired license + if(isset($body->license)) { + $license = null; + $user = md5(base64_encode($body->license)); + $url_key = substr($user, 0, 8); + $input = strtolower($body->license); + + // The stylesheet determines what is shown on the dashboard (and by the plan). + $stylesheet = ''; + if(str_contains($input, 'premium')) { + $license = 'premium'; + $stylesheet = file_get_contents('premium.css'); + // No need to install the user license "id" into CSS class, as that file only contains custom patches + } else if(str_contains($input, 'enterprise')) { + $license = 'enterprise'; + $stylesheet = file_get_contents('enterprise.css'); + $stylesheet = preg_replace('/(\.enterprise)([\.\ ])/', '$1-'.$url_key.'$2', $stylesheet); // Install user license "id" into CSS class + } else if(str_contains($input, 'ultimate')) { + $license = 'enterprise_plus'; + $stylesheet = file_get_contents('enterprise_plus.css'); + $stylesheet = preg_replace('/(\.enterprise-plus)([\.\ ])/', '$1-'.$url_key.'$2', $stylesheet); // Install user license "id" into CSS class + } + $stylesheet .= "\n/* custom.css */\n"; + $stylesheet .= str_replace('BACKGROUND_IMAGE_URI', "https://" . $_SERVER['HTTP_HOST'] . "/logo.png", file_get_contents('custom.css')); + $stylesheet .= "\n/* Generated for $license license */"; + + $state = null; + if($license) { // The following only makes sense if you selected any license + if(str_starts_with($input, 'bad')) { + $state = 'Bad'; + } else if(str_starts_with($input, 'canceled')) { + $state = 'canceled'; + } else if(str_starts_with($input, 'active')) { + $state = 'Active'; + } + } + + if($state == 'Active') { + $result = array( + 'active' => true, // if the sub is not active, the css won't use the LICENSE-subscription_id pattern + 'status' => $state, + 'plan' => $license, + 'url_key' => $user, + 'quantity' => 42, + 'amount' => $licenseCosts, + 'credit' => 42, + 'period_end' => false, + 'trial_end' => false, + 'cancel_at_period_end' => false, + 'premium_buy_url' => 'https://' . $_SERVER['HTTP_HOST'] . '/ykwyhd/', + 'enterprise_buy_url' => 'https://' . $_SERVER['HTTP_HOST'] . '/ykwyhd/', + 'portal_url' => 'https://' . $_SERVER['HTTP_HOST'] . '/ykwyhd/', + 'styles' => array( + 'etag' => null, // the resource is NOT encrypted + 'last_modified' => time(), + 'data' => $stylesheet + ) + ); + } else if($state == 'Canceled') { + $result = array( + 'active' => false, // Here we can savely disable any style + 'status' => $state, + 'plan' => $license, + 'quantity' => 42, + 'amount' => 42, + 'period_end' => false, + 'trial_end' => false, + 'cancel_at_period_end' => false, + 'styles' => array( + 'etag' => null, + 'last_modified' => null, + 'data' => null + ) + ); + } else if($state == 'Bad' || $state == null) { + $code = 470; // -> bad license + // Do not mention "canceled" in "error_msg", as it is somewhat useless (same as bad)... + $result = array( + 'error' => 'license_invalid', + 'error_msg' => $state == null ? 'Unknown command. Use ["bad" | "active"] ["premium" | "enterprise" | "ultimate"].' : 'As you wish.', + 'active' => false, + 'status' => null, + 'plan' => null, + 'quantity' => null, + 'amount' => null, + 'period_end' => null, + 'trial_end' => null, + 'cancel_at_period_end' => null, + 'styles' => array( + 'etag' => null, + 'last_modified' => null, + 'data' => null + ) + ); + } + } else { + $result = array('error_msg' => 'Missing license in body.'); + $code = 401; + } + } else if(count($pathParts) > 0 && $pathParts[0] == 'checkout') { + $result = array( + 'zipCode' => false, + 'allowRememberMe' => false, + 'image' => 'https://' . $_SERVER['HTTP_HOST'] . '/logo.png', + 'key' => null, // Insert here a key to unlock the stripe store (is a string). And buy the subscription... + 'plans' => array( + 'premium' => array( + 'amount' => $licenseCosts + ), + 'enterprise' => array( + 'amount' => $licenseCosts + ), + 'enterprise_plus' => array( + 'amount' => $licenseCosts + ) + ) + ); + } +} + +header('Content-Type: application/json'); +http_response_code($code); +echo json_encode($result); + +// Should we log any request? Used for the development and debugging of this API +if(false) { + // Log request + file_put_contents('access.log', "\n" . date('r') . ":\n" . json_encode(array('head' => getallheaders(), 'body' => file_get_contents('php://input'), 'get' => $_GET, 'post' => $_POST, 'answer_code' => $code, 'answer' => $result)) . "\n", FILE_APPEND); + + // GET operator to clear log file + if(isset($_GET['clear'])) + file_put_contents('access.log', ''); +} +?>