diff --git a/var/www/common.php b/var/www/common.php index cc3c194..b0cfa91 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=17; //database layout version +const DBVERSION=18; //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 @@ -1034,3 +1034,70 @@ function sanitize_system_account(string $system_account){ } return $account; } + +function main_menu(string $current_site){ + echo '

'; + $sites = [ + 'index.php' => 'Info', + 'register.php' => 'Register', + 'login.php' => 'Login', + 'list.php' => 'List of hosted sites', + 'faq.php' => 'FAQ', + ]; + $first = true; + foreach($sites as $link => $name){ + if($first){ + $first = false; + if($link===$current_site){ + echo $name; + } else { + echo "$name"; + } + } else { + if($link===$current_site){ + echo " | $name"; + } else { + echo " | $name"; + } + } + } + echo '

'; +} + +function dashboard_menu(array $user, string $current_site){ + echo '

Logged in as ' . htmlspecialchars($user['username']); + $sites = [ + 'logout.php' => 'Logout', + 'home.php' => 'Dashboard', + 'pgp.php' => 'PGP 2FA', + 'password.php' => 'Change password', + 'files.php' => 'FileManager', + 'delete.php' => 'Delete account', + ]; + foreach($sites as $link => $name){ + if($link===$current_site){ + echo " | $name"; + } else { + echo " | $name"; + } + } + echo '

'; +} + +function print_header(string $sub_title, string $style = '', string $base_target = '_self'){ +?> + +<?php echo htmlspecialchars(SITE_NAME) . ' - ' . htmlspecialchars($sub_title); ?> + + + + +$style"; + } + echo ""; +?> + +'hosting_admin']); if($_SERVER['REQUEST_METHOD']==='HEAD'){ exit; // headers sent, no further processing needed } +print_header('Admin panel', 'td{padding:5px;}', '_blank'); ?> - -<?php echo htmlspecialchars(SITE_NAME); ?> - Admin panel - - - - - - -

Hosting - Admin panel

- -<?php echo htmlspecialchars(SITE_NAME); ?> - Delete account - - - - -

This will delete your account and all data asociated with it. It can't be un-done. Are you sure?

diff --git a/var/www/html/faq.php b/var/www/html/faq.php index 0f37f4d..c525b42 100644 --- a/var/www/html/faq.php +++ b/var/www/html/faq.php @@ -2,16 +2,10 @@ require('../common.php'); header('Content-Type: text/html; charset=UTF-8'); header('X-Accel-Expires: 60'); +print_header('FAQ'); ?> - -<?php echo htmlspecialchars(SITE_NAME); ?> - FAQ - - - - - -

Hosting - Info

-

Info | Register | Login | List of hosted sites | FAQ

+

Hosting - FAQ

+
diff --git a/var/www/html/files.php b/var/www/html/files.php index 56c93df..2e1e72f 100644 --- a/var/www/html/files.php +++ b/var/www/html/files.php @@ -274,17 +274,7 @@ if($sort==='M'){ if($order==='D'){ $list=array_reverse($list); } - -$dir=htmlspecialchars($dir); -?> - - - - - - -<?php echo htmlspecialchars(SITE_NAME); ?> - FileManager - Index of <?php echo $dir; ?> - - +.sh{min-width:22px; background:no-repeat url(data:img/gif;base64,R0lGODlhFAAWAPH/AAAAADMzM5mZmf///yH5BAUAAAQALAAAAAAUABYAAANgGLq89JCEQaudIb5pO88R11UiuFXAkJIXxAEwjAYATZ9UuuZxjPc7imAoAOBUyBHRKBk5hUzR01L8AXuVanPa0b6usWyU2x2rwDLokTzw8tDiNdnNVksCxLx+eIOg0Q8JADs=);}'; +print_header('FileManager - Index of '.$dir, $style); +$dir=htmlspecialchars($dir); +?>

Index of

Upload up to 1GB and up to 100 files at once


@@ -376,24 +367,15 @@ function get_properties($name, &$icon, &$size){ function send_not_found(){ header("HTTP/1.1 404 Not Found"); - echo ''; - echo '404 Not Found'; - echo ''; - echo ''; - echo ''; - echo ''; + print_header('FileManager - 404 Not Found'); echo '

The requested file '.htmlspecialchars($_REQUEST['path']).' was not found on your account.

'; echo '

Go back to home directory.

'; echo ''; } function send_login(){ + print_header('FileManager - Login'); ?> - -<?php echo htmlspecialchars(SITE_NAME); ?> - FileManager - Login - - -

Please type in your system account password:

Go back to dashboard.

@@ -437,11 +419,7 @@ function ftp_recursive_delete($ftp, $file){ } function send_rename($dir){ - echo ''; - echo '' . htmlspecialchars(SITE_NAME) . ' - FileManager - Rename file'; - echo ''; - echo ''; - echo ''; + print_header('FileManager - Rename file'); echo ''; echo ''; echo ''; @@ -456,11 +434,7 @@ function send_rename($dir){ } function send_edit($ftp, $dir){ - echo ''; - echo '' . htmlspecialchars(SITE_NAME) . ' - FileManager - Edit file'; - echo ''; - echo ''; - echo ''; + print_header('FileManager - Edit file'); echo ''; echo ''; echo ''; diff --git a/var/www/html/home.php b/var/www/html/home.php index a1aad65..c716d9a 100644 --- a/var/www/html/home.php +++ b/var/www/html/home.php @@ -12,14 +12,9 @@ if(isset($_POST['action']) && $_POST['action']==='add_db'){ if(isset($_POST['action']) && $_POST['action']==='del_db' && !empty($_POST['db'])){ if($error=check_csrf_error()){ die($error); - } ?> - -<?php echo htmlspecialchars(SITE_NAME); ?> - Delete database - - - - - + } + print_header('Delete database'); +?>

This will delete your database and all data asociated with it. It can't be un-done. Are you sure?

@@ -38,14 +33,9 @@ if(isset($_POST['action']) && $_POST['action']==='del_db_2' && !empty($_POST['db if(isset($_POST['action']) && $_POST['action']==='del_onion' && !empty($_POST['onion'])){ if($error=check_csrf_error()){ die($error); - } ?> - -<?php echo htmlspecialchars(SITE_NAME); ?> - Delete onion domain - - - - - + } + print_header('Delete onion domain'); +?>

This will delete your onion domain .onion and all data asociated with it. It can't be un-done. Are you sure?

@@ -119,14 +109,9 @@ if(isset($_POST['action']) && $_POST['action']==='add_domain' && !empty($_POST[' if(isset($_POST['action']) && $_POST['action']==='del_domain' && !empty($_POST['domain'])){ if($error=check_csrf_error()){ die($error); - } ?> - -<?php echo htmlspecialchars(SITE_NAME); ?> - Delete domain - - - - - + } + print_header('Delete domain'); +?>

This will delete your domain and all data asociated with it. It can't be un-done. Are you sure?

@@ -183,18 +168,8 @@ if(isset($_REQUEST['action']) && isset($_POST['domain']) && $_POST['action']===' enqueue_instance_reload(); } } -?> - -<?php echo htmlspecialchars(SITE_NAME); ?> - Dashboard - - - - - - - -

Logged in as Logout | Change passwords | FileManager | Delete account

- - -<?php echo htmlspecialchars(SITE_NAME); ?> - - - - -

Hosting - Info

-

Info | Register | Login | List of hosted sites | FAQ

+

Here you can get yourself a free web hosting account on my server.

What you get:

Rules

diff --git a/var/www/html/list.php b/var/www/html/list.php index 6b3ac89..ea29b2d 100644 --- a/var/www/html/list.php +++ b/var/www/html/list.php @@ -3,19 +3,11 @@ require_once('../common.php'); header('Content-Type: text/html; charset=UTF-8'); header('X-Accel-Expires: 60'); $db = get_db_instance(); +print_header('List of hosted sites', 'td{padding:5px;}', '_blank'); ?> - -<?php echo htmlspecialchars(SITE_NAME); ?> - List of hosted sites - - - - - - -

Hosting - List of hosted sites

-

Info | Register | Login | List of hosted sites | FAQ

query('SELECT COUNT(*) FROM users WHERE public=1;'); $count=$stmt->fetch(PDO::FETCH_NUM); $stmt=$db->query('SELECT COUNT(*) FROM users WHERE public=0;'); diff --git a/var/www/html/login.php b/var/www/html/login.php index 8532ee6..4691f0f 100644 --- a/var/www/html/login.php +++ b/var/www/html/login.php @@ -8,64 +8,117 @@ if(!empty($_SESSION['hosting_username']) && empty($_SESSION['2fa_code'])){ } $msg=''; $username=''; +$pgp_key=''; +$tfa=0; +if(!empty($_SESSION['hosting_username'])){ + $tfa = $_SESSION['tfa']; + $pgp_key = $_SESSION['pgp_key']; +} if($_SERVER['REQUEST_METHOD']==='POST'){ - $db = get_db_instance(); - $ok=true; - if($error=check_captcha_error()){ - $msg.="

$error

"; - $ok=false; - }elseif(!isset($_POST['username']) || $_POST['username']===''){ - $msg.='

Error: username may not be empty.

'; - $ok=false; - }else{ - $stmt=$db->prepare('SELECT username, password, id FROM users WHERE username=?;'); - $stmt->execute([$_POST['username']]); - $tmp=[]; - if(($tmp=$stmt->fetch(PDO::FETCH_NUM))===false && preg_match('/^([2-7a-z]{16}).onion$/', $_POST['username'], $match)){ - $stmt=$db->prepare('SELECT users.username, users.password, users.id FROM users INNER JOIN onions ON (onions.user_id=users.id) WHERE onions.onion=?;'); - $stmt->execute([$match[1]]); - $tmp=$stmt->fetch(PDO::FETCH_NUM); + if(!empty($_SESSION['hosting_username'])){ + if(!empty($_POST['2fa_code']) && $_POST['2fa_code'] === $_SESSION['2fa_code']){ + unset($_SESSION['2fa_code']); + unset($_SESSION['pgp_key']); + unset($_SESSION['tfa']); + session_write_close(); + header('Location: home.php'); + exit; + }else{ + $msg.='

Wrong 2FA code

'; } - if($tmp){ - $username=$tmp[0]; - $password=$tmp[1]; - $stmt=$db->prepare('SELECT new_account.approved FROM new_account INNER JOIN users ON (users.id=new_account.user_id) WHERE users.id=?;'); - $stmt->execute([$tmp[2]]); - if($tmp=$stmt->fetch(PDO::FETCH_NUM)){ - if(REQUIRE_APPROVAL && !$tmp[0]){ - $msg.='

Error: Your account is pending admin approval. Please try again later.

'; - }else{ - $msg.='

Error: Your account is pending creation. Please try again in a minute.

'; + } else { + $db = get_db_instance(); + $ok=true; + if($error=check_captcha_error()){ + $msg.="

$error

"; + $ok=false; + }elseif(!isset($_POST['username']) || $_POST['username']===''){ + $msg.='

Error: username may not be empty.

'; + $ok=false; + }else{ + $stmt=$db->prepare('SELECT username, password, id, tfa, pgp_key FROM users WHERE username=?;'); + $stmt->execute([$_POST['username']]); + $tmp=[]; + if(($tmp=$stmt->fetch(PDO::FETCH_ASSOC))===false && preg_match('/^([2-7a-z]{16}).onion$/', $_POST['username'], $match)){ + $stmt=$db->prepare('SELECT users.username, users.password, users.id, users.tfa, users.pgp_key FROM users INNER JOIN onions ON (onions.user_id=users.id) WHERE onions.onion=?;'); + $stmt->execute([$match[1]]); + $tmp=$stmt->fetch(PDO::FETCH_ASSOC); + } + if($tmp){ + $username=$tmp['username']; + $password=$tmp['password']; + $tfa=$tmp['tfa']; + $pgp_key=$tmp['pgp_key']; + $stmt=$db->prepare('SELECT new_account.approved FROM new_account INNER JOIN users ON (users.id=new_account.user_id) WHERE users.id=?;'); + $stmt->execute([$tmp['id']]); + if($tmp=$stmt->fetch(PDO::FETCH_NUM)){ + if(REQUIRE_APPROVAL && !$tmp[0]){ + $msg.='

Error: Your account is pending admin approval. Please try again later.

'; + }else{ + $msg.='

Error: Your account is pending creation. Please try again in a minute.

'; + } + $ok=false; + }elseif(!isset($_POST['pass']) || !password_verify($_POST['pass'], $password)){ + $msg.='

Error: wrong password.

'; + $ok=false; } - $ok=false; - }elseif(!isset($_POST['pass']) || !password_verify($_POST['pass'], $password)){ - $msg.='

Error: wrong password.

'; + }else{ + $msg.='

Error: username was not found. If you forgot it, you can enter youraccount.onion instead.

'; $ok=false; } - }else{ - $msg.='

Error: username was not found. If you forgot it, you can enter youraccount.onion instead.

'; - $ok=false; + } + if($ok){ + $_SESSION['hosting_username']=$username; + $_SESSION['csrf_token']=sha1(uniqid()); + if($tfa){ + $code = bin2hex(random_bytes(3)); + $_SESSION['2fa_code'] = $code; + $_SESSION['pgp_key'] = $pgp_key; + $_SESSION['tfa'] = $tfa; + } else { + session_write_close(); + header('Location: home.php'); + exit; + } } } - if($ok){ - $_SESSION['hosting_username']=$username; - $_SESSION['csrf_token']=sha1(uniqid()); - session_write_close(); - header('Location: home.php'); +} +print_header('Login'); +if($tfa){ + $gpg = gnupg_init(); + gnupg_seterrormode($gpg, GNUPG_ERROR_WARNING); + gnupg_setarmor($gpg, 1); + $imported_key = gnupg_import($gpg, $pgp_key); + if($imported_key){ + $key_info = gnupg_keyinfo($gpg, $imported_key['fingerprint']); + foreach($key_info as $key){ + if($key['can_encrypt']){ + foreach($key['subkeys'] as $subkey){ + gnupg_addencryptkey($gpg, $subkey['fingerprint']); + } + } + } + $encrypted = gnupg_encrypt($gpg, "To login, please enter the following code to confirm ownership of your key:\n\n".$_SESSION['2fa_code']."\n"); + echo $msg; + echo "

To login, please decrypt the following PGP encrypted message and confirm the code:

"; + echo "
$encrypted
"; + ?> + +
QuestionAnswer
Your rules are so strict. Can't you make an exception for my site?No, I will not make exceptions for any site and neither am I corruptible by offering me money. Once I start making an exception for your site, I would have to for every other site as well which is the same as if the rules didn't exist.
+ +
+

Don't have the private key at hand? Logout

+ + - -<?php echo htmlspecialchars(SITE_NAME); ?> - Login - - - - -

Hosting - Login

-

Info | Register | Login | List of hosted sites | FAQ

- +
Username'; -echo ''; -echo ''; -echo ''; -echo ''; +print_header('Change password'); echo $msg; echo ''; echo '
Reset type: + + +
+
+ +

Add your PGP key for more security features like 2FA:

+
+ + + + +
+
+

Go back to dashboard.

+ diff --git a/var/www/html/register.php b/var/www/html/register.php index f1f4a2e..6e55311 100644 --- a/var/www/html/register.php +++ b/var/www/html/register.php @@ -6,18 +6,11 @@ if(!empty($_SESSION['hosting_username'])){ header('Location: home.php'); exit; } +print_header('Register', '#custom_onion:not(checked)+#private_key{display:none;}#custom_onion:checked+#private_key{display:block;}'); ?> - -<?php echo htmlspecialchars(SITE_NAME); ?> - Register - - - - - -

Hosting - Register

-

Info | Register | Login | List of hosted sites | FAQ

- -<?php echo htmlspecialchars(SITE_NAME); ?> - Upgrade account - - - - - -

Hosting - Upgrade account

query("SELECT value FROM settings WHERE setting='version';")) //create tables $db->exec('CREATE TABLE captcha (id int(11) NOT NULL AUTO_INCREMENT PRIMARY KEY, time int(11) NOT NULL, code char(5) COLLATE latin1_bin NOT NULL) ENGINE=InnoDB DEFAULT CHARSET=latin1 COLLATE=latin1_bin;'); $db->exec("CREATE TABLE service_instances (id char(1) NOT NULL PRIMARY KEY, reload tinyint(1) UNSIGNED NOT NULL DEFAULT '0', KEY reload (reload)) ENGINE=InnoDB DEFAULT CHARSET=latin1 COLLATE=latin1_bin;"); - $db->exec("CREATE TABLE users (id int(11) NOT NULL AUTO_INCREMENT PRIMARY KEY, system_account varchar(32) COLLATE latin1_bin NOT NULL UNIQUE, username varchar(50) COLLATE latin1_bin NOT NULL UNIQUE, password varchar(255) COLLATE latin1_bin NOT NULL, dateadded int(10) unsigned NOT NULL, public tinyint(1) unsigned NOT NULL, php tinyint(1) unsigned NOT NULL, autoindex tinyint(1) unsigned NOT NULL, todelete tinyint(1) UNSIGNED NOT NULL DEFAULT '0', mysql_user varchar(32) NOT NULL, instance char(1) NOT NULL DEFAULT '2', KEY dateadded (dateadded), KEY public (public), KEY todelete (todelete), KEY instance (instance), CONSTRAINT instance_ibfk_2 FOREIGN KEY (instance) REFERENCES service_instances (id) ON DELETE RESTRICT ON UPDATE RESTRICT) ENGINE=InnoDB DEFAULT CHARSET=latin1 COLLATE=latin1_bin;"); + $db->exec("CREATE TABLE users (id int(11) NOT NULL AUTO_INCREMENT PRIMARY KEY, system_account varchar(32) COLLATE latin1_bin NOT NULL UNIQUE, username varchar(50) COLLATE latin1_bin NOT NULL UNIQUE, password varchar(255) COLLATE latin1_bin NOT NULL, dateadded int(10) unsigned NOT NULL, public tinyint(1) unsigned NOT NULL, php tinyint(1) unsigned NOT NULL, autoindex tinyint(1) unsigned NOT NULL, todelete tinyint(1) UNSIGNED NOT NULL DEFAULT '0', mysql_user varchar(32) NOT NULL, instance char(1) NOT NULL DEFAULT '2', pgp_key text COLLATE 'latin1_bin' NULL, pgp_verified tinyint(1) NOT NULL DEFAULT '0', tfa tinyint(1) NOT NULL DEFAULT '0', KEY dateadded (dateadded), KEY public (public), KEY todelete (todelete), KEY instance (instance), CONSTRAINT instance_ibfk_2 FOREIGN KEY (instance) REFERENCES service_instances (id) ON DELETE RESTRICT ON UPDATE RESTRICT) ENGINE=InnoDB DEFAULT CHARSET=latin1 COLLATE=latin1_bin;"); $db->exec("CREATE TABLE new_account (user_id int(11) NOT NULL PRIMARY KEY, password varchar(255) COLLATE latin1_bin NOT NULL, approved tinyint(1) UNSIGNED NOT NULL DEFAULT '0', CONSTRAINT new_account_ibfk_1 FOREIGN KEY (user_id) REFERENCES users (id) ON DELETE CASCADE ON UPDATE CASCADE) ENGINE=InnoDB DEFAULT CHARSET=latin1 COLLATE=latin1_bin;"); $db->exec('CREATE TABLE pass_change (user_id int(11) NOT NULL PRIMARY KEY, password varchar(255) COLLATE latin1_bin NOT NULL, CONSTRAINT pass_change_ibfk_1 FOREIGN KEY (user_id) REFERENCES users (id) ON DELETE CASCADE ON UPDATE CASCADE) ENGINE=InnoDB DEFAULT CHARSET=latin1 COLLATE=latin1_bin;'); $db->exec('CREATE TABLE mysql_databases (user_id int(11) NOT NULL, mysql_database varchar(64) COLLATE latin1_bin NOT NULL, KEY user_id (user_id), CONSTRAINT mysql_database_ibfk_1 FOREIGN KEY (user_id) REFERENCES users (id) ON DELETE CASCADE ON UPDATE CASCADE) ENGINE=InnoDB DEFAULT CHARSET=latin1 COLLATE=latin1_bin;'); @@ -160,6 +160,10 @@ if(!@$version=$db->query("SELECT value FROM settings WHERE setting='version';")) $db->exec("ALTER TABLE disk_quota ADD quota_size_used int(10) unsigned NOT NULL DEFAULT '0', ADD quota_files_used int(10) unsigned NOT NULL DEFAULT '0';"); $db->exec('CREATE TABLE payments (id int(11) NOT NULL AUTO_INCREMENT PRIMARY KEY, user_id int(11) NULL, payment_for varchar(255) COLLATE latin1_bin NOT NULL, txn_id varchar(255) COLLATE utf8mb4_bin NOT NULL, status tinyint NOT NULL, CONSTRAINT payments_ibfk_1 FOREIGN KEY (user_id) REFERENCES users (id) ON DELETE SET NULL ON UPDATE CASCADE) ENGINE=InnoDB DEFAULT CHARSET=latin1 COLLATE=latin1_bin;'); } + if($version<18){ + $db->exec('UPDATE disk_quota set updated=1;'); + $db->exec("ALTER TABLE users ADD pgp_key text COLLATE 'latin1_bin' NULL, ADD pgp_verified tinyint(1) NOT NULL DEFAULT '0', ADD tfa tinyint(1) NOT NULL DEFAULT '0';"); + } $stmt=$db->prepare("UPDATE settings SET value=? WHERE setting='version';"); $stmt->execute([DBVERSION]); }