Compare commits

..

No commits in common. "3f7fa53eb37202e73fb366e1077feb27ffaefd35" and "446f9ba291b51df7f6b05f082db07711683de2b1" have entirely different histories.

14 changed files with 203 additions and 3951 deletions

View File

@ -26,11 +26,12 @@ Make sure to support the developers by buying the choosen subscription for your
This is _optional_. You can simply use the default instance of this API (host is noted inside the `setup.py` script) and profit from "automatic" updates. This is _optional_. You can simply use the default instance of this API (host is noted inside the `setup.py` script) and profit from "automatic" updates.
Just transfer the `www` files inside a public accessible root-folder on your _dedicated_ Apache webserver (really everthing with PHP support works). Also make sure your instance has a valid SSL-certificate (Let's encrypt is enough), otherwise it may won't work. Just transfer the `www` files inside a public accessible root-folder on your _dedicated_ Apache webserver (really everthing with PHP support works). Also make sure your instance has a valid SSL-certificate (Let's encrypt is enough), otherwise it may won't work.
An example Apache install process can be found [here](docs/apache/install.md). If you want to test your instance, just open the public accessible URI in your browser and append `/healthz` to it - if you see some JSON with the text, then everything worked! An example Apache install process can be found [here](docs/apache/install.md). If you want to test your instance, just open the public accessible URI in your browser and append `/notification` to it - if you see some JSON with the text, then everything worked!
### Nett2Know ### ### Nett2Know ###
* This modification will also block any communication to the Pritunl servers - so no calling home :) * This modification will also block any communication to the Pritunl servers - so no calling home :)
* SSO will not work with this api version! As Pritunls own authentication servers handle the whole SSO stuff, track instance ids and verify users, I won't implement this part for privacy concerns (and also this would need to be securly implemented and a database). * The `ultimate` mode is still a little bit buggy. This is caused by some hacky workarounds to get all features displayed (the server is already unlocked). Caused by this workaround some items are maybe shown instead of being hidden. If you find such thing - just ping me about it.
* SSO will not work with this api version! As Pritunls own authentication servers handle the whole SSO stuff, track instance ids and verify users I won't implement this part for privacy concerns (and also this would need to be securly implemented and need a database).
* This api has also its own docker image. Take a look into the `docker` folder and enjoy! * This api has also its own docker image. Take a look into the `docker` folder and enjoy!
Have fun with your new premium/enterprise/ultimate Pritunl instance! Have fun with your new premium/enterprise/ultimate Pritunl instance!

View File

@ -1 +0,0 @@
mongodb

1
docker/.gitignore vendored
View File

@ -1,2 +1 @@
setup.py setup.py
mongodb

View File

@ -3,4 +3,6 @@ FROM goofball222/pritunl:latest
# Yes, you will need to copy it over into the build context... # Yes, you will need to copy it over into the build context...
COPY setup.py . COPY setup.py .
RUN chmod +x setup.py; python3 -u setup.py --install; rm setup.py RUN chmod +x setup.py
RUN python3 -u setup.py --install
#RUN rm setup.py

View File

@ -7,10 +7,9 @@ services:
- ./mongodb:/data/db - ./mongodb:/data/db
pritunl: pritunl:
# Use the following to build the image from source (assuming you're running inside the repository). # Use the following to build the image from source.
build: build:
context: ../server context: .
dockerfile: ../docker/Dockerfile
restart: always restart: always
depends_on: depends_on:
- mongodb - mongodb

View File

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:d43025688bf8e6ddfa1234615e538005af6032c4fe5c3d72b6902eefaa035173
size 5095831

View File

@ -1,4 +1,4 @@
#!/usr/bin/env python3 #!/usr/lib/python3
import os import os
import glob import glob
import time import time

View File

@ -1,50 +0,0 @@
* {
color: rgb(57, 83, 120);
}
.dark * {
color: rgb(220, 232, 232);
}
.navbar .navbar-brand {
animation-name: pritunl-logo;
animation-duration: 20s;
animation-iteration-count: infinite;
}
@keyframes pritunl-logo {
0% {
transform: rotate3d(1, 0, 0, 360deg);
}
25% {
transform: rotate3d(1, 0, 0, 0deg);
}
50% {
transform: rotate3d(0, 1, 0, 0deg);
}
75% {
transform: rotate3d(0, 1, 0, 360deg);
}
100% {
transform: rotate3d(0, 1, 0, 360deg);
}
}
body::before {
position: fixed;
bottom: 0;
right: 0;
content: '';
background: url("BACKGROUND_IMAGE_URI");
background-size: contain;
background-repeat: no-repeat;
width: 10em;
height: 10em;
margin: 1em;
opacity: 0.1;
z-index: -99;
}

File diff suppressed because one or more lines are too long

4
www/enterprise_fix.css Normal file
View File

@ -0,0 +1,4 @@
/* Enable the display of the uids */
.users-list .users-list-title .org-id, .users-list .user .name-container .user-id, .servers-list .server .server-title .server-id, .servers-list .server .org .org-id, .servers-list .server .host .host-id, .servers-list .server .link .link-id {
display: inline-block;
}

File diff suppressed because one or more lines are too long

View File

@ -1,164 +1,123 @@
<?php <?php
// Author: simonmicro 2023 //Author: simonmicro 2022
// Config header("Access-Control-Allow-Origin: *"); //Allow access from everywhere...
$minVersionNumber = 1003235044068; $code = 200;
$minVersionName = '1.32.3504.68';
$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
//Parse body (if possible) //Parse body (if possible)
$body = json_decode(file_get_contents('php://input')); $body = json_decode(file_get_contents('php://input'));
$clientVersion = isset($body->version) ? $body->version : null;
//Fake API //Fake API
$result = null; $result = null;
if(isset($_GET['path'])) { if(isset($_GET['path'])) {
$path = trim($_GET['path'], ' /');
$pathParts = explode('/', $_GET['path']);
if(count($pathParts) > 0 && $pathParts[0] == 'healthz') {
$result = 'OK';
} else if(count($pathParts) > 1 && $pathParts[0] == 'notification') {
//Any notification/[version] will be answered here //Any notification/[version] will be answered here
$msg = 'Fake API endpoint for v' . $minVersionName . ' active and reachable (contacted at ' . date('r') . ').'; if(preg_match('/notification.*/', $_GET['path'])) {
if(intval($pathParts[1]) < $minVersionNumber) { $result = new stdClass;
$msg .= ' Please update your Pritunl instance to a newer version as this endpoint may not compatible anymore.'; $result->message = 'Fake API endpoint for v1.30.3116.68 active and reachable (contacted at ' . date('r') . ').';
} $result->vpn = false; //Idk
$result = array( $result->www = false; //Idk
'message' => $msg, } else if(isset($body->license) && preg_match('/subscription.*/', $_GET['path'])) {
'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($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 //The following only works with the body containing the desired license
if(isset($body->license)) { $result = new stdClass;
$license = null; $license = null;
$user = md5(base64_encode($body->license)); //The stylesheet determines what is shown on the dashboard (and by the plan). As default we change the colors of any text.
$url_key = substr($user, 0, 8);
$input = strtolower($body->license);
// The stylesheet determines what is shown on the dashboard (and by the plan).
$stylesheet = ''; $stylesheet = '';
if(str_contains($input, 'premium')) { if(preg_match('/.*premium/', $body->license)) {
$license = 'premium'; $license = 'premium';
$stylesheet = file_get_contents('premium.css'); } else if(preg_match('/.*enterprise/', $body->license)) {
// 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'; $license = 'enterprise';
$stylesheet = file_get_contents('enterprise.css'); $stylesheet .= file_get_contents('enterprise.css');
$stylesheet = preg_replace('/(\.enterprise)([\.\ ])/', '$1-'.$url_key.'$2', $stylesheet); // Install user license "id" into CSS class //Now fix some too aggressive display strategies by appending their overrides...
} else if(str_contains($input, 'ultimate')) { $stylesheet .= file_get_contents('enterprise_fix.css');
} else if(preg_match('/.*ultimate/', $body->license)) {
$license = 'enterprise_plus'; $license = 'enterprise_plus';
$stylesheet = file_get_contents('enterprise_plus.css'); //Load the new css file and change all invisible blocks to visible (this will show a little bit too much, but whatever...)
$stylesheet = preg_replace('/(\.enterprise-plus)([\.\ ])/', '$1-'.$url_key.'$2', $stylesheet); // Install user license "id" into CSS class $stylesheet .= file_get_contents('enterprise.css');
$stylesheet = preg_replace('/(enterprise)/', '$1-temp-prefix', $stylesheet);
$stylesheet = preg_replace('/(enterprise)(-temp-prefix-plus)/', '$1', $stylesheet);
$stylesheet = preg_replace('/(enterprise)(-temp-prefix)/', '$1-plus', $stylesheet);
$stylesheet = preg_replace('/(display:.?)none.?$/m', '$1inline-block', $stylesheet); //This WILL SHOW TOO MUCH... So we'll need a fix file...
$stylesheet .= file_get_contents('ultimate_fix.css');
} }
$stylesheet .= "\n/* custom.css */\n"; $stylesheet .= "* { color: rgb(57, 83, 120); }\n.dark * { color: rgb(200, 242, 242); }\n.navbar .navbar-brand { animation-name: pritunl-logo; animation-duration: 20s; animation-iteration-count: infinite; }\n@keyframes pritunl-logo { 0% { transform:rotate3d(1, 0, 0, 360deg); } 25% { transform:rotate3d(1, 0, 0, 0deg); } 50% { transform:rotate3d(0, 1, 0, 0deg); } 75% { transform:rotate3d(0, 1, 0, 360deg); } 100% { transform:rotate3d(0, 1, 0, 360deg); } }\n.footer-brand {visibility: hidden; }\n.footer-brand::before { visibility: visible; position: absolute; bottom: 0; right: 0; content: ''; background: url('https://" . $_SERVER['HTTP_HOST'] . "/logo.png'); background-size: cover; width: 1em; height: 1em; margin: 0.3em; }\n/* Generated for $license license */";
$stylesheet .= str_replace('BACKGROUND_IMAGE_URI', "https://" . $_SERVER['HTTP_HOST'] . "/logo.png", file_get_contents('custom.css'));
$stylesheet .= "\n/* Generated for $license license */"; # Workaround for 70b354a10df55d60515f76d851dee42939864395
if($body->version >= 1003031084050 and $body->version < 1003031164068)
$stylesheet = base64_encode($stylesheet);
$state = null; $state = null;
if($license) { //The following only makes sense if you selected any license if($license) { //The following only makes sense if you selected any license
if(str_starts_with($input, 'bad')) { if(strpos($body->license, 'bad') !== false) {
$state = 'Bad'; $state = 'Bad';
} else if(str_starts_with($input, 'canceled')) { } else if(strpos($body->license, 'canceled') !== false) {
$state = 'canceled'; $state = 'canceled';
} else if(str_starts_with($input, 'active')) { } else if(strpos($body->license, 'active') !== false) {
$state = 'Active'; $state = 'Active';
} }
} }
if($state == 'Active') { if($state == 'Active') {
$result = array( $result->active = $body->version < 1003031164068 ? $license != 'premium' : $license == 'enterprise_plus';
'active' => true, // if the sub is not active, the css won't use the LICENSE-subscription_id pattern $result->status = $state;
'status' => $state, $result->plan = $license;
'plan' => $license, $result->quantity = 42;
'url_key' => $user, $result->amount = 42;
'quantity' => 42, $result->credit = 42;
'amount' => $licenseCosts, $result->period_end = false;
'credit' => 42, $result->trial_end = false;
'period_end' => false, $result->cancel_at_period_end = false;
'trial_end' => false, $result->styles = new stdClass;
'cancel_at_period_end' => false, $result->styles->etag = 42;
'premium_buy_url' => 'https://' . $_SERVER['HTTP_HOST'] . '/ykwyhd/', $result->styles->last_modified = time();
'enterprise_buy_url' => 'https://' . $_SERVER['HTTP_HOST'] . '/ykwyhd/', $result->styles->data = $stylesheet;
'portal_url' => 'https://' . $_SERVER['HTTP_HOST'] . '/ykwyhd/', }
'styles' => array( if($state == 'Canceled') {
'etag' => null, // the resource is NOT encrypted $result->active = false; //Here we can savely disable any styles
'last_modified' => time(), $result->status = $state;
'data' => $stylesheet $result->plan = $license;
) $result->quantity = 42;
); $result->amount = 42;
} else if($state == 'Canceled') { $result->period_end = false;
$result = array( $result->trial_end = false;
'active' => false, // Here we can savely disable any style $result->cancel_at_period_end = false;
'status' => $state, $result->styles = new stdClass;
'plan' => $license, $result->styles->etag = 42;
'quantity' => 42, $result->styles->last_modified = time();
'amount' => 42, $result->styles->data = $stylesheet;
'period_end' => false, }
'trial_end' => false, if($state == 'Bad' || $state == null) {
'cancel_at_period_end' => false,
'styles' => array(
'etag' => null,
'last_modified' => null,
'data' => null
)
);
} else if($state == 'Bad' || $state == null) {
$code = 470; //-> bad license $code = 470; //-> bad license
// Do not mention "canceled" in "error_msg", as it is somewhat useless (same as bad)... $result->error_msg = 'As you wish.';
$result = array( $result->error = 'license_invalid';
'error' => 'license_invalid', $result->active = false;
'error_msg' => $state == null ? 'Unknown command. Use ["bad" | "active"] ["premium" | "enterprise" | "ultimate"].' : 'As you wish.', $result->status = false;
'active' => false, $result->plan = null;
'status' => null, $result->quantity = 0;
'plan' => null, $result->amount = 0;
'quantity' => null, $result->period_end = true;
'amount' => null, $result->trial_end = true;
'period_end' => null, $result->cancel_at_period_end = null;
'trial_end' => null, $result->styles = new stdClass;
'cancel_at_period_end' => null,
'styles' => array(
'etag' => null,
'last_modified' => null,
'data' => null
)
);
} }
} else { if($state == null) {
$result = array('error_msg' => 'Missing license in body.'); $result->error_msg = 'Unknown command. Use ["bad" | "canceled" | "active"] ["premium" | "enterprise" | "ultimate"].';
$code = 401;
} }
} else if(count($pathParts) > 0 && $pathParts[0] == 'checkout') { } else if(preg_match('/checkout.*/', $_GET['path'])) {
$result = array( $result = array();
'zipCode' => false, $result['zipCode'] = false;
'allowRememberMe' => false, $result['allowRememberMe'] = false;
'image' => 'https://' . $_SERVER['HTTP_HOST'] . '/logo.png', $result['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... $result['key'] = null; //Insert here a key to unlock the stripe store (is a string). And buy the subscription...
'plans' => array( $result['plans'] = array();
'premium' => array( $result['plans']['premium'] = array();
'amount' => $licenseCosts $result['plans']['premium']['amount'] = 42;
), $result['plans']['enterprise'] = array();
'enterprise' => array( $result['plans']['enterprise']['amount'] = 42;
'amount' => $licenseCosts $result['plans']['enterprise_plus'] = array();
), $result['plans']['enterprise_plus']['amount'] = 42;
'enterprise_plus' => array( } else if(preg_match('/auth\/.*/', $_GET['path'])) {
'amount' => $licenseCosts $result = array('error' => 'Sorry, but SSO is currently not supported.');
) $code = 401; //Let Pritunl fail, without 500 codes (it will show 405)
)
);
} }
} }
@ -169,7 +128,7 @@ echo json_encode($result);
//Should we log any request? Used for the development and debugging of this API //Should we log any request? Used for the development and debugging of this API
if(false) { if(false) {
//Log request //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); file_put_contents('access.log', "\n" . date('r') . ":\t" . 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 //GET operator to clear log file
if(isset($_GET['clear'])) if(isset($_GET['clear']))

View File

@ -1,12 +0,0 @@
/* Fixes for the premium subscription-modal, which seems to be empty / broken in recent versions */
.enterprise-modal .enterprise-info {
display: inherit;
}
.enterprise-modal .modal .enterprise-info .premium-plan {
display: inherit;
}
.enterprise-modal .enterprise-buttons {
display: inherit;
}

48
www/ultimate_fix.css Normal file
View File

@ -0,0 +1,48 @@
/* Fix the sub info */
.enterprise-modal .enterprise-info {
display: block;
}
.enterprise-modal .enterprise-buttons {
display: block;
}
/* And show the enterprise+ (our ultimate) plan */
.enterprise-modal .modal .enterprise-info .enterprise-plus-plan {
display: block;
}
/* @Servers Fix bad spacing? */
.servers-list .server .server-info .server-output-link-viewer {
display: none;
}
.servers-list .server .server-info .server-graph-viewer {
display: none;
}
/* @Servers Fix double shown IPs */
.enterprise-plus .server-routes-list .route .route-network-no-click {
display: none;
}
/* Fix wrongly shown NAT flag */
.enterprise-plus .server-routes-list .route .route-nat {
display: none;
}
.server-routes-list .route .route-nat {
display: none;
}
.server-routes-list .route .route-nat, .server-routes-list .route .route-nat-netmap, .server-routes-list .route .route-net-gateway, .server-routes-list .route .route-default, .server-routes-list .route .route-virtual-network, .server-routes-list .route .route-network-link, .server-routes-list .route .route-server-link, .server-routes-list .route .route-vpc-id {
display: none;
}
/* Fix selectors */
.selector .selector-inner {
display: none;
}
/* Remove second useless Theme selector in settings */
.enterprise-plus .settings-modal .right .form-group.theme {
display: none;
}
/* Hide advanced settings... So the button is useable again... */
.modal .modal-body .advanced {
display: none;
}
/* Hide admins tab, it will be shown only if the user is a super-user */
.nav .admins {
display: none;
}