Added admin panel + optional manual approval for new sites

This commit is contained in:
Daniel Winzen
2018-02-25 21:25:05 +01:00
parent eca0c675cd
commit 6b0759be73
14 changed files with 244 additions and 129 deletions

View File

@ -16,6 +16,8 @@ const INDEX_MD5S=[ //MD5 sums of index.hosting.html files that should be considd
'd41d8cd98f00b204e9800998ecf8427e', //empty file
'7ae7e9bac6be76f00e0d95347111f037' //default file
];
const REQUIRE_APPROVAL=false; //require admin approval of new sites? true/false
const ADMIN_PASSWORD='MY_PASSWORD'; //password for admin interface
function get_onion($pkey){
$keyData = openssl_pkey_get_details($pkey);
@ -51,7 +53,7 @@ function base32_encode($input) {
function send_captcha(){
global $db;
if(CAPTCHA===0 || !extension_loaded('gd')){
if(!CAPTCHA || !extension_loaded('gd')){
return;
}
$captchachars='ABCDEFGHJKMNPQRSTUVWXYZabcdefghjkmnpqrstuvwxyz23456789';
@ -172,3 +174,29 @@ function get_system_hash($pass){
}
return crypt($pass, '$6$'.$salt.'$');
}
function check_captcha_error(){
global $db;
if(CAPTCHA){
if(!isset($_REQUEST['challenge'])){
return 'Error: Wrong Captcha';
}else{
$stmt=$db->prepare('SELECT code FROM captcha WHERE id=?;');
$stmt->execute([$_REQUEST['challenge']]);
$stmt->bindColumn(1, $code);
if(!$stmt->fetch(PDO::FETCH_BOUND)){
return 'Error: Captcha expired';
}else{
$time=time();
$stmt=$db->prepare('DELETE FROM captcha WHERE id=? OR time<?;');
$stmt->execute([$_REQUEST['challenge'], $time-3600]);
if($_REQUEST['captcha']!==$code){
if(strrev($_REQUEST['captcha'])!==$code){
return 'Error: Wrong captcha';
}
}
}
}
}
return false;
}

View File

@ -10,7 +10,8 @@ $reload=[];
//add new accounts
$del=$db->prepare("DELETE FROM new_account WHERE onion=?;");
$update_priv=$db->prepare("UPDATE users SET private_key=? WHERE onion=?;");
$stmt=$db->query("SELECT new_account.onion, users.username, new_account.password, users.private_key, users.php, users.autoindex FROM new_account INNER JOIN users ON (users.onion=new_account.onion) LIMIT 100;");
$approval = REQUIRE_APPROVAL ? 'WHERE new_account.approved=1': '';
$stmt=$db->query("SELECT new_account.onion, users.username, new_account.password, users.private_key, users.php, users.autoindex FROM new_account INNER JOIN users ON (users.onion=new_account.onion) $approval LIMIT 100;");
while($id=$stmt->fetch(PDO::FETCH_NUM)){
$onion=$id[0];
$firstchar=substr($onion, 0, 1);
@ -113,7 +114,7 @@ php_admin_value[session.save_path] = /home/$onion.onion/tmp
//delete old accounts
$del=$db->prepare("DELETE FROM users WHERE onion=?");
$stmt=$db->query("SELECT onion FROM del_account LIMIT 100;");
$stmt=$db->query("SELECT onion FROM users WHERE todelete=1 LIMIT 100;");
$onions=$stmt->fetchAll(PDO::FETCH_NUM);
foreach($onions as $onion){
$firstchar=substr($onion[0], 0, 1);
@ -134,9 +135,11 @@ foreach($onions as $onion){
$torrc=str_replace("HiddenServiceDir /var/lib/tor-instances/$firstchar/hidden_service_$onion[0].onion/\nHiddenServicePort 80 unix:/var/run/nginx.sock\nHiddenServicePort 25 127.0.0.1:25\n", '', $torrc);
file_put_contents("/etc/tor/instances/$firstchar/torrc", $torrc);
//delete hidden service from tor
if(file_exists("/var/lib/tor-instances/$firstchar/hidden_service_$onion[0].onion/")){
unlink("/var/lib/tor-instances/$firstchar/hidden_service_$onion[0].onion/hostname");
unlink("/var/lib/tor-instances/$firstchar/hidden_service_$onion[0].onion/private_key");
rmdir("/var/lib/tor-instances/$firstchar/hidden_service_$onion[0].onion/");
}
}
//reload services

View File

@ -11,7 +11,7 @@ exec('find /home -path "/home/*.onion/tmp/*" -cmin +1440 -delete');
//delete unused accounts older than 30 days
$all=scandir('/home');
$stmt=$db->prepare('INSERT INTO del_account (onion) VALUES (?);');
$stmt=$db->prepare('UPDATE users SET todelete=1 WHERE onion=?;');
foreach($all as $tmp){
if(!preg_match('~^[a-z2-7]{16}\.onion$~', $tmp)){
continue;

99
var/www/html/admin.php Normal file
View File

@ -0,0 +1,99 @@
<?php
include('../common.php');
try{
$db=new PDO('mysql:host=' . DBHOST . ';dbname=' . DBNAME, DBUSER, DBPASS, [PDO::ATTR_ERRMODE=>PDO::ERRMODE_WARNING, PDO::ATTR_PERSISTENT=>PERSISTENT]);
}catch(PDOException $e){
die('No Connection to MySQL database!');
}
header('Content-Type: text/html; charset=UTF-8');
session_start(['name'=>'hosting_admin']);
if($_SERVER['REQUEST_METHOD']==='HEAD'){
exit; // headers sent, no further processing needed
}
echo '<!DOCTYPE html><html><head>';
echo '<title>Daniel\'s Hosting - Login</title>';
echo '<meta http-equiv="Content-Type" content="text/html; charset=utf-8">';
echo '<meta name="author" content="Daniel Winzen">';
echo '<meta name="viewport" content="width=device-width, initial-scale=1">';
echo '</head><body>';
echo '<h1>Hosting - Admin panel</h1>';
$error=false;
if($_SERVER['REQUEST_METHOD']==='POST' && isSet($_POST['pass']) && $_POST['pass']===ADMIN_PASSWORD){
if(!($error=check_captcha_error())){
$_SESSION['logged_in']=true;
}
}
if(empty($_SESSION['logged_in'])){
echo "<form action=\"$_SERVER[SCRIPT_NAME]\" method=\"POST\"><table>";
echo "<tr><td>Password </td><td><input type=\"password\" name=\"pass\" size=\"30\" required autofocus></td></tr>";
send_captcha();
echo "<tr><td colspan=\"2\"><input type=\"submit\" name=\"action\" value=\"Login\"></td></tr>";
echo '</table></form>';
if($error){
echo "<p style=\"color:red;\">$error</p>";
}elseif(isSet($_POST['pass'])){
echo "<p style=\"color:red;\">Wrong password!</p>";
}
echo '<p>If you disabled cookies, please re-enable them. You can\'t log in without!</p>';
}else{
echo '<p>';
if(REQUIRE_APPROVAL){
$db->query('SELECT COUNT(*) FROM new_account WHERE approved=0;');
$cnt=$db->fetch(PDO::FETCH_NUM)[0];
echo "<a href=\"$_SERVER[SCRIPT_NAME]?action=approve\">Approve pending sites ($cnt)</a> | ";
}
echo "<a href=\"$_SERVER[SCRIPT_NAME]?action=list\">List of hidden hosted sites</a> | <a href=\"$_SERVER[SCRIPT_NAME]?action=delete\">Delete accounts</a> | <a href=\"$_SERVER[SCRIPT_NAME]?action=logout\">Logout</a></p>";
if(empty($_REQUEST['action'])){
echo '<p>Welcome to the admin panel!</p>';
}elseif($_REQUEST['action']==='logout'){
session_destroy();
header("Location: $_SERVER[SCRIPT_NAME]");
exit;
}elseif($_REQUEST['action']==='list'){
echo '<table border="1">';
echo '<tr><td>Onion link</td></tr>';
$stmt=$db->query('SELECT onion FROM users WHERE public=0 ORDER BY onion;');
while($tmp=$stmt->fetch(PDO::FETCH_NUM)){
echo "<tr><td><a href=\"http://$tmp[0].onion\" target=\"_blank\">$tmp[0].onion</a></td></tr>";
}
echo '</table>';
}elseif($_REQUEST['action']==='approve'){
if(!empty($_POST['onion'])){
$stmt=$db->prepare('UPDATE new_account SET approved=1 WHERE onion=?;');
$stmt->execute([$_POST['onion']]);
echo '<p style="color:green;">Successfully approved</p>';
}
echo '<table border="1">';
echo '<tr><td>Username</td><td>Onion address</td><td>Action</td></tr>';
$stmt=$db->query('SELECT username, onion FROM users INNER JOIN new_account ON (user.onion=new_account.onion) WHERE new_account.approved=0 ORDER BY users.username;');
while($tmp=$stmt->fetch(PDO::FETCH_NUM)){
echo "<form action=\"$_SERVER[SCRIPT_NAME]\" method=\"POST\"><input type=\"hidden\" name=\"onion\" value=\"$tmp[1]\"><tr><td>$tmp[0]</td><td>$tmp[1].onion</td><td><input type=\"submit\" name=\"action\" value=\"approve\"><input type=\"submit\" name=\"action\" value=\"delete\"></td></tr></form>";
}
echo '</table>';
}elseif($_REQUEST['action']==='delete'){
echo '<p>Delete accouts:</p>';
echo "<form action=\"$_SERVER[SCRIPT_NAME]\" method=\"POST\">";
echo '<p>Onion address: <input type="text" name="onion" size="30" value="';
if(isSet($_POST['onion'])){
echo htmlspecialchars($_POST['onion']);
}
echo '" required autofocus></p>';
echo '<input type="submit" name="action" value="delete"></form><br>';
if(!empty($_POST['onion'])){
if(preg_match('~^([a-z2-7]{16})(\.onion)?$~', $_POST['onion'], $match)){
$stmt=$db->prepare('SELECT null FROM users WHERE onion=?;');
$stmt->execute([$match[1]]);
if($stmt->fetch(PDO::FETCH_NUM)){
$stmt=$db->prepare('UPDATE users SET todelete=1 WHERE onion=?;');
$stmt->execute([$match[1]]);
echo "<p style=\"color:green;\">Successfully queued for deletion!</p>";
}else{
echo "<p style=\"color:red;\">Onion address not hosted by us!</p>";
}
}else{
echo "<p style=\"color:red;\">Invalid onion address!</p>";
}
}
}
}
echo '</body></html>';

View File

@ -12,7 +12,7 @@ if($_SERVER['REQUEST_METHOD']==='POST'){
if(!isset($_POST['pass']) || !password_verify($_POST['pass'], $user['password'])){
$msg.='<p style="color:red;">Wrong password.</p>';
}else{
$stmt=$db->prepare('INSERT INTO del_account (onion) VALUES (?);');
$stmt=$db->prepare('UPDATE users SET todelete=1 WHERE onion=?;');
$stmt->execute([$user['onion']]);
session_destroy();
header('Location: login.php');

View File

@ -1,22 +1,33 @@
<?php
include('../common.php');
header('Content-Type: text/html; charset=UTF-8');
if(isset($_SERVER['HTTP_HOST']) && preg_match('/danwin1210\.(i2p|me)$/', $_SERVER['HTTP_HOST'])){
if(preg_match('/\.me$/', $_SERVER['HTTP_HOST'])){
$host='https://danwin1210.me';
}else{
$host='http://danwin1210.i2p';
}
}else{
$host='http://tt3j2x4k5ycaa5zt.onion';
}
?>
<!DOCTYPE html><html><head>
<title>Daniel's Hosting - FAQ</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<meta name=viewport content="width=device-width, initial-scale=1">
<meta name="author" content="Daniel Winzen">
<meta name="viewport" content="width=device-width, initial-scale=1">
</head><body>
<h1>Hosting - Info</h1>
<p><a href="index.php">Info</a> | <a href="register.php">Register</a> | <a href="login.php">Login</a> | <a href="list.php">List of hosted sites</a> | FAQ</p>
<table border="1">
<tr><th>Question</th><th>Answer</th></tr>
<tr><td>Your rules are so strict. Can't you make an exception for my site?</td><td>No, I will not make exceptions for any site and neither am I curruptibly 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.</td></tr>
<tr><td>I have an .htaccess file, but it doesn't work. How can I fix it?</td><td>.htaccess files are meant for Apache2 webservers. My server is based on NginX, which is much faster due to using static configuration files and not reading files like .htaccess at runtime. You can <a href="http://tt3j2x4k5ycaa5zt.onion/contact.php">contact me</a> and tell me your sites address where the .htaccess file is. I will then check your .htaccess and convert the rules to NginX rules and apply those.</td></tr>
<tr><td>I just uploaded my page, but it's broken. HELP</td><td>Most likely your site makes use of rewriting rules, which are typically located in an .htaccess file or are mentioned in a readme file. Just <a href="http://tt3j2x4k5ycaa5zt.onion/contact.php">contact me</a> in this case. Also see previous question.</td></tr>
<tr><td>I have an .htaccess file, but it doesn't work. How can I fix it?</td><td>.htaccess files are meant for Apache2 webservers. My server is based on NginX, which is much faster due to using static configuration files and not reading files like .htaccess at runtime. You can <a href="<?php echo "$host/contact.php"; ?>">contact me</a> and tell me your sites address where the .htaccess file is. I will then check your .htaccess and convert the rules to NginX rules and apply those.</td></tr>
<tr><td>I just uploaded my page, but it's broken. HELP</td><td>Most likely your site makes use of rewriting rules, which are typically located in an .htaccess file or are mentioned in a readme file. Just <a href="<?php echo "$host/contact.php"; ?>">contact me</a> in this case. Also see previous question.</td></tr>
<tr><td>Can I host a porn site?</td><td>Yes as long as your content is legal you may upload adult content.</td></tr>
<tr><td>What is the directory structure for when I connect via (s)ftp?</td><td>There are several directories you on the server for your account:<br><b>Maildir</b> - used to store your mails in (don't touch it)<br><b>data</b> - You can store application data here that should not be accessible via your site. E.g. configuration or database files.<br><b>tmp</b> - anything saved here will automatically be deleted after about 24 hours<br><b>www</b> - this is where you upload your website which becomes then available under your domain.</td></tr>
<tr><td>My application is very ressource intensive or I want to host a different service e.g. my own tor relay. Can you get me a VPS?</td><td>Yes, if you have special requirements, want a dedicated VPS for your application or just want to anonymously support the TOR network (or other networks) without having to deal with server setup etc. I can offer you a managed VPS hosting. However this will not be for free. It depends on which server you want me to get. For details, <a href="http://tt3j2x4k5ycaa5zt.onion/contact.php">contact me</a></td></tr>
<tr><td>I want to also publish my site on clearnet. Can you offer a clearnet relay?</td><td>Yes, I can offer you a subdomain on my server, e.g. yoursite.danwin1210.me or if you have your own domain use that. Just <a href="http://tt3j2x4k5ycaa5zt.onion/contact.php">contact me</a> for setting up a clearnet gateway for your site.</td></tr>
<tr><td>Can you make my website also available via I2P?</td><td>Sure I can. Just <a href="http://tt3j2x4k5ycaa5zt.onion/contact.php">contact me</a> to set it up for you.</td></tr>
<tr><td>What is the directory structure for when I connect via (s)ftp?</td><td>There are several directories you on the server for your account:<br><b>Maildir</b> - used to store your mails in (don't touch it)<br><b>data</b> - You can store application data here that should not be accessible via your site. E.g. configuration or database files.<br><b>tmp</b> - anything saved here will automatically be deleted after about 24 hours<br><b>www</b> - this is where you upload your website which becomes then available under your domain.<br><b>logs</b> - you will find webserver logs here<br><b>.ssh</b> - by uploading your ssh public key as authorzed_keys in this folder, you can authenticate to sftp using your ssh key, without a password</td></tr>
<tr><td>My application is very ressource intensive or I want to host a different service e.g. my own tor relay. Can you get me a VPS?</td><td>Yes, if you have special requirements, want a dedicated VPS for your application or just want to anonymously support the TOR network (or other networks) without having to deal with server setup etc. I can offer you a managed VPS hosting. However this will not be for free. It depends on which server you want me to get. For details, <a href="<?php echo "$host/contact.php"; ?>">contact me</a></td></tr>
<tr><td>I want to also publish my site on clearnet. Can you offer a clearnet relay?</td><td>Yes, I can offer you a subdomain on my server, e.g. yoursite.danwin1210.me or if you have your own domain use that. Just <a href="<?php echo "$host/contact.php"; ?>">contact me</a> for setting up a clearnet gateway for your site.</td></tr>
<tr><td>Can you make my website also available via I2P?</td><td>Sure I can. Just <a href="<?php echo "$host/contact.php"; ?>">contact me</a> to set it up for you.</td></tr>
</table>
</body></html>

View File

@ -173,10 +173,16 @@ if(!empty($_POST['unzip']) && !empty($_POST['files'])){
continue;
}
$tmpfile='/tmp/'.uniqid().'.zip';
ftp_get($ftp, $tmpfile, $file, FTP_BINARY);
if(!ftp_get($ftp, $tmpfile, $file, FTP_BINARY)){
continue;
}
//prevent zip-bombs
$size=0;
$resource=zip_open($tmpfile);
if(!is_resource($resource)){
unlink($tmpfile);
continue;
}
while($dir_resource=zip_read($resource)) {
$size+=zip_entry_filesize($dir_resource);
}
@ -198,9 +204,11 @@ if(!empty($_POST['unzip']) && !empty($_POST['files'])){
if(!empty($_FILES['files'])){
$c=count($_FILES['files']['name']);
for($i=0; $i<$c; ++$i){
if($_FILES['files']['error'][$i]===UPLOAD_ERR_OK){
ftp_put($ftp, $dir.$_FILES['files']['name'][$i], $_FILES['files']['tmp_name'][$i], FTP_BINARY);
unlink($_FILES['files']['tmp_name'][$i]);
}
}
}

View File

@ -11,15 +11,11 @@ header('Content-Type: text/html; charset=UTF-8');
echo '<!DOCTYPE html><html><head>';
echo '<title>Daniel\'s Hosting - Dashboard</title>';
echo '<meta http-equiv="Content-Type" content="text/html; charset=utf-8">';
echo '<meta name=viewport content="width=device-width, initial-scale=1">';
echo '<meta name="author" content="Daniel Winzen">';
echo '<meta name="viewport" content="width=device-width, initial-scale=1">';
echo '</head><body>';
echo "<p>Logged in as $user[username] <a href=\"logout.php\">Logout</a> | <a href=\"password.php\">Change passwords</a> | <a target=\"_blank\" href=\"files.php\">FileManager</a> | <a href=\"delete.php\">Delete account</a>
</p>";
$mail=0;
if(file_exists("/home/$user[onion].onion/Maildir/new/")){
$mail=count(scandir("/home/$user[onion].onion/Maildir/new/"))-2;
}
echo "<p>Enter system account password to check your $user[onion].onion@" . ADDRESS . " mail ($mail new):</td><td><form action=\"squirrelmail/src/redirect.php\" method=\"post\" target=\"_blank\"><input type=\"hidden\" name=\"login_username\" value=\"$user[onion].onion\"><input type=\"password\" name=\"secretkey\"><input type=\"submit\" value=\"Login to webmail\"></form></p>";
echo "<p>Logged in as $user[username] <a href=\"logout.php\">Logout</a> | <a href=\"password.php\">Change passwords</a> | <a target=\"_blank\" href=\"files.php\">FileManager</a> | <a href=\"delete.php\">Delete account</a></p>";
echo "<p>Enter system account password to check your $user[onion].onion@" . ADDRESS . " mail:</td><td><form action=\"squirrelmail/src/redirect.php\" method=\"post\" target=\"_blank\"><input type=\"hidden\" name=\"login_username\" value=\"$user[onion].onion\"><input type=\"password\" name=\"secretkey\"><input type=\"submit\" value=\"Login to webmail\"></form></p>";
echo '<h3>Domain</h3>';
echo '<table border="1">';
echo '<tr><th>Onion</th><th>Private key</th></tr>';

View File

@ -17,6 +17,7 @@ if(isset($_SERVER['HTTP_HOST']) && preg_match('/danwin1210\.(i2p|me)$/', $_SERVE
<meta name="author" content="Daniel Winzen">
<meta name="viewport" content="width=device-width, initial-scale=1">
</head><body>
<h1>Hosting - Info</h1>
<p>Info | <a href="register.php">Register</a> | <a href="login.php">Login</a> | <a href="list.php">List of hosted sites</a> | <a href="faq.php">FAQ</a></p>
<p>Here you can get yourself a hosting account on my server.</p>
<p>What you will get:</p>
@ -46,9 +47,8 @@ if(isset($_SERVER['HTTP_HOST']) && preg_match('/danwin1210\.(i2p|me)$/', $_SERVE
<li>No terroristic propaganda!</li>
<li>No illegal content according to German law!</li>
<li>No malware! (e.g. botnets)</li>
<li>No phishing!</li>
<li>No scams!</li>
<li>No spam!</li>
<li>No phishing, scams or spam!</li>
<li>No mining without explicit user permission! (e.g. using coinhive)</li>
<li>No shops, markets or any other sites dedicated to making money! (This is a FREE hosting!)</li>
<li>No proxy scripts! (You are already using TOR and this will just burden the network)</li>
<li>No IP logger or similar de-anonymizer sites!</li>

View File

@ -9,8 +9,10 @@ try{
echo '<!DOCTYPE html><html><head>';
echo '<title>Daniel\'s Hosting - List of hosted sites</title>';
echo '<meta http-equiv="Content-Type" content="text/html; charset=utf-8">';
echo '<meta name=viewport content="width=device-width, initial-scale=1">';
echo '<meta name="author" content="Daniel Winzen">';
echo '<meta name="viewport" content="width=device-width, initial-scale=1">';
echo '</head><body>';
echo '<h1>Hosting - List of hosted sites</h1>';
echo '<p><a href="index.php">Info</a> | <a href="register.php">Register</a> | <a href="login.php">Login</a> | List of hosted sites | <a href="faq.php">FAQ</a></p>';
$stmt=$db->query('SELECT COUNT(*) FROM users WHERE public=1;');
$count=$stmt->fetch(PDO::FETCH_NUM);

View File

@ -15,32 +15,11 @@ $msg='';
$username='';
if($_SERVER['REQUEST_METHOD']==='POST'){
$ok=true;
if(CAPTCHA){
if(!isset($_REQUEST['challenge'])){
$msg.='<p style="color:red;">Error: Wrong Captcha</p>';
if($error=check_captcha_error()){
$msg.="<p style=\"color:red;\">$error</p>";
$ok=false;
}else{
$stmt=$db->prepare('SELECT code FROM captcha WHERE id=?;');
$stmt->execute([$_REQUEST['challenge']]);
$stmt->bindColumn(1, $code);
if(!$stmt->fetch(PDO::FETCH_BOUND)){
$msg.='<p style="color:red;">Error: Captcha expired</p>';
$ok=false;
}else{
$time=time();
$stmt=$db->prepare('DELETE FROM captcha WHERE id=? OR time<?;');
$stmt->execute([$_REQUEST['challenge'], $time-3600]);
if($_REQUEST['captcha']!==$code){
if(strrev($_REQUEST['captcha'])!==$code){
$msg.='<p style="color:red;">Error: Wrong captcha</p>';
$ok=false;
}
}
}
}
}
if(!isset($_POST['username']) || $_POST['username']===''){
$msg.='<p style="color:red;">Error, username may not be empty.</p>';
}elseif(!isset($_POST['username']) || $_POST['username']===''){
$msg.='<p style="color:red;">Error: username may not be empty.</p>';
$ok=false;
}else{
$stmt=$db->prepare('SELECT username, password FROM users WHERE username=?;');
@ -53,13 +32,13 @@ if($_SERVER['REQUEST_METHOD']==='POST'){
}
if($tmp){
if(!isset($_POST['pass']) || !password_verify($_POST['pass'], $tmp[1])){
$msg.='<p style="color:red;">Error, wrong password.</p>';
$msg.='<p style="color:red;">Error: wrong password.</p>';
$ok=false;
}else{
$username=$tmp[0];
}
}else{
$msg.='<p style="color:red;">Error, username was not found. If you forgot it, you can enter youraccount.onion instead.</p>';
$msg.='<p style="color:red;">Error: username was not found. If you forgot it, you can enter youraccount.onion instead.</p>';
$ok=false;
}
}
@ -76,6 +55,7 @@ echo '<meta http-equiv="Content-Type" content="text/html; charset=utf-8">';
echo '<meta name="author" content="Daniel Winzen">';
echo '<meta name="viewport" content="width=device-width, initial-scale=1">';
echo '</head><body>';
echo '<h1>Hosting - Login</h1>';
echo '<p><a href="index.php">Info</a> | <a href="register.php">Register</a> | Login | <a href="list.php">List of hosted sites</a> | <a href="faq.php">FAQ</a></p>';
echo $msg;
echo '<form method="POST" action="login.php"><table>';
@ -85,10 +65,8 @@ if(isset($_POST['username'])){
}
echo '" required autofocus></td></tr>';
echo '<tr><td>Password</td><td><input type="password" name="pass" required></td></tr>';
if(CAPTCHA){
send_captcha();
}
send_captcha();
echo '<tr><td colspan="2"><input type="submit" value="Login"></td></tr>';
echo '</table></form>';
echo '<p>If you disabled cookies, please re-enable them. You currently can\'t log in without</p>';
echo '<p>If you disabled cookies, please re-enable them. You can\'t log in without!</p>';
echo '</body></html>';

View File

@ -17,6 +17,7 @@ echo '<meta http-equiv="Content-Type" content="text/html; charset=utf-8">';
echo '<meta name="author" content="Daniel Winzen">';
echo '<meta name="viewport" content="width=device-width, initial-scale=1">';
echo '</head><body>';
echo '<h1>Hosting - Register</h1>';
echo '<p><a href="index.php">Info</a> | Register | <a href="login.php">Login</a> | <a href="list.php">List of hosted sites</a> | <a href="faq.php">FAQ</a></p>';
if($_SERVER['REQUEST_METHOD']==='POST'){
$ok=true;
@ -26,61 +27,40 @@ if($_SERVER['REQUEST_METHOD']==='POST'){
$autoindex=0;
$hash='';
$priv_key='';
if(empty($_POST['pass'])){
echo '<p style="color:red;">Error, password empty.</p>';
if($error=check_captcha_error()){
echo "<p style=\"color:red;\">$error</p>";
$ok=false;
}elseif(empty($_POST['pass'])){
echo '<p style="color:red;">Error: password empty.</p>';
$ok=false;
}elseif(empty($_POST['passconfirm']) || $_POST['pass']!==$_POST['passconfirm']){
echo '<p style="color:red;">Error, password confirmation does not match.</p>';
echo '<p style="color:red;">Error: password confirmation does not match.</p>';
$ok=false;
}
if(empty($_POST['username'])){
echo '<p style="color:red;">Error, username empty.</p>';
}elseif(empty($_POST['username'])){
echo '<p style="color:red;">Error: username empty.</p>';
$ok=false;
}elseif(preg_match('/[^a-z0-9\-_\.]/', $_POST['username'])){
echo '<p style="color:red;">Error, username may only contain characters that are in the rage of a-z (lower case) - . _ and 0-9.</p>';
echo '<p style="color:red;">Error: username may only contain characters that are in the rage of a-z (lower case) - . _ and 0-9.</p>';
$ok=false;
}elseif(strlen($_POST['username'])>50){
echo '<p style="color:red;">Error, username may not be longer than 50 characters.</p>';
echo '<p style="color:red;">Error: username may not be longer than 50 characters.</p>';
$ok=false;
}else{
$stmt=$db->prepare('SELECT null FROM users WHERE username=?;');
$stmt->execute([$_POST['username']]);
if($stmt->fetch(PDO::FETCH_NUM)){
echo '<p style="color:red;">Error, this username is already registered.</p>';
echo '<p style="color:red;">Error: this username is already registered.</p>';
$ok=false;
}
}
if(CAPTCHA){
if(!isset($_REQUEST['challenge'])){
echo '<p style="color:red;">Error: Wrong Captcha</p>';
$ok=false;
}else{
$stmt=$db->prepare('SELECT code FROM captcha WHERE id=?;');
$stmt->execute([$_REQUEST['challenge']]);
$stmt->bindColumn(1, $code);
if(!$stmt->fetch(PDO::FETCH_BOUND)){
echo '<p style="color:red;">Error: Captcha expired</p>';
$ok=false;
}else{
$time=time();
$stmt=$db->prepare('DELETE FROM captcha WHERE id=? OR time<?;');
$stmt->execute([$_REQUEST['challenge'], $time-3600]);
if($_REQUEST['captcha']!==$code){
if(strrev($_REQUEST['captcha'])!==$code){
echo '<p style="color:red;">Error: Wrong captcha</p>';
$ok=false;
}
}
}
}
}
if($ok){
$check=$db->prepare('SELECT null FROM users WHERE onion=?;');
if(isset($_REQUEST['private_key']) && !empty(trim($_REQUEST['private_key']))){
$priv_key=trim($_REQUEST['private_key']);
if(($pkey=openssl_pkey_get_private($priv_key))!==false){
$details=openssl_pkey_get_details($pkey);
if($details['bits']!==1024){
echo '<p style="color:red;">Error, private key not of bitsize 1024.</p>';
echo '<p style="color:red;">Error: private key not of bitsize 1024.</p>';
$ok=false;
}else{
$onion=get_onion($pkey);
@ -92,7 +72,7 @@ if($_SERVER['REQUEST_METHOD']==='POST'){
}
openssl_pkey_free($pkey);
}else{
echo '<p style="color:red;">Error, private key invalid.</p>';
echo '<p style="color:red;">Error: private key invalid.</p>';
$ok=false;
}
}else{
@ -104,7 +84,6 @@ if($_SERVER['REQUEST_METHOD']==='POST'){
$check->execute([$onion]);
}while($check->fetch(PDO::FETCH_NUM));
}
if($ok){
if(isset($_POST['public']) && $_POST['public']==1){
$public=1;
}
@ -119,7 +98,7 @@ if($_SERVER['REQUEST_METHOD']==='POST'){
}
$check=$db->prepare('SELECT null FROM users WHERE dateadded>?;');
$check->execute([time()-60]);
if($check->fetch(PDO::FETCH_NUM)){
if($ok && $check->fetch(PDO::FETCH_NUM)){
echo '<p style="color:red;">To prevent abuse a site can only be registered every 60 seconds, but one has already been registered within the last 60 seconds. Please try again.</p>';
$ok=false;
}elseif($ok){
@ -149,9 +128,7 @@ if(isset($_POST['username'])){
echo '" required autofocus></td></tr>';
echo '<tr><td>Password</td><td><input type="password" name="pass" required></td></tr>';
echo '<tr><td>Confirm password</td><td><input type="password" name="passconfirm" required></td></tr>';
if(CAPTCHA){
send_captcha();
}
send_captcha();
if($_SERVER['REQUEST_METHOD']!=='POST' || (isset($_POST['public']) && $_POST['public']==1)){
$public=' checked';
}else{

View File

@ -1,7 +1,7 @@
<?php
$head=true;
while($line=fgets(STDIN)){
if($head && stripos(ltrim($line), 'FROM:')===0){
if($head && stripos(ltrim($line), 'FROM')===0){
continue;
}
if($head && ($line==="\r\n" || $line==="\n")){

View File

@ -18,16 +18,29 @@ try{
die("Error: No database connection!\n");
}
}
if(!@$db->query('SELECT null FROM settings LIMIT 1;')){
$version;
if(!@$version=$db->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 users (onion char(16) COLLATE latin1_bin NOT NULL PRIMARY KEY, username varchar(50) COLLATE latin1_bin NOT NULL UNIQUE, password varchar(255) COLLATE latin1_bin NOT NULL, private_key varchar(1000) COLLATE latin1_bin NOT NULL, dateadded int(10) unsigned NOT NULL, public tinyint(3) unsigned NOT NULL, php tinyint(1) unsigned NOT NULL, autoindex tinyint(1) unsigned NOT NULL, KEY public (public), KEY dateadded (dateadded)) ENGINE=InnoDB DEFAULT CHARSET=latin1 COLLATE=latin1_bin;');
$db->exec('CREATE TABLE del_account (onion char(16) COLLATE latin1_bin NOT NULL PRIMARY KEY, CONSTRAINT del_account_ibfk_1 FOREIGN KEY (onion) REFERENCES users (onion) ON DELETE CASCADE ON UPDATE CASCADE) ENGINE=InnoDB DEFAULT CHARSET=latin1 COLLATE=latin1_bin;');
$db->exec('CREATE TABLE new_account (onion char(16) COLLATE latin1_bin NOT NULL PRIMARY KEY, password varchar(255) COLLATE latin1_bin NOT NULL, CONSTRAINT new_account_ibfk_1 FOREIGN KEY (onion) REFERENCES users (onion) ON DELETE CASCADE ON UPDATE CASCADE) ENGINE=InnoDB DEFAULT CHARSET=latin1 COLLATE=latin1_bin;');
$db->exec('CREATE TABLE users (onion char(16) COLLATE latin1_bin NOT NULL PRIMARY KEY, username varchar(50) COLLATE latin1_bin NOT NULL UNIQUE, password varchar(255) COLLATE latin1_bin NOT NULL, private_key varchar(1000) COLLATE latin1_bin NOT NULL, dateadded int(10) unsigned NOT NULL, public tinyint(3) unsigned NOT NULL, php tinyint(1) unsigned NOT NULL, autoindex tinyint(1) unsigned NOT NULL, todelete tinyint(1) UNSIGNED NOT NULL, KEY public (public), KEY dateadded (dateadded), KEY todelete (todelete)) ENGINE=InnoDB DEFAULT CHARSET=latin1 COLLATE=latin1_bin;');
$db->exec('CREATE TABLE new_account (onion char(16) COLLATE latin1_bin NOT NULL PRIMARY KEY, password varchar(255) COLLATE latin1_bin NOT NULL, approved tinyint(1) UNSIGNED NOT NULL, CONSTRAINT new_account_ibfk_1 FOREIGN KEY (onion) REFERENCES users (onion) ON DELETE CASCADE ON UPDATE CASCADE) ENGINE=InnoDB DEFAULT CHARSET=latin1 COLLATE=latin1_bin;');
$db->exec('CREATE TABLE pass_change (onion char(16) COLLATE latin1_bin NOT NULL PRIMARY KEY, password varchar(255) COLLATE latin1_bin NOT NULL, CONSTRAINT pass_change_ibfk_1 FOREIGN KEY (onion) REFERENCES users (onion) ON DELETE CASCADE ON UPDATE CASCADE) ENGINE=InnoDB DEFAULT CHARSET=latin1 COLLATE=latin1_bin;');
$db->exec('CREATE TABLE settings (setting varchar(50) CHARACTER SET latin1 COLLATE latin1_bin NOT NULL PRIMARY KEY, value text CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NOT NULL) ENGINE=InnoDB DEFAULT CHARSET=latin1 COLLATE=latin1_bin;');
$stmt=$db->prepare("INSERT INTO settings (setting, value) VALUES ('version', ?);");
$stmt->execute([DBVERSION]);
echo "Database has successfully been set up\n";
}else{
$version=$version->fetch(PDO::FETCH_NUM)[0];
if($version<2){
$db->exec('ALTER TABLE users ADD todelete tinyint(1) UNSIGNED NOT NULL, ADD INDEX(todelete);');
$db->exec('ALTER TABLE new_account ADD approved tinyint(1) UNSIGNED NOT NULL;');
$db->exec('DROP TABLE del_account;');
}
$stmt=$db->prepare("UPDATE settings SET value=? WHERE setting='version';");
$stmt->execute([DBVERSION]);
if(DBVERSION!=$version){
echo "Database has successfully been updated to the latest version\n";
}else{
echo "Database already up-to-date\n";
}
}
?>