Refactor DB foreign keys to auto_incrementing id instead of onion

Allows moving domains into separate table at a later stage
This commit is contained in:
Daniel Winzen
2018-10-16 21:09:16 +02:00
parent 81c2364b7b
commit 6eb068222c
7 changed files with 38 additions and 20 deletions

View File

@ -4,7 +4,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=3; //database layout version
const DBVERSION=4; //database layout version
const CAPTCHA=0; // Captcha difficulty (0=off, 1=simple, 2=moderate, 3=extreme)
const ADDRESS='dhosting4okcs22v.onion'; // our own address
const SERVERS=[ //servers and ports we are running on

View File

@ -8,10 +8,10 @@ try{
$reload=[];
//add new accounts
$del=$db->prepare("DELETE FROM new_account WHERE onion=?;");
$del=$db->prepare("DELETE FROM new_account WHERE user_id=?;");
$update_priv=$db->prepare("UPDATE users SET private_key=? WHERE onion=?;");
$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;");
$stmt=$db->query("SELECT users.onion, users.username, new_account.password, users.private_key, users.php, users.autoindex, users.id FROM new_account INNER JOIN users ON (users.id=new_account.user_id) $approval LIMIT 100;");
while($id=$stmt->fetch(PDO::FETCH_NUM)){
$onion=$id[0];
$firstchar=substr($onion, 0, 1);
@ -116,10 +116,10 @@ php_admin_value[session.save_path] = /home/$onion.onion/tmp
chgrp("/var/lib/tor-instances/$firstchar/hidden_service_$onion.onion/private_key", "_tor-$firstchar");
//add hidden service to torrc
$torrc=file_get_contents("/etc/tor/instances/$firstchar/torrc");
$torrc.="HiddenServiceDir /var/lib/tor-instances/$firstchar/hidden_service_$onion.onion/\nHiddenServicePort 80 unix:/var/run/nginx/$onion\nHiddenServicePort 25 127.0.0.1:25\n";
$torrc.="HiddenServiceDir /var/lib/tor-instances/$firstchar/hidden_service_$onion.onion/\nHiddenServicePort 80 unix:/var/run/nginx/$onion\nHiddenServicePort 25\n";
file_put_contents("/etc/tor/instances/$firstchar/torrc", $torrc);
//remove from to-add queue
$del->execute([$onion]);
$del->execute([$id[6]]);
}
//delete old accounts
@ -142,7 +142,7 @@ foreach($onions as $onion){
unlink("/etc/nginx/sites-enabled/$onion[0].onion");
//clean torrc from user
$torrc=file_get_contents("/etc/tor/instances/$firstchar/torrc");
$torrc=str_replace("HiddenServiceDir /var/lib/tor-instances/$firstchar/hidden_service_$onion[0].onion/\nHiddenServicePort 80 unix:/var/run/nginx/$onion[0]\nHiddenServicePort 25 127.0.0.1:25\n", '', $torrc);
$torrc=str_replace("HiddenServiceDir /var/lib/tor-instances/$firstchar/hidden_service_$onion[0].onion/\nHiddenServicePort 80 unix:/var/run/nginx/$onion[0]\nHiddenServicePort 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/")){
@ -180,9 +180,9 @@ foreach($onions as $onion){
}
// update passwords
$stmt=$db->query("SELECT onion, password FROM pass_change LIMIT 100;");
$del=$db->prepare("DELETE FROM pass_change WHERE onion=?;");
$stmt=$db->query("SELECT users.onion, pass_change.password, users.id FROM pass_change INNER JOIN users ON (users.id=pass_change.user_id) LIMIT 100;");
$del=$db->prepare("DELETE FROM pass_change WHERE user_id=?;");
while($onion=$stmt->fetch(PDO::FETCH_NUM)){
exec('usermod -p '. escapeshellarg($onion[1]) . " $onion[0].onion");
$del->execute([$onion[0]]);
$del->execute([$onion[2]]);
}

View File

@ -27,7 +27,7 @@ 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 "<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>";
@ -59,13 +59,13 @@ if(empty($_SESSION['logged_in'])){
echo '</table>';
}elseif($_REQUEST['action']==='approve'){
if(!empty($_POST['onion'])){
$stmt=$db->prepare('UPDATE new_account SET approved=1 WHERE onion=?;');
$stmt=$db->prepare('UPDATE new_account INNER JOIN users ON (users.id=new_account.user_id) SET new_account.approved=1 WHERE users.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 users.username, users.onion FROM users INNER JOIN new_account ON (users.onion=new_account.onion) WHERE new_account.approved=0 ORDER BY users.username;');
$stmt=$db->query('SELECT users.username, users.onion FROM users INNER JOIN new_account ON (users.id=new_account.user_id) 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>";
}

View File

@ -33,7 +33,7 @@ if($_SERVER['REQUEST_METHOD']==='POST'){
if($tmp){
$username=$tmp[0];
$password=$tmp[1];
$stmt=$db->prepare('SELECT approved FROM new_account WHERE onion=?;');
$stmt=$db->prepare('SELECT new_account.approved FROM new_account INNER JOIN users ON (users.id=new_account.user_id) WHERE users.onion=?;');
$stmt->execute([$tmp[2]]);
if($tmp=$stmt->fetch(PDO::FETCH_NUM)){
if(REQUIRE_APPROVAL && !$tmp[0]){

View File

@ -23,9 +23,9 @@ if($_SERVER['REQUEST_METHOD']==='POST'){
$stmt->execute([$hash, $user['username']]);
$msg.='<p style="color:green;">Successfully changed account password.</p>';
}elseif($_REQUEST['type']==='sys'){
$stmt=$db->prepare('INSERT INTO pass_change (onion, password) VALUES (?, ?);');
$stmt=$db->prepare('INSERT INTO pass_change (user_id, password) VALUES (?, ?);');
$hash=get_system_hash($_POST['newpass']);
$stmt->execute([$user['onion'], $hash]);
$stmt->execute([$user['id'], $hash]);
$msg.='<p style="color:green;">Successfully changed system account password, change will take affect within the next minute.</p>';
}elseif($_REQUEST['type']==='sql'){
$stmt=$db->prepare("SET PASSWORD FOR '$user[onion].onion'@'%'=PASSWORD(?);");

View File

@ -104,13 +104,16 @@ if($_SERVER['REQUEST_METHOD']==='POST'){
}elseif($ok){
$stmt=$db->prepare('INSERT INTO users (username, password, onion, private_key, dateadded, public, php, autoindex) VALUES (?, ?, ?, ?, ?, ?, ?, ?);');
$stmt->execute([$_POST['username'], $hash, $onion, $priv_key, time(), $public, $php, $autoindex]);
$stmt=$db->prepare('SELECT id FROM users WHERE username=?;');
$stmt->execute([$_POST['username']]);
$user_id=$stmt->fetch(PDO::FETCH_NUM)[0];
$create_user=$db->prepare("CREATE USER '$onion.onion'@'%' IDENTIFIED BY ?;");
$create_user->execute([$_POST['pass']]);
$db->exec("CREATE DATABASE IF NOT EXISTS `$onion`;");
$db->exec("GRANT ALL PRIVILEGES ON `$onion`.* TO '$onion.onion'@'%';");
$db->exec('FLUSH PRIVILEGES;');
$stmt=$db->prepare('INSERT INTO new_account (onion, password) VALUES (?, ?);');
$stmt->execute([$onion, get_system_hash($_POST['pass'])]);
$stmt=$db->prepare('INSERT INTO new_account (user_id, password) VALUES (?, ?);');
$stmt->execute([$user_id, get_system_hash($_POST['pass'])]);
if(EMAIL_TO!==''){
$title="A new hidden service $onion has been created";
$msg="A new hidden service http://$onion.onion has been created";

View File

@ -22,9 +22,9 @@ $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, 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 users (id int(11) NOT NULL AUTO_INCREMENT PRIMARY KEY, onion char(16) COLLATE latin1_bin NOT NULL UNIQUE, 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 (user_id int(11) 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 (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 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]);
@ -50,6 +50,21 @@ if(!@$version=$db->query("SELECT value FROM settings WHERE setting='version';"))
exec('service nginx reload');
exec("service tor reload");
}
if($version<4){
$db->exec('ALTER TABLE new_account DROP FOREIGN KEY new_account_ibfk_1;');
$db->exec('ALTER TABLE pass_change DROP FOREIGN KEY pass_change_ibfk_1;');
$db->exec('ALTER TABLE users DROP PRIMARY KEY;');
$db->exec('ALTER TABLE users ADD id int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT FIRST;');
$db->exec('ALTER TABLE users ADD UNIQUE (onion);');
$db->exec('RENAME TABLE new_account TO copy_new_account;');
$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, 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('INSERT INTO new_account SELECT users.id, copy_new_account.password, copy_new_account.approved FROM copy_new_account INNER JOIN users ON (users.onion=copy_new_account.onion);');
$db->exec('DROP TABLE copy_new_account;');
$db->exec('RENAME TABLE pass_change TO copy_pass_change;');
$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('INSERT INTO pass_change SELECT users.id, copy_pass_change.password FROM copy_pass_change INNER JOIN users ON (users.onion=copy_pass_change.onion);');
$db->exec('DROP TABLE copy_pass_change;');
}
$stmt=$db->prepare("UPDATE settings SET value=? WHERE setting='version';");
$stmt->execute([DBVERSION]);
if(DBVERSION!=$version){