1
0
Fork 0

Implement all existing pages as RequestHandlers

master
Anonymous Contributor 2023-09-05 01:12:48 +02:00
parent 27899ce9c1
commit 1cc4746c6a
28 changed files with 1132 additions and 954 deletions

26
app/page/Dashboard.php Normal file
View File

@ -0,0 +1,26 @@
<?php
declare(strict_types=1);
namespace Mcp\Page;
use Mcp\OpenSim;
use Mcp\Middleware\LoginRequiredMiddleware;
class Dashboard extends \Mcp\RequestHandler
{
public function __construct(\Mcp\Mcp $app)
{
parent::__construct($app, new LoginRequiredMiddleware($app, $app->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();
}
}

16
app/page/Error.php Normal file
View File

@ -0,0 +1,16 @@
<?php
declare(strict_types=1);
namespace Mcp\Page;
class Error extends \Mcp\RequestHandler
{
public function get(): void
{
http_response_code(404);
$this->app->template('error.php')->parent('__presession.php')->vars([
'title' => 'Seite nicht gefunden',
'error-message' => 'Die gewünschte Seite wurde nicht gefunden.'
])->render();
}
}

View File

@ -0,0 +1,89 @@
<?php
declare(strict_types=1);
namespace Mcp\Page;
use Mcp\FormValidator;
use Mcp\Middleware\PreSessionMiddleware;
use Mcp\Util\SmtpClient;
use Mcp\Util\Util;
class ForgotPassword extends \Mcp\RequestHandler
{
const MESSAGE = 'Hallo %%NAME%%,<br/><br/>wir haben soeben eine Anfrage zur Zurücksetzung des Passworts für deinen 4Creative-Account erhalten.<br/><br/>Klicke <a href="%%RESET_LINK%%">hier</a>, um ein neues Passwort festzulegen. Dieser Link läuft in 24 Stunden ab.<br/><br/>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);
}
}
}
}

66
app/page/Friends.php Normal file
View File

@ -0,0 +1,66 @@
<?php
declare(strict_types=1);
namespace Mcp\Page;
use Mcp\FormValidator;
use Mcp\OpenSim;
use Mcp\Middleware\LoginRequiredMiddleware;
class Friends extends \Mcp\RequestHandler
{
public function __construct(\Mcp\Mcp $app)
{
parent::__construct($app, new LoginRequiredMiddleware($app, $app->config('domain')));
}
public function get(): void
{
$table = '<table class="table"><thead><tr><th scope="col">Name</th><th scope="col">Optionen</th></thead><tbody>';
$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.'<tr><td>'.htmlspecialchars($name).'</td><td><form action="index.php?page=friends" method="post">'.$csrf.'<input type="hidden" name="uuid" value="'.htmlspecialchars($row['Friend']).'"><button type="submit" name="remove" class="btn btn-danger btn-sm">LÖSCHEN</button></form></td></tr>';
}
$this->app->template('__dashboard.php')->vars([
'title' => 'Deine Freunde',
'username' => $_SESSION['DISPLAYNAME']
])->unsafeVar('child-content', $table.'</tbody></table>')->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');
}
}

52
app/page/Groups.php Normal file
View File

@ -0,0 +1,52 @@
<?php
declare(strict_types=1);
namespace Mcp\Page;
use Mcp\FormValidator;
use Mcp\OpenSim;
use Mcp\Middleware\LoginRequiredMiddleware;
class Groups extends \Mcp\RequestHandler
{
public function __construct(\Mcp\Mcp $app)
{
parent::__construct($app, new LoginRequiredMiddleware($app, $app->config('domain')));
}
public function get(): void
{
$opensim = new OpenSim($this->app->db());
$table = '<table class="table"><thead><tr><th scope="col">Name</th><th scope="col">Gründer</th><th scope="col">Aktionen</th></thead><tbody>';
$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.'<tr><td>'.htmlspecialchars($rowGroups['Name']).'</td><td>'.htmlspecialchars($opensim->getUserName($rowGroups['FounderID'])).'</td><td><form action="index.php?page=groups" method="post">'.$csrf.'<input type="hidden" name="group" value="'.htmlspecialchars($rowGroups['GroupID']).'"><button type="submit" name="leave" class="btn btn-danger btn-sm">VERLASSEN</button></form></td></tr>';
}
$this->app->template('__dashboard.php')->vars([
'title' => 'Gruppen',
'username' => $_SESSION['DISPLAYNAME']
])->unsafeVar('child-content', $table.'</tbody></table>')->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');
}
}

147
app/page/Identities.php Normal file
View File

@ -0,0 +1,147 @@
<?php
declare(strict_types=1);
namespace Mcp\Page;
use Mcp\FormValidator;
use Mcp\OpenSim;
use Mcp\Middleware\LoginRequiredMiddleware;
class Identities extends \Mcp\RequestHandler
{
public function __construct(\Mcp\Mcp $app)
{
parent::__construct($app, new LoginRequiredMiddleware($app, $app->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 = '<table class="table"><thead><tr><th scope="col">Name</th><th scope="col">Aktionen</th></thead><tbody>';
$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 = '<tr><td>'.htmlspecialchars(trim($opensim->getUserName($row['IdentityID']))).' <span class="badge badge-info">Aktiv</span></td><td>-</td></tr>';
} else {
$entry = '<tr><td>'.htmlspecialchars(trim($opensim->getUserName($row['IdentityID']))).'</td><td><form action="index.php?page=identities" method="post">'.$csrf.'<input type="hidden" name="uuid" value="'.htmlspecialchars($row['IdentityID']).'"><button type="submit" name="enableIdent" class="btn btn-success btn-sm">Aktivieren</button> <button type="submit" name="deleteIdent" class="btn btn-danger btn-sm">Löschen</button></form></td></tr>';
}
$table = $table.$entry;
}
$message = '';
if (isset($_SESSION['identities_err'])) {
$message = '<div class="alert alert-danger" role="alert">'.$_SESSION['identities_err'].'</div>';
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.'</tbody></table>')->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');
}
}

93
app/page/Login.php Normal file
View File

@ -0,0 +1,93 @@
<?php
declare(strict_types=1);
namespace Mcp\Page;
use Mcp\FormValidator;
use Mcp\Middleware\PreSessionMiddleware;
class Login extends \Mcp\RequestHandler
{
public function __construct(\Mcp\Mcp $app)
{
parent::__construct($app, new PreSessionMiddleware($app->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();
}
}
}

111
app/page/ManageUsers.php Normal file
View File

@ -0,0 +1,111 @@
<?php
declare(strict_types=1);
namespace Mcp\Page;
use Mcp\FormValidator;
use Mcp\OpenSim;
use Mcp\RequestHandler;
use Mcp\Util\Util;
use Mcp\Middleware\AdminMiddleware;
class ManageUsers extends RequestHandler
{
public function __construct(\Mcp\Mcp $app)
{
parent::__construct($app, new AdminMiddleware($app, $app->config('domain')));
}
public function get(): void
{
$table = '<table class="table"><thead><tr><th scope="col">Vorname</th><th scope="col">Nachname</th><th scope="col">Status</th><th scope="col">Aktionen</th></thead><tbody>';
// 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 = '<tr><td>'.htmlspecialchars($row['FirstName']).'</td><td>'.htmlspecialchars($row['LastName']).'</td><td>'.htmlspecialchars(strval($row['UserLevel'])).'</td><td><form action="index.php?page=users" method="post">'.$csrf.'<input type="hidden" name="userid" value="'.htmlspecialchars($row['PrincipalID']).'"><button type="submit" name="genpw" class="btn btn-link btn-sm">PASSWORT ZURÜCKSETZEN</button> <button type="submit" name="deluser" class="btn btn-link btn-sm" style="color: red">LÖSCHEN</button></form></td></tr>';
$statementIdent->execute([$row['PrincipalID']]);
while ($identRow = $statementIdent->fetch()) {
$entry = $entry.'<tr class="ident-row"><td>'.htmlspecialchars($identRow['FirstName']).'</td><td>'.htmlspecialchars($identRow['LastName']).'</td><td>'.htmlspecialchars(strval($identRow['UserLevel'])).'</td><td><form action="index.php?page=users" method="post">'.$csrf.'<input type="hidden" name="userid" value="'.htmlspecialchars($row['PrincipalID']).'"><input type="hidden" name="identid" value="'.htmlspecialchars($identRow['IdentityID']).'"><button type="submit" name="delident" class="btn btn-link btn-sm">Identität löschen</button></form></td></tr>';
}
$table = $table.$entry;
}
$tpl = $this->app->template('users.php')->parent('__dashboard.php')->var('title', 'Benutzer')->unsafeVar('user-list', $table.'</tbody></table>')
->unsafeVar('users-message', isset($_SESSION['users-message']) ? $_SESSION['users-message'] : '')
->unsafeVar('custom-css', '<link rel="stylesheet" href="./style/admin-users.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 <b>'.$identName.'</b> von <b>'.$userName.'</b> wurde gelöscht.';
} else {
$_SESSION['users-message'] = 'Identität <b>'.$identName.'</b> 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: <b>'.$resetLink.'</b>';
} elseif (isset($_POST['deluser'])) {
$name = $opensim->getUserName($_POST['userid']);
if ($opensim->deleteUser($_POST['userid'])) {
$_SESSION['users-message'] = 'Der Account <b>'.$name.'</b> wurde gelöscht.';
} else {
$_SESSION['users-message'] = 'Der Account <b>'.$name.'</b> konnte nicht gelöscht werden.';
}
}
}
}
header('Location: index.php?page=users');
}
}

36
app/page/OnlineUsers.php Normal file
View File

@ -0,0 +1,36 @@
<?php
declare(strict_types=1);
namespace Mcp\Page;
use Mcp\OpenSim;
use Mcp\Middleware\LoginRequiredMiddleware;
class OnlineUsers extends \Mcp\RequestHandler
{
public function __construct(\Mcp\Mcp $app)
{
parent::__construct($app, new LoginRequiredMiddleware($app, $app->config('domain')));
}
public function get(): void
{
$opensim = new OpenSim($this->app->db());
$table = '<table class="table"><thead><tr><th scope="col">Benutzername</th><th scope="col">Region</th></thead><tbody>';
$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.'<tr><td>'.htmlspecialchars(trim($opensim->getUserName($row['UserID']))).'</td><td>'.htmlspecialchars($opensim->getRegionName($row['RegionID'])).'</td></tr>';
}
}
$this->app->template('__dashboard.php')->vars([
'title' => 'Online Anzeige',
'username' => $_SESSION['DISPLAYNAME']
])->unsafeVar('child-content', $table.'</tbody></table>')->render();
}
}

View File

@ -1,38 +1,82 @@
<?php
function setNamePart(string $part, string $value, string $otherPart, string $otherValue): bool
declare(strict_types=1);
namespace Mcp\Page;
use Mcp\FormValidator;
use Mcp\OpenSim;
use Mcp\Middleware\LoginRequiredMiddleware;
class Profile extends \Mcp\RequestHandler
{
public function __construct(\Mcp\Mcp $app)
{
global $RUNTIME;
$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;
}
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', '<div class="alert alert-success" role="alert">Deine IAR wird jetzt erstellt und der Download Link wird dir per PM zugesendet.</div>');
} else {
$tpl->unsafeVar('iar-message', '<div class="alert alert-danger" role="alert">Aktuell wird eine IAR erstellt.<br>Warte bitte bis du eine PM bekommst.</div>');
}
$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%%", '<div class="alert alert-success" role="alert">Deine IAR wird jetzt erstellt und der Download Link wird dir per PM zugesendet.'.$APIResult.'</div>');
unset($_SESSION['iar_created']);
} else {
$HTML->ReplaceSeitenInhalt("%%IARINFOMESSAGE%%", '<div class="alert alert-danger" role="alert">Aktuell wird eine IAR erstellt.<br>Warte bitte bis du eine PM bekommst.</div>');
$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();
}

93
app/page/Regions.php Normal file
View File

@ -0,0 +1,93 @@
<?php
declare(strict_types=1);
namespace Mcp\Page;
use Mcp\FormValidator;
use Mcp\OpenSim;
use Mcp\Util\Util;
use Mcp\Middleware\LoginRequiredMiddleware;
use Mcp\Middleware\AdminMiddleware;
class Regions extends \Mcp\RequestHandler
{
public function __construct(\Mcp\Mcp $app)
{
parent::__construct($app, isset($_GET['SHOWALL']) ? new AdminMiddleware($app, $app->config('domain')) : new LoginRequiredMiddleware($app, $app->config('domain')));
}
public function get(): void
{
$table = '<table class="table"><thead><tr><th scope="col">Region Name</th><th scope="col">Eigentümer</th><th scope="col">Position</th><th scope="col">Aktionen</th></thead><tbody>';
$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.'<tr><td>'.htmlspecialchars($row['regionName']).'<div class="blockquote-footer">'.(!empty($stats) ? 'Prims: '.$stats['Prims'].'; RAM-Nutzung: '.$stats['ProcMem'].'; SIM/PHYS FPS: '.$stats['SimFPS'].'/'.$stats['PhyFPS'].' ('.$stats['RegionVersion'].')' : 'Keine Statistik verfügbar').'</div></td><td>'.htmlspecialchars($opensim->getUserName($row['owner_uuid'])).'</td><td>'.Util::fillString(($row['locX'] / 256), 4).' / '.Util::fillString(($row['locY'] / 256), 4).'</td><td><form action="index.php?page=regions" method="post">'.$csrf.'<input type="hidden" name="region" value="'.$row['uuid'].'"><button type="submit" name="remove" class="btn btn-link btn-sm">LÖSCHEN</button></form></td></tr>';
}
$this->app->template('__dashboard.php')->vars([
'title' => isset($_GET["SHOWALL"]) ? 'Regionen verwalten' : 'Deine Regionen',
'username' => $_SESSION['DISPLAYNAME']
])->unsafeVar('child-content', $table.'</tbody></table>')->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();
}
}

182
app/page/Register.php Normal file
View File

@ -0,0 +1,182 @@
<?php
declare(strict_types=1);
namespace Mcp\Page;
use Mcp\FormValidator;
use Mcp\OpenSim;
use Mcp\RequestHandler;
use Mcp\Middleware\PreSessionMiddleware;
use Exception;
class Register extends RequestHandler
{
public function __construct(\Mcp\Mcp $app)
{
parent::__construct($app, new PreSessionMiddleware($app->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;
}
}

110
app/page/ResetPassword.php Normal file
View File

@ -0,0 +1,110 @@
<?php
declare(strict_types=1);
namespace Mcp\Page;
use Mcp\FormValidator;
use Mcp\Middleware\PreSessionMiddleware;
use Mcp\Util\SmtpClient;
use Mcp\Util\Util;
class Dashboard extends \Mcp\RequestHandler
{
private const MESSAGE = 'Hallo %%NAME%%,<br/><br/>das Passwort für deinen 4Creative-Account wurde soeben über die Funktion "Passwort vergessen" geändert.<br/><br/>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 <a href="index.php?page=forgot">hier</a>, 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();
}
}

View File

@ -1 +0,0 @@
Deny from all

View File

@ -1,14 +0,0 @@
<?php
include_once 'app/OpenSim.php';
$opensim = new OpenSim();
$HTML->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();

View File

@ -1,6 +0,0 @@
<?php
$HTML->setHTMLTitle("Seite nicht gefunden");
$HTML->build();
http_response_code(404);
echo $HTML->ausgabe();

View File

@ -1,67 +0,0 @@
<?php
const MESSAGE = 'Hallo %%NAME%%,<br/><br/>wir haben soeben eine Anfrage zur Zurücksetzung des Passworts für deinen 4Creative-Account erhalten.<br/><br/>Klicke <a href="%%RESET_LINK%%">hier</a>, um ein neues Passwort festzulegen. Dieser Link läuft in 24 Stunden ab.<br/><br/>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();
}

View File

@ -1,55 +0,0 @@
<?php
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
if (isset($_POST['remove'])) {
include_once 'app/FormValidator.php';
$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 = $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 = '<table class="table"><thead><tr><th scope="col">Name</th><th scope="col">Optionen</th></thead><tbody>%%ENTRY%%</tbody></table>';
$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 = '<tr><td>'.htmlspecialchars($name).'</td><td><form action="index.php?page=friends" method="post">%%CSRF%%<input type="hidden" name="uuid" value="'.htmlspecialchars($row['Friend']).'"><button type="submit" name="remove" class="btn btn-danger btn-sm">LÖSCHEN</button></form></td></tr>';
$table = str_replace("%%ENTRY%%", $entry."%%ENTRY%%", $table);
}
$table = str_replace("%%ENTRY%%", "", $table);
$HTML->ReplaceSeitenInhalt("%%ONLINE-LIST%%", $table);
$HTML->build();
echo $HTML->ausgabe();

View File

@ -1,39 +0,0 @@
<?php
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
if (isset($_POST['leave'])) {
include_once 'app/FormValidator.php';
$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 = $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 = '<table class="table"><thead><tr><th scope="col">Name</th><th scope="col">Gründer</th><th scope="col">Aktionen</th></thead><tbody>%%ENTRY%%</tbody></table>';
$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 = '<tr><td>'.htmlspecialchars($rowGroups['Name']).'</td><td>'.htmlspecialchars($opensim->getUserName($rowGroups['FounderID'])).'</td><td><form action="index.php?page=groups" method="post">%%CSRF%%<input type="hidden" name="group" value="'.htmlspecialchars($rowGroups['GroupID']).'"><button type="submit" name="leave" class="btn btn-danger btn-sm">VERLASSEN</button></form></td></tr>';
$table = str_replace("%%ENTRY%%", $entry."%%ENTRY%%", $table);
}
$table = str_replace("%%ENTRY%%", "", $table);
$HTML->ReplaceSeitenInhalt("%%REGION-LIST%%", $table);
$HTML->build();
echo $HTML->ausgabe();

View File

@ -1,141 +0,0 @@
<?php
$statementCreateTable = $RUNTIME['PDO']->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 = '<table class="table"><thead><tr><th scope="col">Name</th><th scope="col">Aktionen</th></thead><tbody>%%ENTRY%%</tbody></table>';
$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 = '<tr><td>'.htmlspecialchars(trim($opensim->getUserName($row['IdentityID']))).' <span class="badge badge-info">Aktiv</span></td><td>-</td></tr>';
} else {
$entry = '<tr><td>'.htmlspecialchars(trim($opensim->getUserName($row['IdentityID']))).'</td><td><form action="index.php?page=identities" method="post">%%CSRF%%<input type="hidden" name="uuid" value="'.htmlspecialchars($row['IdentityID']).'"><button type="submit" name="enableIdent" class="btn btn-success btn-sm">Aktivieren</button> <button type="submit" name="deleteIdent" class="btn btn-danger btn-sm">Löschen</button></form></td></tr>';
}
$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 = '<div class="alert alert-danger" role="alert">'.$_SESSION['identities_err'].'</div>';
unset($_SESSION['identities_err']);
}
$HTML->ReplaceSeitenInhalt("%%MESSAGE%%", $message);
$HTML->build();
echo $HTML->ausgabe();

View File

@ -1,17 +0,0 @@
<?php
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();
}
$HTML->setHTMLTitle("Benutzer");
$HTML->importSeitenInhalt("users.html");
$HTML->ReplaceSeitenInhalt("%%link%%", ' ');
$HTML->build();
echo $HTML->ausgabe();

View File

@ -1,55 +0,0 @@
<?php
$HTML = new HTML();
$HTML->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();

View File

@ -1,80 +0,0 @@
<?php
$HTML->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 = '<table class="table"><thead><tr><th scope="col">Region Name</th><th scope="col">Eigentümer</th><th scope="col">Position</th><th scope="col">Aktionen</th></thead><tbody>%%ENTRY%%</tbody></table>';
$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 = '<tr><td>'.htmlspecialchars($row['regionName']).'<div class="blockquote-footer">'.(!empty($stats) ? 'Prims: '.$stats['Prims'].'; RAM-Nutzung: '.$stats['ProcMem'].'; SIM/PHYS FPS: '.$stats['SimFPS'].'/'.$stats['PhyFPS'].' ('.$stats['RegionVersion'].')' : 'Keine Statistik verfügbar').'</div></td><td>'.htmlspecialchars($opensim->getUserName($row['owner_uuid'])).'</td><td>'.fillString(($row['locX'] / 256), 4).' / '.fillString(($row['locY'] / 256), 4).'</td><td><form action="index.php?page=regions" method="post">%%CSRF%%<input type="hidden" name="region" value="'.$row['uuid'].'"><button type="submit" name="remove" class="btn btn-link btn-sm">LÖSCHEN</button></form></td></tr>';
$table = str_replace("%%ENTRY%%", $entry."%%ENTRY%%", $table);
}
$table = str_replace("%%ENTRY%%", "", $table);
$HTML->ReplaceSeitenInhalt("%%REGION-LIST%%", $table);
$HTML->build();
echo $HTML->ausgabe();

View File

@ -1,154 +0,0 @@
<?php
function displayPage(string $message)
{
global $RUNTIME;
$HTML = new HTML();
$HTML->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();

View File

@ -1,90 +0,0 @@
<?php
const MESSAGE = 'Hallo %%NAME%%,<br/><br/>das Passwort für deinen 4Creative-Account wurde soeben über die Funktion "Passwort vergessen" geändert.<br/><br/>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 <a href="index.php?page=forgot">hier</a>, 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('');

View File

@ -1,24 +0,0 @@
<?php
include_once 'app/OpenSim.php';
$opensim = new OpenSim();
$HTML->setHTMLTitle("Online Anzeige");
$HTML->importSeitenInhalt("online-anzeige.html");
$table = '<table class="table"><thead><tr><th scope="col">Benutzername</th><th scope="col">Region</th></thead><tbody>%%ENTRY%%</tbody></table>';
$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 = '<tr><td>'.htmlspecialchars(trim($opensim->getUserName($row['UserID']))).'</td><td>'.htmlspecialchars($opensim->getRegionName($row['RegionID'])).'</td></tr>';
$table = str_replace("%%ENTRY%%", $entry."%%ENTRY%%", $table);
}
}
$table = str_replace("%%ENTRY%%", "", $table);
$HTML->ReplaceSeitenInhalt("%%ONLINE-LIST%%", $table);
$HTML->build();
echo $HTML->ausgabe();

View File

@ -1,99 +0,0 @@
<?php
$HTML->setHTMLTitle("Benutzer");
$HTML->importSeitenInhalt("users.html");
$HTML->addHTMLHeader('<link rel="stylesheet" href="./style/admin-users.css">');
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%%", '<div class="alert alert-danger" role="alert">Identität <b>'.$identName.'</b> von <b>'.$userName.'</b> wurde gelöscht.</div>');
} else {
$HTML->ReplaceSeitenInhalt("%%MESSAGE%%", '<div class="alert alert-danger" role="alert">Identität <b>'.$identName.'</b> konnte nicht gelöscht werden.</div>');
}
}
} 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%%", '<div class="alert alert-danger" role="alert">Das Passwort für '.htmlspecialchars($opensim->getUserName($_POST['userid'])).' kann in den nächsten 24 Stunden über diesen Link zurückgesetzt werden: <b>'.$resetLink.'</b></div>');
} elseif (isset($_POST['deluser'])) {
$name = $opensim->getUserName($_POST['userid']);
if ($opensim->deleteUser($_POST['userid'])) {
$HTML->ReplaceSeitenInhalt("%%MESSAGE%%", '<div class="alert alert-danger" role="alert">Der Account <b>'.$name.'</b> wurde gelöscht.</div>');
} else {
$HTML->ReplaceSeitenInhalt("%%MESSAGE%%", '<div class="alert alert-danger" role="alert">Der Account <b>'.$name.'</b> konnte nicht gelöscht werden.</div>');
}
}
}
}
}
$statement = $RUNTIME['PDO']->prepare("CREATE TABLE IF NOT EXISTS `InviteCodes` (`InviteCode` VARCHAR(64) NOT NULL, PRIMARY KEY (`InviteCode`))");
$statement->execute();
$table = '<table class="table"><thead><tr><th scope="col">Vorname</th><th scope="col">Nachname</th><th scope="col">Status</th><th scope="col">Aktionen</th></thead><tbody>%%ENTRY%%</tbody></table>';
// 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 = '<tr><td>'.htmlspecialchars($row['FirstName']).'</td><td>'.htmlspecialchars($row['LastName']).'</td><td>'.htmlspecialchars($row['UserLevel']).'</td><td><form action="index.php?page=users" method="post">%%CSRF%%<input type="hidden" name="userid" value="'.htmlspecialchars($row['PrincipalID']).'"><button type="submit" name="genpw" class="btn btn-link btn-sm">PASSWORT ZURÜCKSETZEN</button> <button type="submit" name="deluser" class="btn btn-link btn-sm" style="color: red">LÖSCHEN</button></form></td></tr>';
$statementIdent->execute([$row['PrincipalID']]);
while ($identRow = $statementIdent->fetch()) {
$entry = $entry.'<tr class="ident-row"><td>'.htmlspecialchars($identRow['FirstName']).'</td><td>'.htmlspecialchars($identRow['LastName']).'</td><td>'.htmlspecialchars($identRow['UserLevel']).'</td><td><form action="index.php?page=users" method="post">%%CSRF%%<input type="hidden" name="userid" value="'.htmlspecialchars($row['PrincipalID']).'"><input type="hidden" name="identid" value="'.htmlspecialchars($identRow['IdentityID']).'"><button type="submit" name="delident" class="btn btn-link btn-sm">Identität löschen</button></form></td></tr>';
}
$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();

View File

@ -1,11 +0,0 @@
<?php
$HTML = new HTML();
if (isset($_SESSION['LOGIN'])) {
$HTML->importHTML("dashboard.html");
if(isset($_SESSION['LEVEL']) && $_SESSION['LEVEL'] > 100) {
$HTML->importHTML("dashboard-admin.html");
}
$HTML->ReplaceLayoutInhalt("%%USERNAME%%", isset($_SESSION['DISPLAYNAME']) ? htmlspecialchars($_SESSION['DISPLAYNAME']) : '');
}