diff --git a/app/page/Dashboard.php b/app/page/Dashboard.php new file mode 100644 index 0000000..ab8e25d --- /dev/null +++ b/app/page/Dashboard.php @@ -0,0 +1,26 @@ +config('domain'))); + } + + public function get(): void + { + $opensim = new OpenSim($this->app->db()); + $this->app->template('dashboard-home.php')->parent('__dashboard.php')->vars([ + 'title' => 'Dashboard', + 'username' => $_SESSION['DISPLAYNAME'], + 'global-user-count' => $opensim->getUserCount(), + 'global-region-count' => $opensim->getRegionCount() + ])->render(); + } +} diff --git a/app/page/Error.php b/app/page/Error.php new file mode 100644 index 0000000..7fe5b0c --- /dev/null +++ b/app/page/Error.php @@ -0,0 +1,16 @@ +app->template('error.php')->parent('__presession.php')->vars([ + 'title' => 'Seite nicht gefunden', + 'error-message' => 'Die gewünschte Seite wurde nicht gefunden.' + ])->render(); + } +} diff --git a/app/page/ForgotPassword.php b/app/page/ForgotPassword.php new file mode 100644 index 0000000..47e5ddc --- /dev/null +++ b/app/page/ForgotPassword.php @@ -0,0 +1,89 @@ +
wir haben soeben eine Anfrage zur Zurücksetzung des Passworts für deinen 4Creative-Account erhalten.

Klicke hier, um ein neues Passwort festzulegen. Dieser Link läuft in 24 Stunden ab.

Falls du diese Anfrage nicht gesendet hast, ignoriere sie einfach. Bei weiteren Fragen kannst du uns unter info@4creative.net oder per Discord über @ikeytan erreichen.'; + + public function __construct(\Mcp\Mcp $app) + { + parent::__construct($app, new PreSessionMiddleware($app->config('domain'))); + } + + public function get(): void + { + $this->app->template('forgot.php')->parent('__presession.php')->vars([ + 'title' => 'Passwort vergessen', + 'message-color' => 'red' + ])->render(); + } + + public function post(): void + { + $validator = new FormValidator(array( + 'username' => array('required' => true, 'regex' => '/^[^\\/<>\s]{1,64} [^\\/<>\s]{1,64}$/'), + 'email' => array('required' => true, 'regex' => '/^\S{1,64}@\S{1,250}.\S{2,64}$/') + )); + $tpl = $this->app->template('forgot.php')->parent('__presession.php')->var('title', 'Passwort vergessen'); + + if (!$validator->isValid($_POST)) { + $tpl->vars([ + 'message' => 'Bitte gebe deinen Benutzernamen (Vor- und Nachname) und die dazugehörige E-Mail-Adresse ein', + 'message-color' => 'red' + ])->render(); + } else { + $nameParts = explode(" ", $_POST['username']); + $email = strtolower(trim($_POST['email'])); + + $getAccount = $this->app->db()->prepare('SELECT Email,FirstName,LastName,PrincipalID FROM UserAccounts WHERE FirstName = ? AND LastName = ? AND Email = ?'); + $getAccount->execute([trim($nameParts[0]), trim($nameParts[1]), $email]); + $validRequest = $getAccount->rowCount() == 1; + $uuid = null; + $name = null; + if ($res = $getAccount->fetch()) { + $email = $res['Email']; + $uuid = $res['PrincipalID']; + $name = $res['FirstName'].' '.$res['LastName']; + } + + foreach ($this->app->config('reset-blocked-domains') as $domain) { + if (str_ends_with($email, $domain)) { + $validRequest = false; + } + } + + $tpl->vars([ + 'message' => 'Falls Name und E-Mail-Adresse bei uns registriert sind, erhältst du in Kürze eine E-Mail mit weiteren Informationen.', + 'message-color' => 'green' + ])->render(); + fastcgi_finish_request(); + + if ($validRequest) { + $getReqTime = $this->app->db()->prepare('SELECT RequestTime FROM PasswordResetTokens WHERE PrincipalID=?'); + $getReqTime->execute([$uuid]); + if (($res = $getReqTime->fetch()) && time() - $res['RequestTime'] < 900) { + return; + } + + $token = Util::generateToken(32); + $setToken = $this->app->db()->prepare('REPLACE INTO PasswordResetTokens(PrincipalID,Token,RequestTime) VALUES(?,?,?)'); + $setToken->execute([$uuid, $token, time()]); + + $smtp = $this->app->config('smtp'); + $tplMail = $this->app->template('mail.php')->vars([ + 'title' => 'Dein Passwort zurücksetzen', + 'preheader' => 'So kannst du ein neues Passwort für deinen 4Creative-Account festlegen' + ])->unsafeVar('message', str_replace('%%NAME%%', $name, str_replace('%%RESET_LINK%%', 'https://'.$this->app->config('domain').'/index.php?page=reset-password&token='.$token, $this::MESSAGE))); + (new SmtpClient($smtp['host'], $smtp['port'], $smtp['address'], $smtp['password']))->sendHtml($smtp['address'], $smtp['name'], $email, 'Zurücksetzung des Passworts für '.$name, $tplMail); + } + } + } +} diff --git a/app/page/Friends.php b/app/page/Friends.php new file mode 100644 index 0000000..9ea788a --- /dev/null +++ b/app/page/Friends.php @@ -0,0 +1,66 @@ +config('domain'))); + } + + public function get(): void + { + $table = ''; + + $statement = $this->app->db()->prepare("SELECT PrincipalID,Friend FROM Friends WHERE PrincipalID = ? ORDER BY Friend ASC"); + $statement->execute([$_SESSION['UUID']]); + + $opensim = new OpenSim($this->app->db()); + + $csrf = $this->app->csrfField(); + while ($row = $statement->fetch()) { + $friendData = explode(";", $row['Friend']); + $friend = $friendData[0]; + + $name = trim($opensim->getUserName($friend)); + if (count($friendData) > 1) { + $friendData[1] = str_replace("http://", "", $friendData[1]); + $friendData[1] = str_replace("https://", "", $friendData[1]); + $friendData[1] = str_replace("/", "", $friendData[1]); + $name = $name.' @ '.strtolower($friendData[1]); + } + + $table = $table.''; + } + + $this->app->template('__dashboard.php')->vars([ + 'title' => 'Deine Freunde', + 'username' => $_SESSION['DISPLAYNAME'] + ])->unsafeVar('child-content', $table.'
NameOptionen
'.htmlspecialchars($name).'
'.$csrf.'
')->render(); + } + + public function post(): void + { + if (isset($_POST['remove'])) { + $validator = new FormValidator(array( + 'uuid' => array('required' => true, 'regex' => '/^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$/') + )); + + if ($validator->isValid($_POST)) { + $statementMembership = $this->app->db()->prepare("DELETE FROM Friends WHERE Friend = ? AND PrincipalID = ?"); + $statementMembership->execute(array($_REQUEST['uuid'], $_SESSION['UUID'])); + + $statementMembership = $this->app->db()->prepare("DELETE FROM Friends WHERE PrincipalID = ? AND Friend = ?"); + $statementMembership->execute(array($_REQUEST['uuid'], $_SESSION['UUID'])); + } + } + + header('Location: index.php?page=friends'); + } +} diff --git a/app/page/Groups.php b/app/page/Groups.php new file mode 100644 index 0000000..24386a1 --- /dev/null +++ b/app/page/Groups.php @@ -0,0 +1,52 @@ +config('domain'))); + } + + public function get(): void + { + $opensim = new OpenSim($this->app->db()); + + $table = ''; + + $statementGroups = $this->app->db()->prepare("SELECT Name,FounderID,os_groups_membership.GroupID FROM os_groups_groups JOIN os_groups_membership ON os_groups_groups.GroupID = os_groups_membership.GroupID WHERE PrincipalID = ?"); + $statementGroups->execute(array($_SESSION['UUID'])); + + $csrf = $this->app->csrfField(); + while ($rowGroups = $statementGroups->fetch()) { + $table = $table.''; + } + + $this->app->template('__dashboard.php')->vars([ + 'title' => 'Gruppen', + 'username' => $_SESSION['DISPLAYNAME'] + ])->unsafeVar('child-content', $table.'
NameGründerAktionen
'.htmlspecialchars($rowGroups['Name']).''.htmlspecialchars($opensim->getUserName($rowGroups['FounderID'])).'
'.$csrf.'
')->render(); + } + + public function post(): void + { + if (isset($_POST['leave'])) { + $validator = new FormValidator(array( + 'group' => array('required' => true, 'regex' => '/^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$/') + )); + + if ($validator->isValid($_POST)) { + $statementMembership = $this->app->db()->prepare("DELETE FROM os_groups_membership WHERE GroupID = ? AND PrincipalID = ?"); + $statementMembership->execute(array($_REQUEST['group'], $_SESSION['UUID'])); + } + } + + header('Location: index.php?page=groups'); + } +} diff --git a/app/page/Identities.php b/app/page/Identities.php new file mode 100644 index 0000000..d30c7eb --- /dev/null +++ b/app/page/Identities.php @@ -0,0 +1,147 @@ +config('domain'))); + } + + public function get(): void + { + $statementCheckForEntry = $this->app->db()->prepare("SELECT 1 FROM UserIdentitys WHERE PrincipalID = ? LIMIT 1"); + $statementCheckForEntry->execute(array($_SESSION['UUID'])); + + if ($statementCheckForEntry->rowCount() == 0) { + $statement = $this->app->db()->prepare('INSERT INTO `UserIdentitys` (PrincipalID, IdentityID) VALUES (:PrincipalID, :IdentityID)'); + $statement->execute(['PrincipalID' => $_SESSION['UUID'], 'IdentityID' => $_SESSION['UUID']]); + } + + $table = ''; + $statement = $this->app->db()->prepare("SELECT IdentityID FROM UserIdentitys WHERE PrincipalID = ? ORDER BY IdentityID ASC"); + $statement->execute(array($_SESSION['UUID'])); + + $opensim = new OpenSim($this->app->db()); + + $csrf = $this->app->csrfField(); + while ($row = $statement->fetch()) { + if ($row['IdentityID'] == $_SESSION['UUID']) { + $entry = ''; + } else { + $entry = ''; + } + + $table = $table.$entry; + } + + $message = ''; + if (isset($_SESSION['identities_err'])) { + $message = ''; + unset($_SESSION['identities_err']); + } + + $this->app->template('identities.php')->parent('__dashboard.php')->vars([ + 'title' => 'Identitäten', + 'username' => $_SESSION['DISPLAYNAME'], + 'message' => $message + ])->unsafeVar('ident-list', $table.'
NameAktionen
'.htmlspecialchars(trim($opensim->getUserName($row['IdentityID']))).' Aktiv-
'.htmlspecialchars(trim($opensim->getUserName($row['IdentityID']))).'
'.$csrf.'
')->render(); + } + + public function post(): void + { + if (isset($_POST['enableIdent'])) { + $validator = new FormValidator(array( + 'uuid' => array('required' => true, 'regex' => '/^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$/') + )); + + if ($validator->isValid($_POST)) { + $statement = $this->app->db()->prepare("SELECT 1 FROM UserIdentitys WHERE PrincipalID = :PrincipalID AND IdentityID = :IdentityID LIMIT 1"); + $statement->execute(['PrincipalID' => $_SESSION['UUID'], 'IdentityID' => $_POST['uuid']]); + + $statementPresence = $this->app->db()->prepare("SELECT 1 FROM Presence WHERE UserID = :PrincipalID LIMIT 1"); + $statementPresence->execute(['PrincipalID' => $_SESSION['UUID']]); + + if ($statementPresence->rowCount() == 0) { + if ($statement->rowCount() == 1) { + $statementAuth = $this->app->db()->prepare('UPDATE auth SET UUID = :IdentityID WHERE UUID = :PrincipalID'); + $statementAuth->execute(['IdentityID' => $_POST['uuid'], 'PrincipalID' => $_SESSION['UUID']]); + + $statementUserIdentitys = $this->app->db()->prepare('UPDATE UserIdentitys SET PrincipalID = :IdentityID WHERE PrincipalID = :PrincipalID'); + $statementUserIdentitys->execute(['IdentityID' => $_POST['uuid'], 'PrincipalID' => $_SESSION['UUID']]); + + $statementFriends = $this->app->db()->prepare('UPDATE Friends SET PrincipalID = :IdentityID WHERE PrincipalID = :PrincipalID'); + $statementFriends->execute(['IdentityID' => $_POST['uuid'], 'PrincipalID' => $_SESSION['UUID']]); + + //$statementReFriends = $this->app->db()->prepare('UPDATE Friends SET Friend = :IdentityID WHERE Friend = :PrincipalID'); + //$statementReFriends->execute(['IdentityID' => $_POST['uuid'], 'PrincipalID' => $_SESSION['UUID']]); + + $statementInventoryFolders = $this->app->db()->prepare('UPDATE inventoryfolders SET agentID = :IdentityID WHERE agentID = :PrincipalID AND type != :InventarTyp'); + $statementInventoryFolders->execute(['IdentityID' => $_POST['uuid'], 'PrincipalID' => $_SESSION['UUID'], 'InventarTyp' => 46]); + + $statementInventoryItems = $this->app->db()->prepare('UPDATE inventoryitems SET avatarID = :IdentityID WHERE avatarID = :PrincipalID'); + $statementInventoryItems->execute(['IdentityID' => $_POST['uuid'], 'PrincipalID' => $_SESSION['UUID']]); + + $statementGroupMembership = $this->app->db()->prepare('UPDATE os_groups_membership SET PrincipalID = :IdentityID WHERE PrincipalID = :PrincipalID'); + $statementGroupMembership->execute(['IdentityID' => $_POST['uuid'], 'PrincipalID' => $_SESSION['UUID']]); + + $statementGroupRoles = $this->app->db()->prepare('UPDATE os_groups_rolemembership SET PrincipalID = :IdentityID WHERE PrincipalID = :PrincipalID'); + $statementGroupRoles->execute(['IdentityID' => $_POST['uuid'], 'PrincipalID' => $_SESSION['UUID']]); + + $statementGroupRoles = $this->app->db()->prepare('DELETE FROM Presence WHERE UserID = :PrincipalID'); + $statementGroupRoles->execute(['PrincipalID' => $_SESSION['UUID']]); + + $_SESSION['LOGIN'] = 'false'; + session_destroy(); + } + } else { + $_SESSION['identities_err'] = 'Du kannst die Identität nicht ändern, während du angemeldet bist. Bitte schließe den Viewer.'; + } + } + } elseif (isset($_POST['createIdent'])) { + $validator = new FormValidator(array( + 'newName' => array('required' => true, 'regex' => '/^[^\\/<>\s]{1,64} [^\\/<>\s]{1,64}$/') + )); + + if ($validator->isValid($_POST)) { + $avatarNameParts = explode(" ", trim($_POST['newName'])); + + if (count($avatarNameParts) == 2) { + $statement = $this->app->db()->prepare("SELECT 1 FROM UserAccounts WHERE FirstName = :FirstName AND LastName = :LastName LIMIT 1"); + $statement->execute(['FirstName' => trim($avatarNameParts[0]), 'LastName' => trim($avatarNameParts[1])]); + + if ($statement->rowCount() == 0) { + $avatarUUID = (new OpenSim($this->app->db()))->generateUuid(); + + $statementAccounts = $this->app->db()->prepare('INSERT INTO UserAccounts (PrincipalID, ScopeID, FirstName, LastName, Email, ServiceURLs, Created, UserLevel, UserFlags, UserTitle, active) VALUES (:PrincipalID, :ScopeID, :FirstName, :LastName, :Email, :ServiceURLs, :Created, :UserLevel, :UserFlags, :UserTitle, :active )'); + $statementAccounts->execute(['PrincipalID' => $avatarUUID, 'ScopeID' => "00000000-0000-0000-0000-000000000000", 'FirstName' => $avatarNameParts[0], 'LastName' => $avatarNameParts[1], 'Email' => $_SESSION['EMAIL'], 'ServiceURLs' => "HomeURI= GatekeeperURI= InventoryServerURI= AssetServerURI= ", 'Created' => time(), 'UserLevel' => 0, 'UserFlags' => 0, 'UserTitle' => "", 'active' => 1]); + + $statementUserIdentitys = $this->app->db()->prepare('INSERT INTO UserIdentitys (PrincipalID, IdentityID) VALUES (:PrincipalID, :IdentityID)'); + $statementUserIdentitys->execute(['PrincipalID' => $_SESSION['UUID'], 'IdentityID' => $avatarUUID]); + } else { + $_SESSION['identities_err'] = 'Dieser Name ist schon in Benutzung.'; + } + } else { + $_SESSION['identities_err'] = 'Der Name muss aus einem Vor und einem Nachnamen bestehen.'; + } + } + } + elseif (isset($_POST['deleteIdent'])) { + $validator = new FormValidator(array( + 'uuid' => array('required' => true, 'regex' => '/^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$/') + )); + + if ($validator->isValid($_POST)) { + (new OpenSim($this->app->db()))->deleteIdentity($_SESSION['UUID'], $_POST['uuid']); + } + } + + header('Location: index.php?page=identities'); + } +} diff --git a/app/page/Login.php b/app/page/Login.php new file mode 100644 index 0000000..1f913e7 --- /dev/null +++ b/app/page/Login.php @@ -0,0 +1,93 @@ +config('domain'))); + } + + public function get(): void + { + $tpl = $this->app->template('login.php')->parent('__presession.php')->var('title', 'Login')->var('last-username', ''); + + if (isset($_SESSION) && isset($_SESSION['loginMessage'])) { + $tpl->vars([ + 'message' => $_SESSION['loginMessage'], + 'message-color' => $_SESSION['loginMessageColor'] + ]); + unset($_SESSION['loginMessage']); + unset($_SESSION['loginMessageColor']); + } else { + $tpl->vars([ + 'message' => '', + 'message-color' => 'red' + ]); + } + + $tpl->render(); + } + + public function post(): void + { + $validator = new FormValidator(array( + 'username' => array('required' => true, 'regex' => '/^[^\\/<>\s]{1,64} [^\\/<>\s]{1,64}$/'), + 'password' => array('required' => true, 'regex' => '/^.{1,1000}$/') + )); + + $tpl = $this->app->template('login.php')->parent('__presession.php')->var('title', 'Login'); + if (!$validator->isValid($_POST)) { + $tpl->vars([ + 'message' => 'Bitte gebe Benutzername (Vor- und Nachname) und Passwort ein.', + 'message-color' => 'red', + 'last-username'=> '' + ])->render(); + } else { + $statementUser = $this->app->db()->prepare("SELECT PrincipalID,FirstName,LastName,Email,UserLevel,passwordHash,passwordSalt FROM UserAccounts JOIN auth ON UserAccounts.PrincipalID = auth.UUID WHERE FirstName = ? AND LastName = ? LIMIT 1"); + $statementUser->execute(explode(" ", trim($_POST['username']))); + $res = ['passwordHash' => '', 'passwordSalt' => '']; + + if ($rowUser = $statementUser->fetch()) { + $res = $rowUser; + } + + if (hash_equals(md5(md5($_POST['password']).":".$res['passwordSalt']), $res['passwordHash'])) { + session_abort(); + session_set_cookie_params([ + 'lifetime' => 86400, + 'path' => '/', + 'domain' => $this->app->config('domain'), + 'httponly' => true, + 'secure' => true, + 'samesite' => 'Strict' + ]); + session_start(); + session_regenerate_id(true); + $_SESSION['FIRSTNAME'] = $rowUser['FirstName']; + $_SESSION['LASTNAME'] = $rowUser['LastName']; + $_SESSION['EMAIL'] = $rowUser['Email']; + $_SESSION['PASSWORD'] = $rowUser['passwordHash']; + $_SESSION['SALT'] = $rowUser['passwordSalt']; + $_SESSION['UUID'] = $rowUser['PrincipalID']; + $_SESSION['LEVEL'] = $rowUser['UserLevel']; + $_SESSION['DISPLAYNAME'] = strtoupper($rowUser['FirstName'].' '.$rowUser['LastName']); + $_SESSION['LOGIN'] = 'true'; + + header("Location: index.php?page=dashboard"); + die(); + } + + $tpl->vars([ + 'message' => 'Benutzername und/oder Passwort falsch.', + 'message-color' => 'red', + 'last-username' => $_POST['username'] + ])->render(); + } + } +} diff --git a/app/page/ManageUsers.php b/app/page/ManageUsers.php new file mode 100644 index 0000000..255b534 --- /dev/null +++ b/app/page/ManageUsers.php @@ -0,0 +1,111 @@ +config('domain'))); + } + + public function get(): void + { + $table = ''; + + // Only select current primary account + $statement = $this->app->db()->prepare("SELECT FirstName,LastName,UserLevel,PrincipalID FROM UserAccounts JOIN auth ON auth.UUID = UserAccounts.PrincipalID ORDER BY Created ASC"); + $statement->execute(); + + $statementIdent = $this->app->db()->prepare("SELECT FirstName,LastName,UserLevel,IdentityID FROM UserIdentitys JOIN UserAccounts ON UserAccounts.PrincipalID = UserIdentitys.IdentityID WHERE UserIdentitys.PrincipalID = ? AND UserIdentitys.PrincipalID != UserIdentitys.IdentityID"); + $csrf = $this->app->csrfField(); + while ($row = $statement->fetch()) { + $entry = ''; + $statementIdent->execute([$row['PrincipalID']]); + while ($identRow = $statementIdent->fetch()) { + $entry = $entry.''; + } + $table = $table.$entry; + } + + $tpl = $this->app->template('users.php')->parent('__dashboard.php')->var('title', 'Benutzer')->unsafeVar('user-list', $table.'
VornameNachnameStatusAktionen
'.htmlspecialchars($row['FirstName']).''.htmlspecialchars($row['LastName']).''.htmlspecialchars(strval($row['UserLevel'])).'
'.$csrf.'
'.htmlspecialchars($identRow['FirstName']).''.htmlspecialchars($identRow['LastName']).''.htmlspecialchars(strval($identRow['UserLevel'])).'
'.$csrf.'
') + ->unsafeVar('users-message', isset($_SESSION['users-message']) ? $_SESSION['users-message'] : '') + ->unsafeVar('custom-css', ''); + + if (isset($_SESSION['users-message'])) { + $tpl->unsafeVar('users-message', $_SESSION['users-message']); + unset($_SESSION['users-message']); + } + + if (isset($_SESSION['invite-id'])) { + $tpl->var('invite-link', 'https://'.$this->app->config('domain').'/index.php?page=register&code='.$_SESSION['invite-id']); + unset($_SESSION['invite-id']); + } + + $tpl->render(); + } + + public function post(): void + { + if (isset($_POST['generateLink'])) { + $validator = new FormValidator(array()); // Needed only for CSRF token validation + + if ($validator->isValid($_POST)) { + $inviteID = bin2hex(random_bytes(16)); + + $statement = $this->app->db()->prepare('INSERT INTO `InviteCodes` (`InviteCode`) VALUES (:InviteCode)'); + $statement->execute(['InviteCode' => $inviteID]); + + $_SESSION['invite-id'] = $inviteID; + } + } elseif (isset($_POST['delident'])) { + $validator = new FormValidator(array( + 'userid' => array('required' => true, 'regex' => '/^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$/'), + 'identid' => array('required' => true, 'regex' => '/^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$/') + )); + + if ($validator->isValid($_POST)) { + $os = new OpenSim($this->app->db()); + $identName = $os->getUserName($_POST['identid']); + $userName = $os->getUserName($_POST['userid']); + if ($os->deleteIdentity($_POST['userid'], $_POST['identid'])) { + $_SESSION['users-message'] = 'Identität '.$identName.' von '.$userName.' wurde gelöscht.'; + } else { + $_SESSION['users-message'] = 'Identität '.$identName.' konnte nicht gelöscht werden.'; + } + } + } else { + $validator = new FormValidator(array( + 'userid' => array('required' => true, 'regex' => '/^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$/') + )); + + if ($validator->isValid($_POST)) { + $opensim = new OpenSim($this->app->db()); + if (isset($_POST['genpw'])) { + $token = Util::generateToken(32); + $setToken = $this->app->db()->prepare('REPLACE INTO PasswordResetTokens(PrincipalID,Token,RequestTime) VALUES(?,?,?)'); + $setToken->execute([$_POST['userid'], $token, time()]); + $resetLink = "https://".$this->app->config('domain').'/index.php?page=reset-password&token='.$token; + + $_SESSION['users-message'] = 'Das Passwort für '.htmlspecialchars($opensim->getUserName($_POST['userid'])).' kann in den nächsten 24 Stunden über diesen Link zurückgesetzt werden: '.$resetLink.''; + } elseif (isset($_POST['deluser'])) { + $name = $opensim->getUserName($_POST['userid']); + if ($opensim->deleteUser($_POST['userid'])) { + $_SESSION['users-message'] = 'Der Account '.$name.' wurde gelöscht.'; + } else { + $_SESSION['users-message'] = 'Der Account '.$name.' konnte nicht gelöscht werden.'; + } + } + } + } + + header('Location: index.php?page=users'); + } +} diff --git a/app/page/OnlineUsers.php b/app/page/OnlineUsers.php new file mode 100644 index 0000000..7e18ef6 --- /dev/null +++ b/app/page/OnlineUsers.php @@ -0,0 +1,36 @@ +config('domain'))); + } + + public function get(): void + { + $opensim = new OpenSim($this->app->db()); + + $table = ''; + + $statement = $this->app->db()->prepare("SELECT RegionID,UserID FROM Presence ORDER BY RegionID ASC"); + $statement->execute(); + + while ($row = $statement->fetch()) { + if ($row['RegionID'] != "00000000-0000-0000-0000-000000000000") { + $table = $table.''; + } + } + + $this->app->template('__dashboard.php')->vars([ + 'title' => 'Online Anzeige', + 'username' => $_SESSION['DISPLAYNAME'] + ])->unsafeVar('child-content', $table.'
BenutzernameRegion
'.htmlspecialchars(trim($opensim->getUserName($row['UserID']))).''.htmlspecialchars($opensim->getRegionName($row['RegionID'])).'
')->render(); + } +} diff --git a/pages/profile.php b/app/page/Profile.php similarity index 53% rename from pages/profile.php rename to app/page/Profile.php index 97a77a2..c449e3a 100644 --- a/pages/profile.php +++ b/app/page/Profile.php @@ -1,38 +1,82 @@ prepare('SELECT 1 FROM UserAccounts WHERE '.$part.' = ? AND '.$otherPart.' = ?'); - $query->execute(array($value, $otherValue)); - - if ($query->rowCount() == 0) { - $statement = $RUNTIME['PDO']->prepare('UPDATE UserAccounts SET '.$part.' = ? WHERE PrincipalID = ?'); - $statement->execute(array($value, $_SESSION['UUID'])); - return true; - } - - return false; + parent::__construct($app, new LoginRequiredMiddleware($app, $app->config('domain'))); } - $statement = $RUNTIME['PDO']->prepare("CREATE TABLE IF NOT EXISTS `iarstates` (`userID` VARCHAR(36) NOT NULL COLLATE 'utf8_unicode_ci', `filesize` BIGINT(20) NOT NULL DEFAULT '0', `iarfilename` VARCHAR(64) NOT NULL COLLATE 'utf8_unicode_ci', `running` INT(1) NOT NULL DEFAULT '0', PRIMARY KEY (`userID`) USING BTREE) COLLATE='utf8_unicode_ci' ENGINE=InnoDB;"); - $statement->execute(); + public function get(): void + { + $tpl = $this->app->template('profile.php')->parent('__dashboard.php'); - //Prüfe ob IAR grade erstellt wird. - $statementIARCheck = $RUNTIME['PDO']->prepare('SELECT 1 FROM iarstates WHERE userID =:userID'); - $statementIARCheck->execute(['userID' => $_SESSION['UUID']]); - $IARRUNNING = $statementIARCheck->rowCount() != 0; - $statementIARCheck->closeCursor(); + $statement = $this->app->db()->prepare("CREATE TABLE IF NOT EXISTS `iarstates` (`userID` VARCHAR(36) NOT NULL COLLATE 'utf8_unicode_ci', `filesize` BIGINT(20) NOT NULL DEFAULT '0', `iarfilename` VARCHAR(64) NOT NULL COLLATE 'utf8_unicode_ci', `running` INT(1) NOT NULL DEFAULT '0', PRIMARY KEY (`userID`) USING BTREE) COLLATE='utf8_unicode_ci' ENGINE=InnoDB;"); + $statement->execute(); - if ($_SERVER['REQUEST_METHOD'] == 'POST') { - include_once 'app/FormValidator.php'; + //Prüfe ob IAR grade erstellt wird. + $statementIARCheck = $this->app->db()->prepare('SELECT 1 FROM iarstates WHERE userID =:userID'); + $statementIARCheck->execute(['userID' => $_SESSION['UUID']]); + $iarRunning = $statementIARCheck->rowCount() != 0; + $statementIARCheck->closeCursor(); + + if ($iarRunning) { + if (isset($_SESSION['iar_created'])) { + $tpl->unsafeVar('iar-message', ''); + } else { + $tpl->unsafeVar('iar-message', ''); + } + $tpl->var('iar-button-state', 'disabled'); + } + else { + $tpl->vars([ + 'iar-message' => ' ', + 'iar-state' => '' + ]); + } + + $opensim = new OpenSim($this->app->db()); + + $partnerUUID = $opensim->getPartner($_SESSION['UUID']); + $partnerName = ""; + + if ($partnerUUID != null) { + $partnerName = $opensim->getUserName($partnerUUID); + } + + $profileInfo = ''; + if (isset($_SESSION['profile_info'])) { + $profileInfo = $_SESSION['profile_info']; + unset($_SESSION['profile_info']); + } + $tpl->vars([ + 'title' => 'Dein Profil', + 'offline-im-state' => $opensim->allowOfflineIM($_SESSION['UUID']) == "TRUE" ? ' checked' : ' ', + 'firstname' => $_SESSION['FIRSTNAME'], + 'lastname' => $_SESSION['LASTNAME'], + 'partner' => $partnerName, + 'email' => $opensim->getUserMail($_SESSION['UUID']), + 'residents-js-array' => '', + 'message' => $profileInfo + ])->render(); + } + + public function post(): void + { if (isset($_POST['createIAR'])) { $validator = new FormValidator(array()); // CSRF validation only - if($validator->isValid($_POST) && !$IARRUNNING) { + if($validator->isValid($_POST)) { $iarname = md5(time().$_SESSION['UUID'] . rand()).".iar"; - $statementIARSTART = $RUNTIME['PDO']->prepare('INSERT INTO iarstates (userID, filesize, iarfilename) VALUES (:userID, :filesize, :iarfilename)'); + $statementIARSTART = $this->app->db()->prepare('INSERT INTO iarstates (userID, filesize, iarfilename) VALUES (:userID, :filesize, :iarfilename)'); $statementIARSTART->execute(['userID' => $_SESSION['UUID'], 'filesize' => 0, 'iarfilename' => $iarname]); $_SESSION['iar_created'] = true; @@ -49,11 +93,11 @@ if ($validator->isValid($_POST)) { if(isset($_POST['formInputFeldVorname'])) { - $NewFirstName = trim($_POST['formInputFeldVorname']); + $newFirstName = trim($_POST['formInputFeldVorname']); - if($NewFirstName != "" && $_SESSION['FIRSTNAME'] != $NewFirstName) { - if(setNamePart('FirstName', $NewFirstName, 'LastName', isset($_POST['formInputFeldNachname']) && strlen(trim($_POST['formInputFeldNachname'])) > 0 ? $_POST['formInputFeldNachname'] : $_SESSION['LASTNAME'])) { - $_SESSION['FIRSTNAME'] = $NewFirstName; + if($newFirstName != "" && $_SESSION['FIRSTNAME'] != $newFirstName) { + if($this->setNamePart('FirstName', $newFirstName, 'LastName', isset($_POST['formInputFeldNachname']) && strlen(trim($_POST['formInputFeldNachname'])) > 0 ? $_POST['formInputFeldNachname'] : $_SESSION['LASTNAME'])) { + $_SESSION['FIRSTNAME'] = $newFirstName; $_SESSION['USERNAME'] = $_SESSION['FIRSTNAME']." ".$_SESSION['LASTNAME']; $_SESSION['DISPLAYNAME'] = strtoupper($_SESSION['USERNAME']); } @@ -64,11 +108,11 @@ } if (isset($_POST['formInputFeldNachname'])) { - $NewLastName = trim($_POST['formInputFeldNachname']); + $newLastName = trim($_POST['formInputFeldNachname']); - if ($NewLastName != "" && $_SESSION['LASTNAME'] != $NewLastName) { - if (setNamePart('LastName', $NewLastName, 'FirstName', isset($_POST['formInputFeldVorname']) && strlen(trim($_POST['formInputFeldVorname'])) > 0 ? $_POST['formInputFeldVorname'] : $_SESSION['FIRSTNAME'])) { - $_SESSION['LASTNAME'] = $NewLastName; + if ($newLastName != "" && $_SESSION['LASTNAME'] != $newLastName) { + if ($this->setNamePart('LastName', $newLastName, 'FirstName', isset($_POST['formInputFeldVorname']) && strlen(trim($_POST['formInputFeldVorname'])) > 0 ? $_POST['formInputFeldVorname'] : $_SESSION['FIRSTNAME'])) { + $_SESSION['LASTNAME'] = $newLastName; $_SESSION['USERNAME'] = $_SESSION['FIRSTNAME']." ".$_SESSION['LASTNAME']; $_SESSION['DISPLAYNAME'] = strtoupper($_SESSION['USERNAME']); } else { @@ -78,47 +122,46 @@ } if (isset($_POST['formInputFeldEMail'])) { - $NewEMail = trim($_POST['formInputFeldEMail']); + $newEmail = trim($_POST['formInputFeldEMail']); - if ($NewEMail != "" && $_SESSION['EMAIL'] != $NewEMail) { - $statement = $RUNTIME['PDO']->prepare('UPDATE UserAccounts SET Email = :Email WHERE PrincipalID = :PrincipalID'); - $statement->execute(['Email' => $NewEMail, 'PrincipalID' => $_SESSION['UUID']]); + if ($newEmail != "" && $_SESSION['EMAIL'] != $newEmail) { + $statement = $this->app->db()->prepare('UPDATE UserAccounts SET Email = :Email WHERE PrincipalID = :PrincipalID'); + $statement->execute(['Email' => $newEmail, 'PrincipalID' => $_SESSION['UUID']]); - $statement = $RUNTIME['PDO']->prepare('UPDATE usersettings SET email = :Email WHERE useruuid = :PrincipalID'); - $statement->execute(['Email' => $NewEMail, 'PrincipalID' => $_SESSION['UUID']]); + $statement = $this->app->db()->prepare('UPDATE usersettings SET email = :Email WHERE useruuid = :PrincipalID'); + $statement->execute(['Email' => $newEmail, 'PrincipalID' => $_SESSION['UUID']]); - $_SESSION['EMAIL'] = $NewEMail; + $_SESSION['EMAIL'] = $newEmail; } } if (isset($_POST['formInputFeldOfflineIM']) && $_POST['formInputFeldOfflineIM'] == "on") { - $statement = $RUNTIME['PDO']->prepare('UPDATE usersettings SET imviaemail = :IMState WHERE useruuid = :PrincipalID'); + $statement = $this->app->db()->prepare('UPDATE usersettings SET imviaemail = :IMState WHERE useruuid = :PrincipalID'); $statement->execute(['IMState' => 'true', 'PrincipalID' => $_SESSION['UUID']]); } else { - $statement = $RUNTIME['PDO']->prepare('UPDATE usersettings SET imviaemail = :IMState WHERE useruuid = :PrincipalID'); + $statement = $this->app->db()->prepare('UPDATE usersettings SET imviaemail = :IMState WHERE useruuid = :PrincipalID'); $statement->execute(['IMState' => 'false', 'PrincipalID' => $_SESSION['UUID']]); } if (isset($_POST['formInputFeldPartnerName']) && $_POST['formInputFeldPartnerName'] != "") { - include_once 'app/OpenSim.php'; - $opensim = new OpenSim(); + $opensim = new OpenSim($this->app->db()); - $NewPartner = trim($_POST['formInputFeldPartnerName']); - $CurrentPartner = $opensim->getPartner($_SESSION['UUID']); + $newPartner = trim($_POST['formInputFeldPartnerName']); + $currentPartner = $opensim->getPartner($_SESSION['UUID']); - if ($CurrentPartner != "") { - $CurrentPartner = $opensim->getUserName($CurrentPartner); + if ($currentPartner != "") { + $currentPartner = $opensim->getUserName($currentPartner); } - if ($NewPartner != "" && $CurrentPartner != $NewPartner) { - $newPartnerUUID = $opensim->getUserUUID($NewPartner); + if ($newPartner != "" && $currentPartner != $newPartner) { + $newPartnerUUID = $opensim->getUserUUID($newPartner); if ($newPartnerUUID != null) { - $statement = $RUNTIME['PDO']->prepare('UPDATE userprofile SET profilePartner = :profilePartner WHERE useruuid = :PrincipalID'); + $statement = $this->app->db()->prepare('UPDATE userprofile SET profilePartner = :profilePartner WHERE useruuid = :PrincipalID'); $statement->execute(['profilePartner' => $newPartnerUUID, 'PrincipalID' => $_SESSION['UUID']]); } } else { - $statement = $RUNTIME['PDO']->prepare('UPDATE userprofile SET profilePartner = :profilePartner WHERE useruuid = :PrincipalID'); + $statement = $this->app->db()->prepare('UPDATE userprofile SET profilePartner = :profilePartner WHERE useruuid = :PrincipalID'); $statement->execute(['profilePartner' => '00000000-0000-0000-0000-000000000000', 'PrincipalID' => $_SESSION['UUID']]); } } @@ -132,11 +175,11 @@ if ($validator->isValid($_POST)) { if ($_POST['newPasswordRepeat'] == $_POST['newPassword']) { - if (strlen(trim($_POST['newPassword'])) >= $RUNTIME['PASSWORD_MIN_LENGTH']) { + if (strlen(trim($_POST['newPassword'])) >= $this->app->config('password-min-length')) { if (md5(md5($_POST['oldPassword']).':'.$_SESSION['SALT']) == $_SESSION['PASSWORD']) { $salt = bin2hex(random_bytes(16)); $hash = md5(md5(trim($_POST['newPassword'])).':'.$salt); - $statement = $RUNTIME['PDO']->prepare('UPDATE auth SET passwordHash = :PasswordHash, passwordSalt = :PasswordSalt WHERE UUID = :PrincipalID'); + $statement = $this->app->db()->prepare('UPDATE auth SET passwordHash = :PasswordHash, passwordSalt = :PasswordSalt WHERE UUID = :PrincipalID'); $statement->execute(['PasswordHash' => $hash, 'PasswordSalt' => $salt, 'PrincipalID' => $_SESSION['UUID']]); $_SESSION['PASSWORD'] = $hash; $_SESSION['SALT'] = $salt; @@ -145,7 +188,7 @@ $_SESSION['profile_info'] = 'Das alte Passwort ist nicht richtig!'; } } else { - $_SESSION['profile_info'] = 'Das neue Passwort muss mindestens '.$RUNTIME['PASSWORD_MIN_LENGTH'].' Zeichen lang sein.'; + $_SESSION['profile_info'] = 'Das neue Passwort muss mindestens '.$this->app->config('password-min-length').' Zeichen lang sein.'; } } else { $_SESSION['profile_info'] = 'Die neuen Passwörter stimmen nicht überein!'; @@ -161,9 +204,7 @@ if ($validator->isValid($_POST)) { if (hash_equals(md5(md5($_POST['delete-confirm-password']).':'.$_SESSION['SALT']), $_SESSION['PASSWORD'])) { - $uuid = $_SESSION['UUID']; - include_once 'app/OpenSim.php'; - $os = new OpenSim(); + $os = new OpenSim($this->app->db()); if ($os->deleteUser($_SESSION['UUID'])) { $_SESSION['LOGIN'] = false; session_destroy(); @@ -183,52 +224,21 @@ } header('Location: index.php?page=profile'); - die(); } - $HTML->setHTMLTitle("Dein Profile"); - $HTML->importSeitenInhalt("profile.html"); + private function setNamePart(string $part, string $value, string $otherPart, string $otherValue): bool + { + global $RUNTIME; - if ($IARRUNNING) { - if (isset($_SESSION['iar_created'])) { - $HTML->ReplaceSeitenInhalt("%%IARINFOMESSAGE%%", ''); - unset($_SESSION['iar_created']); - } else { - $HTML->ReplaceSeitenInhalt("%%IARINFOMESSAGE%%", ''); + $query = $RUNTIME['PDO']->prepare('SELECT 1 FROM UserAccounts WHERE '.$part.' = ? AND '.$otherPart.' = ?'); + $query->execute(array($value, $otherValue)); + + if ($query->rowCount() == 0) { + $statement = $RUNTIME['PDO']->prepare('UPDATE UserAccounts SET '.$part.' = ? WHERE PrincipalID = ?'); + $statement->execute(array($value, $_SESSION['UUID'])); + return true; } - $HTML->ReplaceSeitenInhalt("%%IARBUTTONSTATE%%", 'disabled'); + + return false; } - - include_once 'app/OpenSim.php'; - $opensim = new OpenSim(); - - $PartnerUUID = $opensim->getPartner($_SESSION['UUID']); - $PartnerName = ""; - - if ($PartnerUUID != null) { - $PartnerName = $opensim->getUserName($PartnerUUID); - } - - if ($opensim->allowOfflineIM($_SESSION['UUID']) == "TRUE") { - $HTML->ReplaceSeitenInhalt("%%offlineIMSTATE%%", ' checked'); - } - - $HTML->ReplaceSeitenInhalt("%%offlineIMSTATE%%", ' '); - $HTML->ReplaceSeitenInhalt("%%firstname%%", htmlspecialchars($_SESSION['FIRSTNAME'])); - $HTML->ReplaceSeitenInhalt("%%lastname%%", htmlspecialchars($_SESSION['LASTNAME'])); - $HTML->ReplaceSeitenInhalt("%%partner%%", htmlspecialchars($PartnerName)); - $HTML->ReplaceSeitenInhalt("%%email%%", htmlspecialchars($opensim->getUserMail($_SESSION['UUID']))); - $HTML->ReplaceSeitenInhalt("%%listAllResidentsAsJSArray%%", ""); - - $profileInfo = ''; - if (isset($_SESSION['profile_info'])) { - $profileInfo = $_SESSION['profile_info']; - unset($_SESSION['profile_info']); - } - $HTML->ReplaceSeitenInhalt("%%INFOMESSAGE%%", $profileInfo); - - $HTML->ReplaceSeitenInhalt("%%IARINFOMESSAGE%%", ' '); - $HTML->ReplaceSeitenInhalt("%%IARBUTTONSTATE%%", ''); - - $HTML->build(); - echo $HTML->ausgabe(); +} diff --git a/app/page/Regions.php b/app/page/Regions.php new file mode 100644 index 0000000..25447c1 --- /dev/null +++ b/app/page/Regions.php @@ -0,0 +1,93 @@ +config('domain')) : new LoginRequiredMiddleware($app, $app->config('domain'))); + } + + public function get(): void + { + $table = ''; + + $showAll = isset($_GET['SHOWALL']) && $_GET['SHOWALL'] == "1"; + $statement = $this->app->db()->prepare("SELECT uuid,regionName,owner_uuid,locX,locY FROM regions ".($showAll ? "ORDER BY owner_uuid ASC" : "WHERE owner_uuid = ? ORDER BY uuid ASC")); + $statement->execute($showAll ? array() : array($_SESSION['UUID'])); + + $opensim = new OpenSim($this->app->db()); + + $csrf = $this->app->csrfField(); + while ($row = $statement->fetch()) { + $stats = $this->getRegionStatsData($row['uuid']); + $table = $table.''; + } + + $this->app->template('__dashboard.php')->vars([ + 'title' => isset($_GET["SHOWALL"]) ? 'Regionen verwalten' : 'Deine Regionen', + 'username' => $_SESSION['DISPLAYNAME'] + ])->unsafeVar('child-content', $table.'
Region NameEigentümerPositionAktionen
'.htmlspecialchars($row['regionName']).''.htmlspecialchars($opensim->getUserName($row['owner_uuid'])).''.Util::fillString(($row['locX'] / 256), 4).' / '.Util::fillString(($row['locY'] / 256), 4).'
'.$csrf.'
')->render(); + } + + public function post(): void + { + $validator = new FormValidator(array( + 'remove' => array('required' => true), + 'region' => array('required' => true, 'regex' => '/^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$/') + )); + + if ($validator->isValid($_POST)) { + if (isset($_GET['SHOWALL'])) { + $statementMembership = $this->app->db()->prepare("DELETE FROM regions WHERE uuid = ?"); + $statementMembership->execute(array($_POST['region'])); + } else { + $statementMembership = $this->app->db()->prepare("DELETE FROM regions WHERE uuid = ? AND owner_uuid = ?"); + $statementMembership->execute(array($_POST['region'], $_SESSION['UUID'])); + } + } + + header('Location: index.php?page=regions'); + } + + private function cleanSize($bytes) + { + if ($bytes > 0) { + $unit = intval(log($bytes, 1024)); + $units = array('B', 'KB', 'MB', 'GB'); + + if (array_key_exists($unit, $units) === true) { + return sprintf('%d %s', $bytes / pow(1024, $unit), $units[$unit]); + } + } + + return $bytes; + } + + private function getRegionStatsData($regionID) + { + $statement = $this->app->db()->prepare("SELECT Prims,SimFPS,PhyFPS,ProcMem,RegionVersion FROM regions_info WHERE regionID = ?"); + $statement->execute([$regionID]); + + if ($row = $statement->fetch()) { + $return = array(); + $return['Prims'] = $row['Prims']; + $return['SimFPS'] = $row['SimFPS']; + $return['PhyFPS'] = $row['PhyFPS']; + $return['ProcMem'] = $this->cleanSize(str_replace(".", "", str_replace(",", ".", $row['ProcMem']))."000"); + $return['RegionVersion'] = trim($row['RegionVersion']); + + return $return; + } + + return array(); + } +} diff --git a/app/page/Register.php b/app/page/Register.php new file mode 100644 index 0000000..d0986b6 --- /dev/null +++ b/app/page/Register.php @@ -0,0 +1,182 @@ +config('domain'))); + } + + public function get(): void + { + if ($this->checkInvite()) { + $this->displayPage(); + } + } + + public function post(): void + { + $validator = new FormValidator(array( + 'tos' => array('required' => true, 'equals' => 'on'), + 'username' => array('required' => true, 'regex' => '/^[^\\/<>\s]{1,64}( [^\\/<>\s]{1,64})?$/'), + 'password' => array('required' => true, 'regex' => '/^.{1,1000}$/'), + 'email' => array('required' => true, 'regex' => '/^\S{1,64}@\S{1,250}.\S{2,64}$/'), + 'avatar' => array('required' => true) + )); + + if (!$validator->isValid($_POST)) { + if (!isset($_POST['tos']) || $_POST['tos'] !== true) { + $this->displayPage("Du musst die Nutzungsbedingungen lesen und Akzeptieren."); + } else { + $this->displayPage("Ups da stimmt was nicht. Versuche es bitte noch mal."); + } + + return; + } + + $name = trim($_POST['username']); + $nameParts = explode(" ", $name); + if ($name != "") { + if (count($nameParts) == 1) { + $name .= " Resident"; + $nameParts = explode(" ", $name); + } + + $statementAvatarName = $this->app->db()->prepare("SELECT 1 FROM UserAccounts WHERE FirstName = :FirstName AND LastName = :LastName LIMIT 1"); + $statementAvatarName->execute(['FirstName' => $nameParts[0], 'LastName' => $nameParts[1]]); + if ($statementAvatarName->rowCount() > 0) { + $this->displayPage("Der gewählte Name ist bereits vergeben."); + } + } + + $pass = trim($_POST['password']); + if (strlen($pass) < $this->app->config('password-min-length')) { + $this->displayPage('Dein Passwort muss mindestens '.$this->app->config('password-min-length').' Zeichen lang sein.'); + } + + $email = trim($_POST['email']); + + $avatar = null; + if (isset($this->app->config('default-avatar')[$_POST['avatar']]['UUID'])) { + $avatar = trim($_POST['avatar']); + } else { + $this->displayPage("Der gewählte Standardavatar existiert nicht."); + } + + $opensim = new OpenSim($this->app->db()); + + $avatarUUID = $opensim->generateUuid(); + $salt = bin2hex(random_bytes(16)); + $passwordHash = md5(md5($pass).':'.$salt); + + $statementInviteDeleter = $this->app->db()->prepare('DELETE FROM InviteCodes WHERE InviteCode = :code'); + $statementInviteDeleter->execute(['code' => $_REQUEST['code']]); + if ($statementInviteDeleter->rowCount() == 0) { + $this->displayError("Der angegebene Einladungscode ist nicht mehr gültig."); + } + + try { + $this->app->db()->beginTransaction(); + + $statementAuth = $this->app->db()->prepare('INSERT INTO `auth` (`UUID`, `passwordHash`, `passwordSalt`, `webLoginKey`, `accountType`) VALUES (:UUID, :HASHVALUE, :SALT, :WEBKEY, :ACCTYPE)'); + $statementAuth->execute(['UUID' => $avatarUUID, 'HASHVALUE' => $passwordHash, 'SALT' => $salt, 'WEBKEY' => "00000000-0000-0000-0000-000000000000", 'ACCTYPE' => "UserAccount"]); + + $statementAccounts = $this->app->db()->prepare('INSERT INTO `UserAccounts` (`PrincipalID`, `ScopeID`, `FirstName`, `LastName`, `Email`, `ServiceURLs`, `Created`, `UserLevel`, `UserFlags`, `UserTitle`, `active`) VALUES (:PrincipalID, :ScopeID, :FirstName, :LastName, :Email, :ServiceURLs, :Created, :UserLevel, :UserFlags, :UserTitle, :active )'); + $statementAccounts->execute(['PrincipalID' => $avatarUUID, 'ScopeID' => "00000000-0000-0000-0000-000000000000", 'FirstName' => $nameParts[0], 'LastName' => $nameParts[1], 'Email' => $email, 'ServiceURLs' => "HomeURI= GatekeeperURI= InventoryServerURI= AssetServerURI= ", 'Created' => time(), 'UserLevel' => 0, 'UserFlags' => 0, 'UserTitle' => "", 'active' => 1]); + + $statementProfile = $this->app->db()->prepare('INSERT INTO `userprofile` (`useruuid`, `profilePartner`, `profileImage`, `profileURL`, `profileFirstImage`, `profileAllowPublish`, `profileMaturePublish`, `profileWantToMask`, `profileWantToText`, `profileSkillsMask`, `profileSkillsText`, `profileLanguages`, `profileAboutText`, `profileFirstText`) VALUES (:useruuid, :profilePartner, :profileImage, :profileURL, :profileFirstImage, :profileAllowPublish, :profileMaturePublish, :profileWantToMask, :profileWantToText, :profileSkillsMask, :profileSkillsText, :profileLanguages, :profileAboutText, :profileFirstText)'); + $statementProfile->execute(['useruuid' => $avatarUUID, 'profilePartner' => "00000000-0000-0000-0000-000000000000", 'profileImage' => "00000000-0000-0000-0000-000000000000", 'profileURL' => '', 'profileFirstImage' => "00000000-0000-0000-0000-000000000000", "profileAllowPublish" => "0", "profileMaturePublish" => "0", "profileWantToMask" => "0", "profileWantToText" => "", "profileSkillsMask" => "0", "profileSkillsText" => "", "profileLanguages" => "", "profileAboutText" => "", "profileFirstText" => ""]); + + $statementInventoryFolder = $this->app->db()->prepare('INSERT INTO `inventoryfolders` (`folderName`, `type`, `version`, `folderID`, `agentID`, `parentFolderID`) VALUES (:folderName, :folderTyp, :folderVersion, :folderID, :agentID, :parentFolderID)'); + $inventory = array('Calling Cards' => 2, 'Objects' => 6, 'Landmarks' => 3, 'Clothing' => 5, 'Gestures' => 21, 'Body Parts' => 13, 'Textures' => 0, 'Scripts' => 10, 'Photo Album' => 15, 'Lost And Found' => 16, 'Trash' => 14, 'Notecards' => 7, 'My Inventory' => 8, 'Sounds' => 1, 'Animations' => 20); + $inventoryRootFolder = $opensim->generateUuid(); + foreach ($inventory as $folderName => $inventoryType) { + $folderUUID = $opensim->generateUuid(); + if ($inventoryType == 8) { + $folderUUID = $inventoryRootFolder; + $folderParent = "00000000-0000-0000-0000-000000000000"; + } else { + $folderParent = $inventoryRootFolder; + } + $statementInventoryFolder->execute(['agentID' => $avatarUUID, 'folderName' => $folderName, 'folderTyp' => $inventoryType, 'folderVersion' => 1, 'folderID' => $folderUUID, 'parentFolderID' => $folderParent]); + } + + $this->app->db()->commit(); + } catch (Exception $pdoException) { + $this->app->db()->rollBack(); + error_log('Could not create Account: '.$pdoException->getMessage()); + $this->displayPage('Fehler bei der Erstellung deines Accounts. Bitte versuche es später erneut.'); + } + + session_abort(); + session_set_cookie_params([ + 'lifetime' => 86400, + 'path' => '/', + 'domain' => $this->app->config('domain'), + 'httponly' => true, + 'secure' => true, + 'samesite' => 'Strict' + ]); + session_start(); + session_regenerate_id(true); + $_SESSION['FIRSTNAME'] = trim($nameParts[0]); + $_SESSION['LASTNAME'] = trim($nameParts[1]); + $_SESSION['EMAIL'] = $email; + $_SESSION['PASSWORD'] = $passwordHash; + $_SESSION['SALT'] = $salt; + $_SESSION['UUID'] = $avatarUUID; + $_SESSION['LEVEL'] = 0; + $_SESSION['DISPLAYNAME'] = strtoupper($name); + $_SESSION['LOGIN'] = 'true'; + + header('Location: index.php?page=dashboard'); + } + + private function displayPage(string $message = ''): void + { + $this->app->template('register.php')->parent('__presession.php')->vars([ + 'title' => 'Registrieren', + 'message' => $message, + 'tos-url' => $this->app->config('tos-url'), + 'invcode' => $_REQUEST['code'] + ])->render(); + } + + private function displayError(string $message): void + { + $this->app->template('error.php')->parent('__presession.php')->vars([ + 'error-message' => $message, + 'title' => 'Fehler' + ])->render(); + } + + private function checkInvite(): bool + { + if (!isset($_REQUEST['code'])) { + $this->displayError("Du benötigst einen Einladungscode, um dich bei 4Creative zu registrieren."); + } elseif (strlen($_REQUEST['code']) != 32 || !preg_match('/^[a-f0-9]+$/', $_REQUEST['code'])) { + $this->displayError("Der angegebene Einladungscode ist nicht gültig. Nutze genau den Link, der dir zugeschickt wurde."); + } else { + $statementInviteCode = $this->app->db()->prepare("SELECT 1 FROM InviteCodes WHERE InviteCode = ? LIMIT 1"); + $statementInviteCode->execute([$_REQUEST['code']]); + + if ($statementInviteCode->rowCount() == 0) { + $this->displayError("Der angegebene Einladungscode ist nicht gültig. Nutze genau den Link, der dir zugeschickt wurde."); + return false; + } + return true; + } + + return false; + } +} diff --git a/app/page/ResetPassword.php b/app/page/ResetPassword.php new file mode 100644 index 0000000..c7aa0f2 --- /dev/null +++ b/app/page/ResetPassword.php @@ -0,0 +1,110 @@ +
das Passwort für deinen 4Creative-Account wurde soeben über die Funktion "Passwort vergessen" geändert.

Solltest du diese Änderung nicht selbst durchgeführt haben, wende dich bitte umgehend per E-Mail (info@4creative.net) oder Discord (@ikeytan) an uns.'; + private const TOKEN_INVALID = 'Dieser Link zur Passwortzurücksetzung ist nicht gültig. Bitte klicke oder kopiere den Link aus der E-Mail, die du erhalten hast.'; + private const TOKEN_EXPIRED = 'Dein Link zur Passwortzurücksetzung ist abgelaufen. Klicke hier, um eine neue Anfrage zu senden.'; + + public function __construct(\Mcp\Mcp $app) + { + parent::__construct($app, new PreSessionMiddleware($app->config('domain'))); + } + + public function get(): void + { + $this->displayPage(); + } + + public function post(): void + { + $validator = new FormValidator(array( + 'password' => array('required' => true, 'regex' => '/^.{1,1000}$/'), + 'passwordRepeat' => array('required' => true, 'regex' => '/^.{1,1000}$/'), + 'resetToken' => array('required' => true, 'regex' => '/^[a-zA-Z0-9]{32}$/') + )); + + if ($validator->isValid($_POST)) { + if ($_POST['password'] !== $_POST['passwordRepeat']) { + $this->displayPage('Du musst in beiden Feldern das gleiche Passwort eingeben'); + return; + } + + if (strlen($_POST['password']) < $this->app->config('password-min-length')) { + $this->displayPage('Dein Passwort muss mindestens '.$this->app->config('password-min-length').' Zeichen lang sein.'); + return; + } + + $getReq = $this->app->db()->prepare('SELECT UserAccounts.PrincipalID AS UUID,FirstName,LastName,Email,Token,RequestTime FROM PasswordResetTokens JOIN UserAccounts ON UserAccounts.PrincipalID = PasswordResetTokens.PrincipalID WHERE Token = ?'); + $getReq->execute([$_POST['resetToken']]); + $res = $getReq->fetch(); + + if (!$res || !hash_equals($res['Token'], $_POST['resetToken'])) { + $this->displayTokenError($this::TOKEN_INVALID); + return; + } + + $uuid = $res['UUID']; + $name = $res['FirstName'].' '.$res['LastName']; + $getToken = $this->app->db()->prepare('DELETE FROM PasswordResetTokens WHERE PrincipalID = ? AND Token = ?'); + $getToken->execute([$uuid, $_POST['resetToken']]); + if ($getToken->rowCount() == 0) { + $this->displayTokenError($this::TOKEN_INVALID); + return; + } + + if (time() - $res['RequestTime'] > 86400) { + $this->displayTokenError($this::TOKEN_EXPIRED); + return; + } + + $salt = bin2hex(random_bytes(16)); + $hash = md5(md5(trim($_POST['password'])).':'.$salt); + $statement = $this->app->db()->prepare('UPDATE auth SET passwordHash = :PasswordHash, passwordSalt = :PasswordSalt WHERE UUID = :PrincipalID'); + $statement->execute(['PasswordHash' => $hash, 'PasswordSalt' => $salt, 'PrincipalID' => $uuid]); + + session_unset(); + $_SESSION['loginMessage'] = 'Du kannst dich jetzt mit deinem neuen Passwort einloggen!'; + $_SESSION['loginMessageColor'] = 'darkgreen'; + + $smtp = $this->app->config('smtp'); + $tplMail = $this->app->template('mail.php')->vars([ + 'title' => 'Passwort geändert', + 'preheader' => 'Das Passwort für deinen 4Creative-Account wurde soeben zurückgesetzt' + ])->unsafeVar('message', str_replace('%%NAME%%', $name, $this::MESSAGE)); + (new SmtpClient($smtp['host'], $smtp['port'], $smtp['address'], $smtp['password']))->sendHtml($smtp['address'], $smtp['name'], $res['Email'], 'Passwort für '.$name.' zurückgesetzt', $tplMail); + + header('Location: index.php?page=login'); + } + } + + private function displayTokenError(string $message): void + { + $this->app->template('error.php')->parent('__presession.php')->vars([ + 'title' => 'Fehler', + 'message' => $message + ])->render(); + } + + private function displayPage(string $message = ''): void + { + if (!isset($_GET['token']) || !preg_match('/^[a-z0-9A-Z]{32}$/', $_GET['token'])) { + displayTokenError(TOKEN_INVALID); + } + + $this->app->template('reset-password.php')->parent('__presession.php')->vars([ + 'title' => 'Neues Passwort festlegen', + 'message' => $message, + 'reset-token' => $_GET['token'] + ])->render(); + } +} diff --git a/pages/.htaccess b/pages/.htaccess deleted file mode 100644 index 14249c5..0000000 --- a/pages/.htaccess +++ /dev/null @@ -1 +0,0 @@ -Deny from all \ No newline at end of file diff --git a/pages/dashboard.php b/pages/dashboard.php deleted file mode 100644 index 2585503..0000000 --- a/pages/dashboard.php +++ /dev/null @@ -1,14 +0,0 @@ -setHTMLTitle("Dashboard"); - $HTML->importSeitenInhalt("dashboard-home.html"); - - $HTML->ReplaceSeitenInhalt("%%GLOBAL-USER-COUNT%%", $opensim->getUserCount()); - $HTML->ReplaceSeitenInhalt("%%GLOBAL-REGION-COUNT%%", $opensim->getRegionCount()); - - $HTML->ReplaceLayoutInhalt("%%USERNAME%%", htmlspecialchars($_SESSION['DISPLAYNAME'])); - - $HTML->build(); - echo $HTML->ausgabe(); diff --git a/pages/error.php b/pages/error.php deleted file mode 100644 index 18c1acd..0000000 --- a/pages/error.php +++ /dev/null @@ -1,6 +0,0 @@ -setHTMLTitle("Seite nicht gefunden"); - - $HTML->build(); - http_response_code(404); - echo $HTML->ausgabe(); diff --git a/pages/forgot.php b/pages/forgot.php deleted file mode 100644 index f923676..0000000 --- a/pages/forgot.php +++ /dev/null @@ -1,67 +0,0 @@ -
wir haben soeben eine Anfrage zur Zurücksetzung des Passworts für deinen 4Creative-Account erhalten.

Klicke hier, um ein neues Passwort festzulegen. Dieser Link läuft in 24 Stunden ab.

Falls du diese Anfrage nicht gesendet hast, ignoriere sie einfach. Bei weiteren Fragen kannst du uns unter info@4creative.net oder per Discord über @ikeytan erreichen.'; - - $HTML = new HTML(); - $HTML->setHTMLTitle("Passwort vergessen"); - $HTML->importHTML("forgot.html"); - - if ($_SERVER['REQUEST_METHOD'] == 'POST') { - include_once 'app/FormValidator.php'; - $validator = new FormValidator(array( - 'username' => array('required' => true, 'regex' => '/^[^\\/<>\s]{1,64} [^\\/<>\s]{1,64}$/'), - 'email' => array('required' => true, 'regex' => '/^\S{1,64}@\S{1,250}.\S{2,64}$/') - )); - - if (!$validator->isValid($_POST)) { - $HTML->ReplaceLayoutInhalt('%%MESSAGE%%', 'Bitte gebe deinen Benutzernamen (Vor- und Nachname) und die dazugehörige E-Mail-Adresse ein'); - $HTML->ReplaceLayoutInhalt('%%MESSAGECOLOR%%', 'red'); - $HTML->build(); - echo $HTML->ausgabe(); - } else { - $nameParts = explode(" ", $_POST['username']); - $email = strtolower(trim($_POST['email'])); - - $getAccount = $RUNTIME['PDO']->prepare('SELECT Email,FirstName,LastName,PrincipalID FROM UserAccounts WHERE FirstName = ? AND LastName = ? AND Email = ?'); - $getAccount->execute([trim($nameParts[0]), trim($nameParts[1]), $email]); - $validRequest = $getAccount->rowCount() == 1; - $uuid; - $name; - if ($res = $getAccount->fetch()) { - $email = $res['Email']; - $uuid = $res['PrincipalID']; - $name = $res['FirstName'].' '.$res['LastName']; - } - - foreach ($RUNTIME['RESET_BLOCKED_DOMAINS'] as $domain) { - if (str_ends_with($email, $domain)) { - $validRequest = false; - } - } - - $HTML->ReplaceLayoutInhalt('%%MESSAGE%%', 'Falls Name und E-Mail-Adresse bei uns registriert sind, erhältst du in Kürze eine E-Mail mit weiteren Informationen.'); - $HTML->ReplaceLayoutInhalt('%%MESSAGECOLOR%%', 'green'); - $HTML->build(); - echo $HTML->ausgabe(); - fastcgi_finish_request(); - - if ($validRequest) { - $getReqTime = $RUNTIME['PDO']->prepare('SELECT RequestTime FROM PasswordResetTokens WHERE PrincipalID=?'); - $getReqTime->execute([$uuid]); - if (($res = $getReqTime->fetch()) && time() - $res['RequestTime'] < 900) { - return; - } - - require_once 'app/utils.php'; - $token = generateToken(32); - $setToken = $RUNTIME['PDO']->prepare('REPLACE INTO PasswordResetTokens(PrincipalID,Token,RequestTime) VALUES(?,?,?)'); - $setToken->execute([$uuid, $token, time()]); - - sendMail($email, str_replace('%%NAME%%', $name, str_replace('%%RESET_LINK%%', 'https://'.$RUNTIME['DOMAIN'].'/index.php?page=reset-password&token='.$token, MESSAGE)), "Zurücksetzung des Passworts für ".$name, 'Dein Passwort zurücksetzen', 'Folge diesen Anweisungen, um ein neues Passwort für deinen 4Creative-Account festzulegen'); - } - } - } else { - $HTML->ReplaceLayoutInhalt('%%MESSAGE%%', ''); - $HTML->ReplaceLayoutInhalt('%%MESSAGECOLOR%%', 'red'); - $HTML->build(); - echo $HTML->ausgabe(); - } diff --git a/pages/friends.php b/pages/friends.php deleted file mode 100644 index 16002f3..0000000 --- a/pages/friends.php +++ /dev/null @@ -1,55 +0,0 @@ - array('required' => true, 'regex' => '/^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$/') - )); - - if ($validator->isValid($_POST)) { - $statementMembership = $RUNTIME['PDO']->prepare("DELETE FROM Friends WHERE Friend = ? AND PrincipalID = ?"); - $statementMembership->execute(array($_REQUEST['uuid'], $_SESSION['UUID'])); - - $statementMembership = $RUNTIME['PDO']->prepare("DELETE FROM Friends WHERE PrincipalID = ? AND Friend = ?"); - $statementMembership->execute(array($_REQUEST['uuid'], $_SESSION['UUID'])); - } - } - - header('Location: index.php?page=friends'); - die(); - } - - $HTML->setHTMLTitle("Deine Freunde"); - $HTML->importSeitenInhalt("online-anzeige.html"); - - $table = '%%ENTRY%%
NameOptionen
'; - - $statement = $RUNTIME['PDO']->prepare("SELECT PrincipalID,Friend FROM Friends WHERE PrincipalID = ? ORDER BY Friend ASC"); - $statement->execute([$_SESSION['UUID']]); - - include_once 'app/OpenSim.php'; - $opensim = new OpenSim(); - - while ($row = $statement->fetch()) { - $PrincipalID = explode(";", $row['PrincipalID'])[0]; - $FriendData = explode(";", $row['Friend']); - $Friend = $FriendData[0]; - - $name = trim($opensim->getUserName($Friend)); - if (count($FriendData) > 1) { - $FriendData[1] = str_replace("http://", "", $FriendData[1]); - $FriendData[1] = str_replace("https://", "", $FriendData[1]); - $FriendData[1] = str_replace("/", "", $FriendData[1]); - $name = $name.' @ '.strtolower($FriendData[1]); - } - - $entry = ''.htmlspecialchars($name).'
%%CSRF%%
'; - - $table = str_replace("%%ENTRY%%", $entry."%%ENTRY%%", $table); - } - - $table = str_replace("%%ENTRY%%", "", $table); - $HTML->ReplaceSeitenInhalt("%%ONLINE-LIST%%", $table); - - $HTML->build(); - echo $HTML->ausgabe(); diff --git a/pages/groups.php b/pages/groups.php deleted file mode 100644 index 92c9b68..0000000 --- a/pages/groups.php +++ /dev/null @@ -1,39 +0,0 @@ - array('required' => true, 'regex' => '/^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$/') - )); - - if ($validator->isValid($_POST)) { - $statementMembership = $RUNTIME['PDO']->prepare("DELETE FROM os_groups_membership WHERE GroupID = ? AND PrincipalID = ?"); - $statementMembership->execute(array($_REQUEST['group'], $_SESSION['UUID'])); - } - } - - header('Location: index.php?page=groups'); - die(); - } - - include_once 'app/OpenSim.php'; - $opensim = new OpenSim(); - - $HTML->setHTMLTitle("Gruppen"); - $HTML->importSeitenInhalt("deine-regionen.html"); - - $table = '%%ENTRY%%
NameGründerAktionen
'; - - $statementGroups = $RUNTIME['PDO']->prepare("SELECT Name,FounderID,os_groups_membership.GroupID FROM os_groups_groups JOIN os_groups_membership ON os_groups_groups.GroupID = os_groups_membership.GroupID WHERE PrincipalID = ?"); - $statementGroups->execute(array($_SESSION['UUID'])); - - while ($rowGroups = $statementGroups->fetch()) { - $entry = ''.htmlspecialchars($rowGroups['Name']).''.htmlspecialchars($opensim->getUserName($rowGroups['FounderID'])).'
%%CSRF%%
'; - $table = str_replace("%%ENTRY%%", $entry."%%ENTRY%%", $table); - } - - $table = str_replace("%%ENTRY%%", "", $table); - $HTML->ReplaceSeitenInhalt("%%REGION-LIST%%", $table); - - $HTML->build(); - echo $HTML->ausgabe(); diff --git a/pages/identities.php b/pages/identities.php deleted file mode 100644 index c2d6f7f..0000000 --- a/pages/identities.php +++ /dev/null @@ -1,141 +0,0 @@ -prepare("CREATE TABLE IF NOT EXISTS `UserIdentitys` (`PrincipalID` CHAR(36) NOT NULL, `IdentityID` CHAR(36) NOT NULL, PRIMARY KEY (`PrincipalID`, `IdentityID`)) ENGINE=MyISAM CHARSET=utf8mb3 COLLATE=utf8mb3_general_ci"); - $statementCreateTable->execute(); - $statementCreateTrigger = $RUNTIME['PDO']->prepare("CREATE TRIGGER IF NOT EXISTS del_id_trig AFTER DELETE ON UserAccounts FOR EACH ROW DELETE FROM UserIdentitys WHERE UserIdentitys.PrincipalID = OLD.PrincipalID OR UserIdentitys.IdentityID = OLD.PrincipalID"); - $statementCreateTrigger->execute(); - - if ($_SERVER['REQUEST_METHOD'] == 'POST') { - include_once 'app/FormValidator.php'; - if (isset($_POST['enableIdent'])) { - $validator = new FormValidator(array( - 'uuid' => array('required' => true, 'regex' => '/^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$/') - )); - - if ($validator->isValid($_POST)) { - $statement = $RUNTIME['PDO']->prepare("SELECT 1 FROM UserIdentitys WHERE PrincipalID = :PrincipalID AND IdentityID = :IdentityID LIMIT 1"); - $statement->execute(['PrincipalID' => $_SESSION['UUID'], 'IdentityID' => $_POST['uuid']]); - - $statementPresence = $RUNTIME['PDO']->prepare("SELECT 1 FROM Presence WHERE UserID = :PrincipalID LIMIT 1"); - $statementPresence->execute(['PrincipalID' => $_SESSION['UUID']]); - - if ($statementPresence->rowCount() == 0) { - if ($statement->rowCount() == 1) { - $statementAuth = $RUNTIME['PDO']->prepare('UPDATE auth SET UUID = :IdentityID WHERE UUID = :PrincipalID'); - $statementAuth->execute(['IdentityID' => $_POST['uuid'], 'PrincipalID' => $_SESSION['UUID']]); - - $statementUserIdentitys = $RUNTIME['PDO']->prepare('UPDATE UserIdentitys SET PrincipalID = :IdentityID WHERE PrincipalID = :PrincipalID'); - $statementUserIdentitys->execute(['IdentityID' => $_POST['uuid'], 'PrincipalID' => $_SESSION['UUID']]); - - $statementFriends = $RUNTIME['PDO']->prepare('UPDATE Friends SET PrincipalID = :IdentityID WHERE PrincipalID = :PrincipalID'); - $statementFriends->execute(['IdentityID' => $_POST['uuid'], 'PrincipalID' => $_SESSION['UUID']]); - - //$statementReFriends = $RUNTIME['PDO']->prepare('UPDATE Friends SET Friend = :IdentityID WHERE Friend = :PrincipalID'); - //$statementReFriends->execute(['IdentityID' => $_POST['uuid'], 'PrincipalID' => $_SESSION['UUID']]); - - $statementInventoryFolders = $RUNTIME['PDO']->prepare('UPDATE inventoryfolders SET agentID = :IdentityID WHERE agentID = :PrincipalID AND type != :InventarTyp'); - $statementInventoryFolders->execute(['IdentityID' => $_POST['uuid'], 'PrincipalID' => $_SESSION['UUID'], 'InventarTyp' => 46]); - - $statementInventoryItems = $RUNTIME['PDO']->prepare('UPDATE inventoryitems SET avatarID = :IdentityID WHERE avatarID = :PrincipalID'); - $statementInventoryItems->execute(['IdentityID' => $_POST['uuid'], 'PrincipalID' => $_SESSION['UUID']]); - - $statementGroupMembership = $RUNTIME['PDO']->prepare('UPDATE os_groups_membership SET PrincipalID = :IdentityID WHERE PrincipalID = :PrincipalID'); - $statementGroupMembership->execute(['IdentityID' => $_POST['uuid'], 'PrincipalID' => $_SESSION['UUID']]); - - $statementGroupRoles = $RUNTIME['PDO']->prepare('UPDATE os_groups_rolemembership SET PrincipalID = :IdentityID WHERE PrincipalID = :PrincipalID'); - $statementGroupRoles->execute(['IdentityID' => $_POST['uuid'], 'PrincipalID' => $_SESSION['UUID']]); - - $statementGroupRoles = $RUNTIME['PDO']->prepare('DELETE FROM Presence WHERE UserID = :PrincipalID'); - $statementGroupRoles->execute(['PrincipalID' => $_SESSION['UUID']]); - - $_SESSION['LOGIN'] = 'false'; - session_destroy(); - } - } else { - $_SESSION['identities_err'] = 'Du kannst die Identität nicht ändern, während du angemeldet bist. Bitte schließe den Viewer.'; - } - } - } elseif (isset($_POST['createIdent'])) { - $validator = new FormValidator(array( - 'newName' => array('required' => true, 'regex' => '/^[^\\/<>\s]{1,64} [^\\/<>\s]{1,64}$/') - )); - - if ($validator->isValid($_POST)) { - $avatarNameParts = explode(" ", trim($_POST['newName'])); - - if (count($avatarNameParts) == 2) { - $statement = $RUNTIME['PDO']->prepare("SELECT 1 FROM UserAccounts WHERE FirstName = :FirstName AND LastName = :LastName LIMIT 1"); - $statement->execute(['FirstName' => trim($avatarNameParts[0]), 'LastName' => trim($avatarNameParts[1])]); - - if ($statement->rowCount() == 0) { - include_once 'app/OpenSim.php'; - $avatarUUID = (new OpenSim())->gen_uuid(); - - $statementAccounts = $RUNTIME['PDO']->prepare('INSERT INTO UserAccounts (PrincipalID, ScopeID, FirstName, LastName, Email, ServiceURLs, Created, UserLevel, UserFlags, UserTitle, active) VALUES (:PrincipalID, :ScopeID, :FirstName, :LastName, :Email, :ServiceURLs, :Created, :UserLevel, :UserFlags, :UserTitle, :active )'); - $statementAccounts->execute(['PrincipalID' => $avatarUUID, 'ScopeID' => "00000000-0000-0000-0000-000000000000", 'FirstName' => $avatarNameParts[0], 'LastName' => $avatarNameParts[1], 'Email' => $_SESSION['EMAIL'], 'ServiceURLs' => "HomeURI= GatekeeperURI= InventoryServerURI= AssetServerURI= ", 'Created' => time(), 'UserLevel' => 0, 'UserFlags' => 0, 'UserTitle' => "", 'active' => 1]); - - $statementUserIdentitys = $RUNTIME['PDO']->prepare('INSERT INTO UserIdentitys (PrincipalID, IdentityID) VALUES (:PrincipalID, :IdentityID)'); - $statementUserIdentitys->execute(['PrincipalID' => $_SESSION['UUID'], 'IdentityID' => $avatarUUID]); - } else { - $_SESSION['identities_err'] = 'Dieser Name ist schon in Benutzung.'; - } - } else { - $_SESSION['identities_err'] = 'Der Name muss aus einem Vor und einem Nachnamen bestehen.'; - } - } - } - elseif (isset($_POST['deleteIdent'])) { - $validator = new FormValidator(array( - 'uuid' => array('required' => true, 'regex' => '/^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$/') - )); - - if ($validator->isValid($_POST)) { - include_once 'app/OpenSim.php'; - (new OpenSim())->deleteIdentity($_SESSION['UUID'], $_POST['uuid']); - } - } - - header('Location: index.php?page=identities'); - die(); - } - - $HTML->setHTMLTitle("Identitäten"); - $HTML->importSeitenInhalt("identities.html"); - - $statementCheckForEntry = $RUNTIME['PDO']->prepare("SELECT 1 FROM UserIdentitys WHERE PrincipalID = ? LIMIT 1"); - $statementCheckForEntry->execute(array($_SESSION['UUID'])); - - if ($statementCheckForEntry->rowCount() == 0) { - $statement = $RUNTIME['PDO']->prepare('INSERT INTO `UserIdentitys` (PrincipalID, IdentityID) VALUES (:PrincipalID, :IdentityID)'); - $statement->execute(['PrincipalID' => $_SESSION['UUID'], 'IdentityID' => $_SESSION['UUID']]); - } - - $table = '%%ENTRY%%
NameAktionen
'; - $statement = $RUNTIME['PDO']->prepare("SELECT IdentityID FROM UserIdentitys WHERE PrincipalID = ? ORDER BY IdentityID ASC"); - $statement->execute(array($_SESSION['UUID'])); - - include_once 'app/OpenSim.php'; - $opensim = new OpenSim(); - - while ($row = $statement->fetch()) { - if ($row['IdentityID'] == $_SESSION['UUID']) { - $entry = ''.htmlspecialchars(trim($opensim->getUserName($row['IdentityID']))).' Aktiv-'; - } else { - $entry = ''.htmlspecialchars(trim($opensim->getUserName($row['IdentityID']))).'
%%CSRF%%
'; - } - - $table = str_replace("%%ENTRY%%", $entry."%%ENTRY%%", $table); - } - - $table = str_replace("%%ENTRY%%", "", $table); - $HTML->ReplaceSeitenInhalt("%%IDENT-LIST%%", $table); - $HTML->ReplaceSeitenInhalt("%%link%%", ' '); - - $message = ''; - if (isset($_SESSION['identities_err'])) { - $message = ''; - unset($_SESSION['identities_err']); - } - $HTML->ReplaceSeitenInhalt("%%MESSAGE%%", $message); - - $HTML->build(); - echo $HTML->ausgabe(); diff --git a/pages/invite.php b/pages/invite.php deleted file mode 100644 index d0c8cd7..0000000 --- a/pages/invite.php +++ /dev/null @@ -1,17 +0,0 @@ -setHTMLTitle("Kein Zugriff"); - $HTML->SetSeitenInhalt("Dazu hast du keine Rechte!"); - $HTML->build(); - echo $HTML->ausgabe(); - die(); - } - - $HTML->setHTMLTitle("Benutzer"); - $HTML->importSeitenInhalt("users.html"); - - - $HTML->ReplaceSeitenInhalt("%%link%%", ' '); - - $HTML->build(); - echo $HTML->ausgabe(); diff --git a/pages/login.php b/pages/login.php deleted file mode 100644 index 70d8a34..0000000 --- a/pages/login.php +++ /dev/null @@ -1,55 +0,0 @@ -setHTMLTitle("Login"); - $HTML->importHTML("login.html"); - - if ($_SERVER['REQUEST_METHOD'] == 'POST') { - include_once 'app/FormValidator.php'; - $validator = new FormValidator(array( - 'username' => array('required' => true, 'regex' => '/^[^\\/<>\s]{1,64} [^\\/<>\s]{1,64}$/'), - 'password' => array('required' => true, 'regex' => '/^.{1,1000}$/') - )); - - if (!$validator->isValid($_POST)) { - $HTML->ReplaceLayoutInhalt("%%LOGINMESSAGE%%", "Bitte gebe Benutzername (Vor- und Nachname) und Passwort ein."); - } else { - $statementUser = $RUNTIME['PDO']->prepare("SELECT PrincipalID,FirstName,LastName,Email,UserLevel,passwordHash,passwordSalt FROM UserAccounts JOIN auth ON UserAccounts.PrincipalID = auth.UUID WHERE FirstName = ? AND LastName = ? LIMIT 1"); - $statementUser->execute(explode(" ", trim($_POST['username']))); - $res = ['passwordHash' => '', 'passwordSalt' => '']; - - if ($rowUser = $statementUser->fetch()) { - $res = $rowUser; - } - - if (hash_equals(md5(md5($_POST['password']).":".$res['passwordSalt']), $res['passwordHash'])) { - session_unset(); // Unset pre-session variables, next request will generate a new CSRF token - $_SESSION['FIRSTNAME'] = $rowUser['FirstName']; - $_SESSION['LASTNAME'] = $rowUser['LastName']; - $_SESSION['EMAIL'] = $rowUser['Email']; - $_SESSION['PASSWORD'] = $rowUser['passwordHash']; - $_SESSION['SALT'] = $rowUser['passwordSalt']; - $_SESSION['UUID'] = $rowUser['PrincipalID']; - $_SESSION['LEVEL'] = $rowUser['UserLevel']; - $_SESSION['DISPLAYNAME'] = strtoupper($rowUser['FirstName'].' '.$rowUser['LastName']); - $_SESSION['LOGIN'] = 'true'; - - header("Location: index.php?page=dashboard"); - die(); - } - - $HTML->ReplaceLayoutInhalt("%%LOGINMESSAGE%%", "Benutzername und/oder Passwort falsch."); - $HTML->ReplaceLayoutInhalt("%%LASTUSERNAME%%", htmlspecialchars($_POST['username'])); - } - } elseif (isset($_SESSION) && isset($_SESSION['loginMessage'])) { - $HTML->ReplaceLayoutInhalt('%%LOGINMESSAGE%%', $_SESSION['loginMessage']); - $HTML->ReplaceLayoutInhalt('%%MESSAGECOLOR%%', $_SESSION['loginMessageColor']); - unset($_SESSION['loginMessage']); - unset($_SESSION['loginMessageColor']); - } - - $HTML->ReplaceLayoutInhalt("%%LOGINMESSAGE%%", ""); - $HTML->ReplaceLayoutInhalt("%%MESSAGECOLOR%%", "red"); - $HTML->ReplaceLayoutInhalt("%%LASTUSERNAME%%", ""); - - $HTML->build(); - echo $HTML->ausgabe(); diff --git a/pages/regions.php b/pages/regions.php deleted file mode 100644 index 4b85a9e..0000000 --- a/pages/regions.php +++ /dev/null @@ -1,80 +0,0 @@ -setHTMLTitle("Deine Regionen"); - $HTML->importSeitenInhalt("deine-regionen.html"); - - function cleanSize($bytes) - { - if ($bytes > 0) { - $unit = intval(log($bytes, 1024)); - $units = array('B', 'KB', 'MB', 'GB'); - - if (array_key_exists($unit, $units) === true) { - return sprintf('%d %s', $bytes / pow(1024, $unit), $units[$unit]); - } - } - - return $bytes; - } - - function getRegionStatsData($regionID) - { - global $RUNTIME; - - $statement = $RUNTIME['PDO']->prepare("SELECT Prims,SimFPS,PhyFPS,ProcMem,RegionVersion FROM regions_info WHERE regionID = ?"); - $statement->execute([$regionID]); - - if ($row = $statement->fetch()) { - $return = array(); - $return['Prims'] = $row['Prims']; - $return['SimFPS'] = $row['SimFPS']; - $return['PhyFPS'] = $row['PhyFPS']; - $return['ProcMem'] = cleanSize(str_replace(".", "", str_replace(",", ".", $row['ProcMem']))."000"); - $return['RegionVersion'] = trim($row['RegionVersion']); - - return $return; - } - - return array(); - } - - if ($_SERVER['REQUEST_METHOD'] == 'POST' && isset($_REQUEST['remove'])) { - include_once 'app/FormValidator.php'; - $validator = new FormValidator(array( - 'region' => array('required' => true, 'regex' => '/^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$/') - )); - - if ($validator->isValid($_POST)) { - if (isset($_SESSION['LEVEL']) && $_SESSION['LEVEL'] >= 100) { - $statementMembership = $RUNTIME['PDO']->prepare("DELETE FROM regions WHERE uuid = ?"); - $statementMembership->execute(array($_POST['region'])); - } else { - $statementMembership = $RUNTIME['PDO']->prepare("DELETE FROM regions WHERE uuid = ? AND owner_uuid = ?"); - $statementMembership->execute(array($_POST['region'], $_SESSION['UUID'])); - } - } - - header('Location: index.php?page=regions'); - die(); - } - - $table = '%%ENTRY%%
Region NameEigentümerPositionAktionen
'; - - $showAll = isset($_SESSION['LEVEL']) && $_SESSION['LEVEL'] >= 100 && isset($_REQUEST['SHOWALL']) && $_REQUEST['SHOWALL'] == "1"; - $statement = $RUNTIME['PDO']->prepare("SELECT uuid,regionName,owner_uuid,locX,locY FROM regions ".($showAll ? "ORDER BY owner_uuid ASC" : "WHERE owner_uuid = ? ORDER BY uuid ASC")); - $statement->execute($showAll ? array() : array($_SESSION['UUID'])); - - include_once 'app/OpenSim.php'; - $opensim = new OpenSim(); - - while ($row = $statement->fetch()) { - $stats = getRegionStatsData($row['uuid']); - - $entry = ''.htmlspecialchars($row['regionName']).''.htmlspecialchars($opensim->getUserName($row['owner_uuid'])).''.fillString(($row['locX'] / 256), 4).' / '.fillString(($row['locY'] / 256), 4).'
%%CSRF%%
'; - $table = str_replace("%%ENTRY%%", $entry."%%ENTRY%%", $table); - } - - $table = str_replace("%%ENTRY%%", "", $table); - $HTML->ReplaceSeitenInhalt("%%REGION-LIST%%", $table); - - $HTML->build(); - echo $HTML->ausgabe(); diff --git a/pages/register.php b/pages/register.php deleted file mode 100644 index 2951246..0000000 --- a/pages/register.php +++ /dev/null @@ -1,154 +0,0 @@ -setHTMLTitle("Registrieren"); - $HTML->importHTML("register.html"); - - $HTML->ReplaceLayoutInhalt("%%MESSAGE%%", $message); - $HTML->ReplaceLayoutInhalt("%%tosURL%%", $RUNTIME['TOOLS']['TOS'] ); - $HTML->ReplaceLayoutInhalt("%%INVCODE%%", htmlspecialchars($_REQUEST['code'])); - - $HTML->build(); - echo $HTML->ausgabe(); - die(); - } - - function displayError(string $message) - { - $HTML = new HTML(); - $HTML->importHTML("error.html"); - $HTML->ReplaceLayoutInhalt("%%MESSAGE%%", $message); - $HTML->build(); - echo $HTML->ausgabe(); - die(); - } - - if (!isset($_REQUEST['code'])) { - displayError("Du benötigst einen Einladungscode, um dich bei 4Creative zu registrieren."); - } - - if (strlen($_REQUEST['code']) != 32 || !preg_match('/^[a-f0-9]+$/', $_REQUEST['code'])) { - displayError("Der angegebene Einladungscode ist nicht gültig. Nutze genau den Link, der dir zugeschickt wurde."); - } - - $statementInviteCode = $RUNTIME['PDO']->prepare("SELECT 1 FROM InviteCodes WHERE InviteCode = ? LIMIT 1"); - $statementInviteCode->execute([$_REQUEST['code']]); - - if ($statementInviteCode->rowCount() == 0) { - displayError("Der angegebene Einladungscode ist nicht gültig. Nutze genau den Link, der dir zugeschickt wurde."); - } - - if ($_SERVER['REQUEST_METHOD'] != 'POST') { - displayPage(""); - } - - include_once 'app/FormValidator.php'; - $validator = new FormValidator(array( - 'tos' => array('required' => true, 'equals' => 'on'), - 'username' => array('required' => true, 'regex' => '/^[^\\/<>\s]{1,64}( [^\\/<>\s]{1,64})?$/'), - 'password' => array('required' => true, 'regex' => '/^.{1,1000}$/'), - 'email' => array('required' => true, 'regex' => '/^\S{1,64}@\S{1,250}.\S{2,64}$/'), - 'avatar' => array('required' => true) - )); - - if (!$validator->isValid($_POST)) { - if (!isset($_POST['tos']) || $_POST['tos'] !== true) { - displayPage("Du musst die Nutzungsbedingungen lesen und Akzeptieren."); - } else { - displayPage("Ups da stimmt was nicht. Versuche es bitte noch mal."); - } - - die(); - } - - $name = trim($_POST['username']); - $nameParts; - if ($name != "") { - $nameParts = explode(" ", $name); - if (count($nameParts) == 1) { - $name .= " Resident"; - $nameParts = explode(" ", $name); - } - - $statementAvatarName = $RUNTIME['PDO']->prepare("SELECT 1 FROM UserAccounts WHERE FirstName = :FirstName AND LastName = :LastName LIMIT 1"); - $statementAvatarName->execute(['FirstName' => $nameParts[0], 'LastName' => $nameParts[1]]); - if ($statementAvatarName->rowCount() > 0) { - displayPage("Der gewählte Name ist bereits vergeben."); - } - } - - $pass = trim($_POST['password']); - if (strlen($pass) < $RUNTIME['PASSWORD_MIN_LENGTH']) { - displayPage('Dein Passwort muss mindestens '.$RUNTIME['PASSWORD_MIN_LENGTH'].' Zeichen lang sein.'); - } - - $email = trim($_POST['email']); - - $avatar; - if (isset($RUNTIME['DEFAULTAVATAR'][$_POST['avatar']]['UUID'])) { - $avatar = trim($_POST['avatar']); - } else { - displayPage("Der gewählte Standardavatar existiert nicht."); - } - - include_once 'app/OpenSim.php'; - $opensim = new OpenSim(); - - $avatarUUID = $opensim->gen_uuid(); - $salt = bin2hex(random_bytes(16)); - $passwordHash = md5(md5($pass).':'.$salt); - - $statementInviteDeleter = $RUNTIME['PDO']->prepare('DELETE FROM InviteCodes WHERE InviteCode = :code'); - $statementInviteDeleter->execute(['code' => $_REQUEST['code']]); - if ($statementInviteDeleter->rowCount() == 0) { - displayError("Der angegebene Einladungscode ist nicht mehr gültig."); - } - - try { - $RUNTIME['PDO']->beginTransaction(); - - $statementAuth = $RUNTIME['PDO']->prepare('INSERT INTO `auth` (`UUID`, `passwordHash`, `passwordSalt`, `webLoginKey`, `accountType`) VALUES (:UUID, :HASHVALUE, :SALT, :WEBKEY, :ACCTYPE)'); - $statementAuth->execute(['UUID' => $avatarUUID, 'HASHVALUE' => $passwordHash, 'SALT' => $salt, 'WEBKEY' => "00000000-0000-0000-0000-000000000000", 'ACCTYPE' => "UserAccount"]); - - $statementAccounts = $RUNTIME['PDO']->prepare('INSERT INTO `UserAccounts` (`PrincipalID`, `ScopeID`, `FirstName`, `LastName`, `Email`, `ServiceURLs`, `Created`, `UserLevel`, `UserFlags`, `UserTitle`, `active`) VALUES (:PrincipalID, :ScopeID, :FirstName, :LastName, :Email, :ServiceURLs, :Created, :UserLevel, :UserFlags, :UserTitle, :active )'); - $statementAccounts->execute(['PrincipalID' => $avatarUUID, 'ScopeID' => "00000000-0000-0000-0000-000000000000", 'FirstName' => $nameParts[0], 'LastName' => $nameParts[1], 'Email' => $email, 'ServiceURLs' => "HomeURI= GatekeeperURI= InventoryServerURI= AssetServerURI= ", 'Created' => time(), 'UserLevel' => 0, 'UserFlags' => 0, 'UserTitle' => "", 'active' => 1]); - - $statementProfile = $RUNTIME['PDO']->prepare('INSERT INTO `userprofile` (`useruuid`, `profilePartner`, `profileImage`, `profileURL`, `profileFirstImage`, `profileAllowPublish`, `profileMaturePublish`, `profileWantToMask`, `profileWantToText`, `profileSkillsMask`, `profileSkillsText`, `profileLanguages`, `profileAboutText`, `profileFirstText`) VALUES (:useruuid, :profilePartner, :profileImage, :profileURL, :profileFirstImage, :profileAllowPublish, :profileMaturePublish, :profileWantToMask, :profileWantToText, :profileSkillsMask, :profileSkillsText, :profileLanguages, :profileAboutText, :profileFirstText)'); - $statementProfile->execute(['useruuid' => $avatarUUID, 'profilePartner' => "00000000-0000-0000-0000-000000000000", 'profileImage' => "00000000-0000-0000-0000-000000000000", 'profileURL' => '', 'profileFirstImage' => "00000000-0000-0000-0000-000000000000", "profileAllowPublish" => "0", "profileMaturePublish" => "0", "profileWantToMask" => "0", "profileWantToText" => "", "profileSkillsMask" => "0", "profileSkillsText" => "", "profileLanguages" => "", "profileAboutText" => "", "profileFirstText" => ""]); - - $statementInventoryFolder = $RUNTIME['PDO']->prepare('INSERT INTO `inventoryfolders` (`folderName`, `type`, `version`, `folderID`, `agentID`, `parentFolderID`) VALUES (:folderName, :folderTyp, :folderVersion, :folderID, :agentID, :parentFolderID)'); - $Inventory = array('Calling Cards' => 2, 'Objects' => 6, 'Landmarks' => 3, 'Clothing' => 5, 'Gestures' => 21, 'Body Parts' => 13, 'Textures' => 0, 'Scripts' => 10, 'Photo Album' => 15, 'Lost And Found' => 16, 'Trash' => 14, 'Notecards' => 7, 'My Inventory' => 8, 'Sounds' => 1, 'Animations' => 20); - $InventoryRootFolder = $opensim->gen_uuid(); - foreach ($Inventory as $FolderName => $InventoryType) { - $FolderUUID = $opensim->gen_uuid(); - if ($InventoryType == 8) { - $FolderUUID = $InventoryRootFolder; - $FolderParent = "00000000-0000-0000-0000-000000000000"; - } else { - $FolderParent = $InventoryRootFolder; - } - $statementInventoryFolder->execute(['agentID' => $avatarUUID, 'folderName' => $FolderName, 'folderTyp' => $InventoryType, 'folderVersion' => 1, 'folderID' => $FolderUUID, 'parentFolderID' => $FolderParent]); - } - - $RUNTIME['PDO']->commit(); - } catch (Exception $pdoException) { - $RUNTIME['PDO']->rollBack(); - error_log('Could not create Account: '.$pdoException->getMessage()); - displayPage('Fehler bei der Erstellung deines Accounts. Bitte versuche es später erneut.'); - } - - session_unset(); // Unset pre-session variables, next request will generate a new CSRF token - $_SESSION['FIRSTNAME'] = trim($nameParts[0]); - $_SESSION['LASTNAME'] = trim($nameParts[1]); - $_SESSION['EMAIL'] = $email; - $_SESSION['PASSWORD'] = $passwordHash; - $_SESSION['SALT'] = $salt; - $_SESSION['UUID'] = $avatarUUID; - $_SESSION['LEVEL'] = 0; - $_SESSION['DISPLAYNAME'] = strtoupper($name); - $_SESSION['LOGIN'] = 'true'; - - header('Location: index.php?page=dashboard'); - die(); diff --git a/pages/reset-password.php b/pages/reset-password.php deleted file mode 100644 index c36f29e..0000000 --- a/pages/reset-password.php +++ /dev/null @@ -1,90 +0,0 @@ -
das Passwort für deinen 4Creative-Account wurde soeben über die Funktion "Passwort vergessen" geändert.

Solltest du diese Änderung nicht selbst durchgeführt haben, wende dich bitte umgehend per E-Mail (info@4creative.net) oder Discord (@ikeytan) an uns.'; - const TOKEN_INVALID = 'Dieser Link zur Passwortzurücksetzung ist nicht gültig. Bitte klicke oder kopiere den Link aus der E-Mail, die du erhalten hast.'; - const TOKEN_EXPIRED = 'Dein Link zur Passwortzurücksetzung ist abgelaufen. Klicke hier, um eine neue Anfrage zu senden.'; - - function displayTokenError($message) - { - $HTML = new HTML(); - $HTML->importHTML("error.html"); - $HTML->ReplaceLayoutInhalt('%%MESSAGE%%', $message); - $HTML->build(); - echo $HTML->ausgabe(); - exit(); - } - - function displayPage($err) - { - if (!isset($_GET['token']) || !preg_match('/^[a-z0-9A-Z]{32}$/', $_GET['token'])) { - displayTokenError(TOKEN_INVALID); - } - - $HTML = new HTML(); - $HTML->setHTMLTitle(""); - $HTML->importHTML("reset-password.html"); - $HTML->ReplaceLayoutInhalt('%%MESSAGE%%', $err); - $HTML->ReplaceLayoutInhalt('%%RESET_TOKEN%%', htmlspecialchars($_GET['token'])); - $HTML->build(); - echo $HTML->ausgabe(); - exit(); - } - - if ($_SERVER['REQUEST_METHOD'] == 'POST') { - include_once 'app/FormValidator.php'; - $validator = new FormValidator(array( - 'password' => array('required' => true, 'regex' => '/^.{1,1000}$/'), - 'passwordRepeat' => array('required' => true, 'regex' => '/^.{1,1000}$/'), - 'resetToken' => array('required' => true, 'regex' => '/^[a-zA-Z0-9]{32}$/') - )); - - if ($validator->isValid($_POST)) { - if ($_POST['password'] !== $_POST['passwordRepeat']) { - displayPage('Du musst in beiden Feldern das gleiche Passwort eingeben'); - } - - if (strlen($_POST['password']) < $RUNTIME['PASSWORD_MIN_LENGTH']) { - displayPage('Dein Passwort muss mindestens '.$RUNTIME['PASSWORD_MIN_LENGTH'].' Zeichen lang sein.'); - } - - $getReq = $RUNTIME['PDO']->prepare('SELECT UserAccounts.PrincipalID AS UUID,FirstName,LastName,Email,Token,RequestTime FROM PasswordResetTokens JOIN UserAccounts ON UserAccounts.PrincipalID = PasswordResetTokens.PrincipalID WHERE Token = ?'); - $getReq->execute([$_POST['resetToken']]); - if ($getReq->rowCount() == 0) { - displayTokenError(TOKEN_INVALID); - } - - $res = $getReq->fetch(); - - if (!hash_equals($res['Token'], $_POST['resetToken'])) { - displayTokenError(TOKEN_INVALID); - } - - $uuid = $res['UUID']; - $name = $res['FirstName'].' '.$res['LastName']; - $getToken = $RUNTIME['PDO']->prepare('DELETE FROM PasswordResetTokens WHERE PrincipalID = ? AND Token = ?'); - $getToken->execute([$uuid, $_POST['resetToken']]); - if ($getToken->rowCount() == 0) { - displayTokenError(TOKEN_INVALID); - } - - if (time() - $res['RequestTime'] > 86400) { - displayTokenError(TOKEN_EXPIRED); - } - - $salt = bin2hex(random_bytes(16)); - $hash = md5(md5(trim($_POST['password'])).':'.$salt); - $statement = $RUNTIME['PDO']->prepare('UPDATE auth SET passwordHash = :PasswordHash, passwordSalt = :PasswordSalt WHERE UUID = :PrincipalID'); - $statement->execute(['PasswordHash' => $hash, 'PasswordSalt' => $salt, 'PrincipalID' => $uuid]); - - session_unset(); - $_SESSION['loginMessage'] = 'Du kannst dich jetzt mit deinem neuen Passwort einloggen!'; - $_SESSION['loginMessageColor'] = 'darkgreen'; - - require_once 'app/utils.php'; - sendMail($res['Email'], str_replace('%%NAME%%', $name, MESSAGE), 'Passwort für '.$name.' zurückgesetzt', 'Passwort geändert', 'Das Passwort für deinen 4Creative-Account wurde soeben zurückgesetzt'); - - header('Location: index.php?page=login'); - exit(); - } - } - - displayPage(''); diff --git a/pages/user-online-state.php b/pages/user-online-state.php deleted file mode 100644 index b65fc77..0000000 --- a/pages/user-online-state.php +++ /dev/null @@ -1,24 +0,0 @@ -setHTMLTitle("Online Anzeige"); - $HTML->importSeitenInhalt("online-anzeige.html"); - - $table = '%%ENTRY%%
BenutzernameRegion
'; - - $statement = $RUNTIME['PDO']->prepare("SELECT RegionID,UserID FROM Presence ORDER BY RegionID ASC"); - $statement->execute(); - - while ($row = $statement->fetch()) { - if ($row['RegionID'] != "00000000-0000-0000-0000-000000000000") { - $entry = ''.htmlspecialchars(trim($opensim->getUserName($row['UserID']))).''.htmlspecialchars($opensim->getRegionName($row['RegionID'])).''; - $table = str_replace("%%ENTRY%%", $entry."%%ENTRY%%", $table); - } - } - - $table = str_replace("%%ENTRY%%", "", $table); - $HTML->ReplaceSeitenInhalt("%%ONLINE-LIST%%", $table); - - $HTML->build(); - echo $HTML->ausgabe(); diff --git a/pages/users.php b/pages/users.php deleted file mode 100644 index 0ae2cca..0000000 --- a/pages/users.php +++ /dev/null @@ -1,99 +0,0 @@ -setHTMLTitle("Benutzer"); - $HTML->importSeitenInhalt("users.html"); - $HTML->addHTMLHeader(''); - - if (!isset($_SESSION['LOGIN']) || !isset($_SESSION['LEVEL']) || $_SESSION['LEVEL'] < 100) { - $HTML->setHTMLTitle("Kein Zugriff"); - $HTML->SetSeitenInhalt("Dazu hast du keine Rechte!"); - $HTML->build(); - echo $HTML->ausgabe(); - die(); - } - - include_once 'app/OpenSim.php'; - $opensim = new OpenSim(); - - if ($_SERVER['REQUEST_METHOD'] == 'POST') { - include_once 'app/FormValidator.php'; - if (isset($_POST['generateLink'])) { - $validator = new FormValidator(array()); // Needed only for CSRF token validation - - if ($validator->isValid($_POST)) { - $inviteID = bin2hex(random_bytes(16)); - $link = "https://".$_SERVER['SERVER_NAME']."/index.php?page=register&code=".$inviteID; - - $statement = $RUNTIME['PDO']->prepare('INSERT INTO `InviteCodes` (`InviteCode`) VALUES (:InviteCode)'); - $statement->execute(['InviteCode' => $inviteID]); - - $HTML->ReplaceSeitenInhalt("%%link%%", $link); - } - } elseif (isset($_POST['delident'])) { - $validator = new FormValidator(array( - 'userid' => array('required' => true, 'regex' => '/^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$/'), - 'identid' => array('required' => true, 'regex' => '/^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$/') - )); - - if ($validator->isValid($_POST)) { - include_once 'app/OpenSim.php'; - $os = new OpenSim(); - $identName = $os->getUserName($_POST['identid']); - $userName = $os->getUserName($_POST['userid']); - if($os->deleteIdentity($_POST['userid'], $_POST['identid'])) { - $HTML->ReplaceSeitenInhalt("%%MESSAGE%%", ''); - } else { - $HTML->ReplaceSeitenInhalt("%%MESSAGE%%", ''); - } - } - } else { - $validator = new FormValidator(array( - 'userid' => array('required' => true, 'regex' => '/^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$/') - )); - - if ($validator->isValid($_POST)) { - if (isset($_POST['genpw'])) { - require_once 'app/utils.php'; - $token = generateToken(32); - $setToken = $RUNTIME['PDO']->prepare('REPLACE INTO PasswordResetTokens(PrincipalID,Token,RequestTime) VALUES(?,?,?)'); - $setToken->execute([$_POST['userid'], $token, time()]); - $resetLink = "https://".$RUNTIME['DOMAIN'].'/index.php?page=reset-password&token='.$token; - - $HTML->ReplaceSeitenInhalt("%%MESSAGE%%", ''); - } elseif (isset($_POST['deluser'])) { - $name = $opensim->getUserName($_POST['userid']); - if ($opensim->deleteUser($_POST['userid'])) { - $HTML->ReplaceSeitenInhalt("%%MESSAGE%%", ''); - } else { - $HTML->ReplaceSeitenInhalt("%%MESSAGE%%", ''); - } - } - } - } - } - - $statement = $RUNTIME['PDO']->prepare("CREATE TABLE IF NOT EXISTS `InviteCodes` (`InviteCode` VARCHAR(64) NOT NULL, PRIMARY KEY (`InviteCode`))"); - $statement->execute(); - - $table = '%%ENTRY%%
VornameNachnameStatusAktionen
'; - - // Only select current primary account - $statement = $RUNTIME['PDO']->prepare("SELECT FirstName,LastName,UserLevel,PrincipalID FROM UserAccounts JOIN auth ON auth.UUID = UserAccounts.PrincipalID ORDER BY Created ASC"); - $statement->execute(); - - $statementIdent = $RUNTIME['PDO']->prepare("SELECT FirstName,LastName,UserLevel,IdentityID FROM UserIdentitys JOIN UserAccounts ON UserAccounts.PrincipalID = UserIdentitys.IdentityID WHERE UserIdentitys.PrincipalID = ? AND UserIdentitys.PrincipalID != UserIdentitys.IdentityID"); - while ($row = $statement->fetch()) { - $entry = ''.htmlspecialchars($row['FirstName']).''.htmlspecialchars($row['LastName']).''.htmlspecialchars($row['UserLevel']).'
%%CSRF%%
'; - $statementIdent->execute([$row['PrincipalID']]); - while ($identRow = $statementIdent->fetch()) { - $entry = $entry.''.htmlspecialchars($identRow['FirstName']).''.htmlspecialchars($identRow['LastName']).''.htmlspecialchars($identRow['UserLevel']).'
%%CSRF%%
'; - } - $table = str_replace("%%ENTRY%%", $entry."%%ENTRY%%", $table); - } - - $table = str_replace("%%ENTRY%%", "", $table); - $HTML->ReplaceSeitenInhalt("%%USER-LIST%%", $table); - $HTML->ReplaceSeitenInhalt("%%link%%", ' '); - $HTML->ReplaceSeitenInhalt("%%MESSAGE%%", ' '); - - $HTML->build(); - echo $HTML->ausgabe(); diff --git a/plugins/default-html.php b/plugins/default-html.php deleted file mode 100644 index f9873ae..0000000 --- a/plugins/default-html.php +++ /dev/null @@ -1,11 +0,0 @@ -importHTML("dashboard.html"); - - if(isset($_SESSION['LEVEL']) && $_SESSION['LEVEL'] > 100) { - $HTML->importHTML("dashboard-admin.html"); - } - - $HTML->ReplaceLayoutInhalt("%%USERNAME%%", isset($_SESSION['DISPLAYNAME']) ? htmlspecialchars($_SESSION['DISPLAYNAME']) : ''); - }