From 0e0fb54eae7128e548a6fe003e6b3ccfbeee8152 Mon Sep 17 00:00:00 2001
From: Daniel Winzen
Date: Sat, 14 Dec 2019 20:59:04 +0100
Subject: [PATCH] Track quota usage and allow upgrading quotas
---
var/www/common.php | 117 +++++++++++++++++++++++++++++-
var/www/composer.json | 3 +-
var/www/find_old.php | 13 ++++
var/www/html/coinpayments_ipn.php | 44 +++++++++++
var/www/html/home.php | 64 +++++++++-------
var/www/html/index.php | 6 +-
var/www/html/login.php | 9 ++-
var/www/html/robots.txt | 3 +
var/www/html/upgrade.php | 70 ++++++++++++++++++
var/www/setup.php | 9 ++-
var/www/setup_chroot.sh | 2 +-
11 files changed, 300 insertions(+), 40 deletions(-)
create mode 100644 var/www/html/coinpayments_ipn.php
create mode 100644 var/www/html/robots.txt
create mode 100644 var/www/html/upgrade.php
diff --git a/var/www/common.php b/var/www/common.php
index 72bc793..bb1d5c3 100644
--- a/var/www/common.php
+++ b/var/www/common.php
@@ -5,7 +5,7 @@ const DBUSER='hosting'; // Database user
const DBPASS='MY_PASSWORD'; // Database password
const DBNAME='hosting'; // Database
const PERSISTENT=true; // Use persistent database conection true/false
-const DBVERSION=16; //database layout version
+const DBVERSION=17; //database layout version
const CAPTCHA=1; // Captcha difficulty (0=off, 1=simple, 2=moderate, 3=extreme)
const ADDRESS='dhosting4xxoydyaivckq7tsmtgi4wfs3flpeyitekkmqwu4v4r46syd.onion'; // our own address
const CANONICAL_URL='https://hosting.danwin1210.me'; // our preferred domain for search engines
@@ -24,7 +24,7 @@ const INDEX_MD5S=[ //MD5 sums of index.hosting.html files that should be considd
const REQUIRE_APPROVAL=false; //require admin approval of new sites? true/false
const ENABLE_SHELL_ACCESS=true; //allows users to login via ssh, when disabled only (s)ftp is allowed - run setup.php to migrate existing accounts
const ADMIN_PASSWORD='MY_PASSWORD'; //password for admin interface
-const SERVICE_INSTANCES=['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's']; //one character per instance - run multiple tor+php-fpm instances for load balancing, remove all but one instance if you expect less than 200 accounts. - run setup.php after change
+const SERVICE_INSTANCES=['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's']; //one character per instance - run multiple tor+php-fpm instances for load balancing, remove all but one instance if you expect less than 200 accounts. If tor starts using 100% cpu and failing circuits every few hours after a restart, add more instances. In my experience this happens around 250 hidden services per instance - run setup.php after change
const DISABLED_PHP_VERSIONS=[]; //php versions still installed on the system but no longer offered for new accounts
const PHP_VERSIONS=[3 => '7.2', 4 => '7.3', 5 => '7.4']; //currently active php versions
const DEFAULT_PHP_VERSION='7.3'; //default php version
@@ -116,9 +116,20 @@ const MAX_NUM_USER_DBS = 5; //maximum number of databases a user may have
const MAX_NUM_USER_ONIONS = 3; //maximum number of onion domains a user may have
const MAX_NUM_USER_DOMAINS = 3; //maximum number of clearnet domains a user may have
const SKIP_USER_CHROOT_UPDATE = true; //skips updating user chroots when running setup.php
-const DEFAULT_QUOTA_SIZE = 10 * 1024 * 1024; //per user disk quota in kb - Defaults to 10 GB
+const DEFAULT_QUOTA_SIZE = 1024 * 1024; //per user disk quota in kb - Defaults to 1 GB
const DEFAULT_QUOTA_FILES = 100000; //per user file quota - by default allow no more than 100000 files
const NUM_GUARDS = 50; //number of tor guard relays to distribute the load on
+//Optional paid upgrades in format of 'identifier' => ['name', 'usd_price']
+const ACCOUNT_UPGRADES = [
+ '1g_quota' => ['name' => '+1GB disk Quota', 'usd_price' => 10],
+ '5g_quota' => ['name' => '+5GB disk Quota', 'usd_price' => 20],
+ '10g_quota' => ['name' => '+10GB disk Quota', 'usd_price' => 30],
+ '20g_quota' => ['name' => '+20GB disk Quota', 'usd_price' => 40],
+];
+const COINPAYMENTS_PRIVATE = 'COINPAYMENTS_PRIVATE_API_KEY';
+const COINPAYMENTS_PUBLIC = 'COINPAYMENTS_PUBLIC_API_KEY';
+const COINPAYMENTS_MERCHANT_ID = 'COINPAYMENTS_MERCHANT_ID';
+const COINPAYMENTS_IPN_SECRET = 'COINPAYMENTS_IPN_SECRET';
function get_onion_v2($pkey) : string {
$keyData = openssl_pkey_get_details($pkey);
@@ -751,3 +762,103 @@ function get_db_instance(){
}
return $db;
}
+
+function coinpayments_create_transaction(string $currency, int $price, string $payment_for, $user_id = null){
+ $query=[];
+ $query['currency1'] = 'USD';
+ $query['currency2'] = $currency;
+ $query['amount'] = $price;
+ $query['buyer_email'] = 'daniel@danwin1210.me';
+ $query['version'] = '1';
+ $query['cmd'] = 'create_transaction';
+ $query['key'] = COINPAYMENTS_PUBLIC;
+ $query['format'] = 'json';
+ $query_string = http_build_query( $query );
+ $hmac = hash_hmac( 'sha512', $query_string, COINPAYMENTS_PRIVATE );
+
+ $ch = curl_init();
+ curl_setopt( $ch, CURLOPT_POSTFIELDS, $query_string );
+ curl_setopt( $ch, CURLOPT_HTTPHEADER, ["HMAC: $hmac", 'Content-type: application/x-www-form-urlencoded'] );
+ curl_setopt( $ch, CURLOPT_RETURNTRANSFER, true );
+ curl_setopt( $ch, CURLOPT_URL, 'https://www.coinpayments.net/api.php' );
+ $result = curl_exec( $ch );
+ if( !$result ) {
+ return false;
+ }
+ $json = json_decode( $result, true );
+ if( !$json ){
+ return false;
+ }
+ if( $json['error'] !== 'ok' ) {
+ return false;
+ }
+ $db = get_db_instance();
+ $stmt = $db->prepare('INSERT INTO payments (user_id, payment_for, txn_id, status) VALUES (?, ?, ?, 0);');
+ $stmt->execute([$user_id, $payment_for, $json['result']['txn_id']]);
+ return $json['result'];
+}
+
+function coinpayments_get_rates(){
+ $query=[];
+ $query['accepted'] = '1';
+ $query['short'] = '0';
+ $query['version'] = '1';
+ $query['cmd'] = 'rates';
+ $query['key'] = COINPAYMENTS_PUBLIC;
+ $query['format'] = 'json';
+ $query_string = http_build_query( $query );
+ $hmac = hash_hmac( 'sha512', $query_string, COINPAYMENTS_PRIVATE );
+
+ $ch = curl_init();
+ curl_setopt( $ch, CURLOPT_POSTFIELDS, $query_string );
+ curl_setopt( $ch, CURLOPT_HTTPHEADER, ["HMAC: $hmac", 'Content-type: application/x-www-form-urlencoded'] );
+ curl_setopt( $ch, CURLOPT_RETURNTRANSFER, true );
+ curl_setopt( $ch, CURLOPT_URL, 'https://www.coinpayments.net/api.php' );
+ $result = curl_exec( $ch );
+ if( !$result ) {
+ return false;
+ }
+ $json = json_decode( $result, true );
+ if( !$json ){
+ return false;
+ }
+ if( $json['error'] !== 'ok' ) {
+ return false;
+ }
+ return $json['result'];
+}
+
+function payment_status_update(string $txid){
+ $db = get_db_instance();
+ $stmt = $db->prepare('SELECT * FROM payments WHERE txn_id = ?;');
+ $stmt->execute([$txid]);
+ while($tmp = $stmt->fetch(PDO::FETCH_ASSOC)){
+ if($tmp['status'] == '2'){
+ switch($tmp['payment_for']){
+ case '1g_quota':
+ add_disk_quota($tmp['user_id'], 1024 * 1024);
+ break;
+ case '5g_quota':
+ add_disk_quota($tmp['user_id'], 5 * 1024 * 1024);
+ break;
+ case '10g_quota':
+ add_disk_quota($tmp['user_id'], 10 * 1024 * 1024);
+ break;
+ case '20g_quota':
+ add_disk_quota($tmp['user_id'], 20 * 1024 * 1024);
+ break;
+ default:
+ break;
+ }
+ }
+ }
+}
+
+function add_disk_quota(int $user_id, int $kb){
+ $db = get_db_instance();
+ $stmt = $db->prepare('SELECT quota_size FROM disk_quota WHERE user_id = ?;');
+ $stmt->execute([$user_id]);
+ $tmp = $stmt->fetch(PDO::FETCH_ASSOC);
+ $stmt = $db->prepare('UPDATE disk_quota SET quota_size = ?, updated = 1 WHERE user_id = ?;');
+ $stmt->execute([$tmp['quota_size'] + $kb, $user_id]);
+}
diff --git a/var/www/composer.json b/var/www/composer.json
index f2de8bb..f0d68dd 100644
--- a/var/www/composer.json
+++ b/var/www/composer.json
@@ -1,5 +1,6 @@
{
"require": {
- "paragonie/sodium_compat": "^1.11"
+ "paragonie/sodium_compat": "^1.11",
+ "chillerlan/php-qrcode": "^3.1"
}
}
diff --git a/var/www/find_old.php b/var/www/find_old.php
index 4b0ab35..e2fa4f7 100644
--- a/var/www/find_old.php
+++ b/var/www/find_old.php
@@ -2,6 +2,19 @@
include('common.php');
$db = get_db_instance();
+//update quota usage
+$stmt=$db->query('SELECT id, system_account FROM users WHERE id NOT IN (SELECT user_id FROM new_account) AND todelete!=1;');
+$update=$db->prepare('UPDATE disk_quota SET quota_size_used = ?, quota_files_used = ? WHERE user_id = ?;');
+while($tmp=$stmt->fetch(PDO::FETCH_NUM)){
+ $quota = shell_exec('quota -pu ' . escapeshellarg($tmp[1]));
+ $quota_array = explode("\n", $quota);
+ if(!empty($quota_array[2])){
+ $quota_size=(int) preg_replace('~^\s+[^\s]+\s+([^\s]+).*~', '$1', $quota_array[2]);
+ $quota_files=(int) preg_replace('~^\s+[^\s]+\s+[^\s]+\s+[^\s]+\s+[^\s]+\s+[^\s]+\s+([^\s]+).*~', '$1', $quota_array[2]);
+ $update->execute([$quota_size, $quota_files, $tmp[0]]);
+ }
+}
+
//delete tmp files older than 24 hours
$stmt=$db->query('SELECT system_account FROM users;');
$all=$stmt->fetchAll(PDO::FETCH_NUM);
diff --git a/var/www/html/coinpayments_ipn.php b/var/www/html/coinpayments_ipn.php
new file mode 100644
index 0000000..c589c88
--- /dev/null
+++ b/var/www/html/coinpayments_ipn.php
@@ -0,0 +1,44 @@
+ 0 && $_POST['status'] < 100){
+ $status = 1;
+}elseif($_POST['status'] >= 100){
+ $status = 2;
+}
+$stmt = $db->prepare('SELECT status FROM payments WHERE txn_id = ?;');
+$stmt->execute([$_POST['txn_id']]);
+if($tmp = $stmt->fetch(PDO::FETCH_ASSOC)){
+ if($status != $tmp['status']){
+ $stmt = $db->prepare('UPDATE payments SET status = ? WHERE txn_id = ?;');
+ $stmt->execute([$status, $_POST['txn_id']]);
+ payment_status_update($_POST['txn_id']);
+ }
+}
diff --git a/var/www/html/home.php b/var/www/html/home.php
index f90d85f..f674d5a 100644
--- a/var/www/html/home.php
+++ b/var/www/html/home.php
@@ -3,6 +3,7 @@ include('../common.php');
$db = get_db_instance();
session_start();
$user=check_login();
+header('Content-Type: text/html; charset=UTF-8');
if(isset($_POST['action']) && $_POST['action']==='add_db'){
if($error=check_csrf_error()){
die($error);
@@ -186,17 +187,18 @@ if(isset($_REQUEST['action']) && isset($_POST['domain']) && $_POST['action']==='
enqueue_instance_reload();
}
}
-
-header('Content-Type: text/html; charset=UTF-8');
-echo '';
-echo 'Daniel\'s Hosting - Dashboard ';
-echo ' ';
-echo ' ';
-echo ' ';
-echo ' ';
-echo '';
-echo '';
-echo "Logged in as $user[username] Logout | Change passwords | FileManager | Delete account
";
+?>
+
+Daniel's Hosting - Dashboard
+
+
+
+
+
+
+
+Logged in as Logout | Change passwords | FileManager | Delete account
+';
if($count_dbs
';
}
-echo 'Change MySQL password
';
-echo 'You can use PHPMyAdmin and Adminer for web based database administration.
';
-echo 'System Account ';
-echo '';
-echo 'Username Host FTP Port SFTP Port POP3 Port IMAP Port SMTP port ';
+?>
+Change MySQL password
+You can use PHPMyAdmin and Adminer for web based database administration.
+System Account
+
+Username Host FTP Port SFTP Port POP3 Port IMAP Port SMTP port
+$tmp){
echo "$user[system_account] $server $tmp[ftp] $tmp[sftp] $tmp[pop3] $tmp[imap] $tmp[smtp] ";
}
-echo '
';
-echo 'Change system account password
';
-echo 'You can use the FileManager for web based file management.
';
-echo 'Logs ';
-echo '';
-echo '';
+?>
+
+Change system account password
+You can use the FileManager for web based file management.
+prepare('SELECT quota_size, quota_size_used FROM disk_quota WHERE user_id = ?;');
+$stmt->execute([$user['id']]);
+$quota = $stmt->fetch(PDO::FETCH_ASSOC);
+$quota_usage = $quota['quota_size_used'] / $quota['quota_size'];
+?>
+Your disk usage: % - % (updated hourly) Upgrade
+Logs
+
+
diff --git a/var/www/html/index.php b/var/www/html/index.php
index ce3110f..58dbf26 100644
--- a/var/www/html/index.php
+++ b/var/www/html/index.php
@@ -22,9 +22,9 @@ header('X-Accel-Expires: 60');
MariaDB (MySQL) database support
PHPMyAdmin and Adminer for web based database administration
Web-based file manager
-FTP access
-SFTP access
-10GB disk quota and a maximum of 100.000 files. If you need more, just contact me
+FTP and SFTP access
+command line access to shell via SSH
+1GB disk quota and a maximum of 100.000 files. - upgradable
mail() can send e-mails from your.onion@ (your.onion@hosting.danwin1210.me for clearnet) - not yet working but will return in future, use https://github.com/PHPMailer/PHPMailer or similar for now
Webmail and IMAP, POP3 and SMTP access to your mail account
Mail sent to anything@your.onion gets automatically redirected to your inbox
diff --git a/var/www/html/login.php b/var/www/html/login.php
index b3ac3c2..241f9f4 100644
--- a/var/www/html/login.php
+++ b/var/www/html/login.php
@@ -73,7 +73,8 @@ if(isset($_POST['username'])){
echo '" required autofocus>';
echo 'Password ';
send_captcha();
-echo ' ';
-echo '';
-echo 'If you disabled cookies, please re-enable them. You can\'t log in without!
';
-echo '