Compare commits
74 Commits
release/1.
...
master
Author | SHA1 | Date |
---|---|---|
Anonymous Contributor | 685853a9f9 | |
Anonymous Contributor | 36ef1c5721 | |
Anonymous Contributor | 882c5ae372 | |
Anonymous Contributor | e4e050908b | |
Anonymous Contributor | 2b5c00db1c | |
Anonymous Contributor | 2f9caf8923 | |
Anonymous Contributor | 939f600b3f | |
Anonymous Contributor | 8231fbb08c | |
Anonymous Contributor | eb5a850869 | |
Anonymous Contributor | ce41e107af | |
Anonymous Contributor | 204fcb96e1 | |
Anonymous Contributor | 891f1dff70 | |
Anonymous Contributor | 6a4c343b03 | |
Anonymous Contributor | dbcb57f71f | |
Anonymous Contributor | 1a869b62c2 | |
Anonymous Contributor | 93d8aafd6f | |
Anonymous Contributor | 2ed8285c93 | |
Anonymous Contributor | a166e65421 | |
Anonymous Contributor | e6ba73430b | |
Anonymous Contributor | 80db5f35d1 | |
Anonymous Contributor | bb40c8c9a4 | |
Anonymous Contributor | a213a38b3c | |
Anonymous Contributor | b18b960fb0 | |
Anonymous Contributor | c416ec0992 | |
Anonymous Contributor | 13495cd041 | |
Anonymous Contributor | 9e0267513b | |
Anonymous Contributor | 8e20909f23 | |
Anonymous Contributor | f87fa5d5bb | |
Anonymous Contributor | 5274f306e3 | |
Anonymous Contributor | 9483889e55 | |
Anonymous Contributor | 37ad81fb16 | |
Anonymous Contributor | f50053a745 | |
Anonymous Contributor | 07f196fc51 | |
Anonymous Contributor | fc0412d50a | |
Anonymous Contributor | f9453d5dec | |
Anonymous Contributor | 598e55dd6f | |
Anonymous Contributor | 7be78e387d | |
Anonymous Contributor | 79959cc696 | |
Anonymous Contributor | 01eb373798 | |
Anonymous Contributor | 27fe2187b4 | |
Anonymous Contributor | c7bf6f4d6e | |
Anonymous Contributor | 3bc2fee80a | |
Anonymous Contributor | 2e3124406a | |
Anonymous Contributor | ef9cb8831e | |
Anonymous Contributor | cbc065f3a4 | |
Anonymous Contributor | eca5aa0d92 | |
Anonymous Contributor | 1ac6474194 | |
Anonymous Contributor | a4b008f7ae | |
Anonymous Contributor | 6dae322a2a | |
Anonymous Contributor | ea5c1ee4d7 | |
Anonymous Contributor | 16dcd2ab46 | |
Anonymous Contributor | 94d84ab935 | |
Anonymous Contributor | d33a89b355 | |
Anonymous Contributor | 9ebb54ce64 | |
Anonymous Contributor | b68884f33c | |
Anonymous Contributor | 6b96f8281c | |
Anonymous Contributor | 1cc4746c6a | |
Anonymous Contributor | 27899ce9c1 | |
Anonymous Contributor | 686e991266 | |
Anonymous Contributor | cc240f47a2 | |
Anonymous Contributor | a80919fdce | |
Anonymous Contributor | b163f4d764 | |
Anonymous Contributor | 024a140609 | |
Anonymous Contributor | 6c22684b2f | |
Anonymous Contributor | ea2fffa872 | |
Anonymous Contributor | d6ca2e6e00 | |
Anonymous Contributor | c5871a626b | |
Anonymous Contributor | 007e0ac4fb | |
Anonymous Contributor | 48882cbb1b | |
Anonymous Contributor | 120fb3772e | |
Anonymous Contributor | 9a5182816f | |
Anonymous Contributor | bfeb4f5eef | |
Anonymous Contributor | 6f150ac55c | |
Anonymous Contributor | fb605bcf4a |
|
@ -1 +1,2 @@
|
|||
config.php
|
||||
config.php
|
||||
node_modules
|
41
README.md
41
README.md
|
@ -1,2 +1,41 @@
|
|||
# OpenSim-Gridverwaltung
|
||||
# MCP: OpenSim-Gridverwaltung
|
||||
|
||||
Das MCP ist ein PHP-Webinterface für Benutzer und Administratoren von OpenSimulator-Grids. Es ermöglicht Benutzern die Registrierung (auf Einladung) und Verwaltung des eigenen OpenSimulator-Accounts im Self-Service-Verfahren. Administratoren können Accounts und Regionen einfacher verwalten.
|
||||
|
||||
## Installation
|
||||
|
||||
Voraussetzung ist, dass die Datenbankstruktur eines OpenSimulator-Grids bereits existiert. Das MCP muss vor der Nutzung mit den Zugangsdaten derselben Datenbank konfiguriert werden. Eigene Tabellen des MCP besitzen zur Vermeidung von Konflikten den Präfix `mcp_`.
|
||||
|
||||
Folgende PHP-Erweiterungen werden benötigt:
|
||||
1. php-curl
|
||||
2. php-mysql (PDO)
|
||||
3. php-xml
|
||||
4. php-xmlrpc
|
||||
|
||||
Für bessere Performance kann optional `php-apcu` installiert werden.
|
||||
|
||||
Die Installation läuft folgendermaßen ab:
|
||||
1. Gewünschtes Release als ZIP/TAR-Archiv oder per `git clone` herunterladen
|
||||
2. Verzeichnisse `app`, `data`, `lib`, `public` und `templates` in das Verzeichnis des Webservers entpacken
|
||||
3. Öffentliche Stammverzeichnis des Webservers (Apache: `DocumentRoot`, nginx: `root`) auf Pfad zum Verzeichnis `public` ändern
|
||||
4. Index des Webservers auf index.php ändern, falls erforderlich
|
||||
5. Beispielkonfiguration `config.example.ini` anpassen, in `config.ini` umbenennen und in das Verzeichnis der in Schritt 2 entpackten Verzeichnisse verschieben
|
||||
|
||||
## Aktualisierung
|
||||
|
||||
Zur Aktualisierung müssen lediglich die Verzeichnisse `app`, `lib`, `public` und `templates`, sowie der Inhalt von `data` (außer `iars`) ersetzt werden.
|
||||
Die Migration der Datenbankstruktur erfolgt automatisch. Möglicherweise erforderliche Änderungen an der Konfiguration sind den Release-Informationen zu entnehmen.
|
||||
|
||||
## Entwickler
|
||||
|
||||
Die Abhängigkeiten des Frontends werden über [npm](https://www.npmjs.com/) verwaltet. Alle erforderlichen Pakete können nach dem Download des Repository über `npm install` heruntergeladen werden.
|
||||
In `package.json` ist zudem ein Buildprozess (Befehl: `npm build`) definiert, durch den die Sass-Stylesheets im Verzeichnis `scss` kompiliert und optimiert und zusammen mit Schriftarten und Skripts im öffentlichen Webverzeichnis abgelegt werden.
|
||||
|
||||
Das Backend besitzt kein Dependency Management. Die einzige Abhängigkeit, [PHPMailer](https://github.com/PHPMailer/PHPMailer), wurde manuell in das Repository eingefügt. Der Autoloader sucht im Verzeichnis `lib` nach solchen externen Klassen.
|
||||
|
||||
### Verarbeitung von Anfragen
|
||||
|
||||
Das Skript `index.php` wird bei allen Anfragen aufgerufen. Die angeforderte Route wird als GET-Parameter `<Gruppe>=<Name>` übermittelt. Gruppen (momentan `api` und `page`), zugehörige Seiten und die assoziierte `RequestHandler`-Subklasse sind in `Mcp.php` definiert.
|
||||
|
||||
Ist zu einer Anfrage eine Route definiert, wird der zugehörige `RequestHandler` erzeugt. Ist eine `Middleware`-Klasse für diesen definiert, ist die weitere Verarbeitung von dem Rückgabewert von `Middleware::canAccess()` abhängig.
|
||||
Schließlich wird je nach Methode der Anfrage `RequestHandler::get()` bzw. `RequestHandler::post()` aufgerufen.
|
|
@ -1 +0,0 @@
|
|||
Deny from all
|
110
api/economy.php
110
api/economy.php
|
@ -1,110 +0,0 @@
|
|||
<?php
|
||||
|
||||
# Copyright (c)Melanie Thielker and Teravus Ovares (http://opensimulator.org/)
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions are met:
|
||||
# * Redistributions of source code must retain the above copyright
|
||||
# notice, this list of conditions and the following disclaimer.
|
||||
# * Redistributions in binary form must reproduce the above copyright
|
||||
# notice, this list of conditions and the following disclaimer in the
|
||||
# documentation and/or other materials provided with the distribution.
|
||||
# * Neither the name of the OpenSim Project nor the
|
||||
# names of its contributors may be used to endorse or promote products
|
||||
# derived from this software without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
|
||||
# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
# DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
|
||||
# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#
|
||||
|
||||
# updated for Robust installations: BlueWall 2011
|
||||
# further minor changes by justincc (http://justincc.org)
|
||||
|
||||
# Tables
|
||||
$presence = "Presence";
|
||||
|
||||
# XMLRPC
|
||||
$xmlrpc_server = xmlrpc_server_create();
|
||||
xmlrpc_server_register_method($xmlrpc_server, "preflightBuyLandPrep", "buy_land_prep");
|
||||
|
||||
function validate_user($agent_id, $s_session_id)
|
||||
{
|
||||
$stmt = $RUNTIME['PDO']->prepare("SELECT UserID FROM Presence WHERE UserID=? AND SecureSessionID = ?");
|
||||
$stmt->execute(array($agent_id, $s_session_id));
|
||||
|
||||
if($stmt->rowCount() == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$res = $stmt->fetch();
|
||||
return $res['UserID'];
|
||||
}
|
||||
|
||||
function buy_land_prep($method_name, $params, $app_data)
|
||||
{
|
||||
$confirmvalue = "";
|
||||
$req = $params[0];
|
||||
$agentid = $req['agentId'];
|
||||
$sessionid = $req['secureSessionId'];
|
||||
$amount = $req['currencyBuy'];
|
||||
$billableArea = $req['billableArea'];
|
||||
|
||||
$ID = validate_user($agentid, $sessionid);
|
||||
|
||||
if($ID)
|
||||
{
|
||||
$membership_levels = array(
|
||||
'levels' => array(
|
||||
'id' => "00000000-0000-0000-0000-000000000000",
|
||||
'description' => "some level"));
|
||||
|
||||
$landUse = array(
|
||||
'upgrade' => False,
|
||||
'action' => "".SYSURL."");
|
||||
|
||||
$currency = array(
|
||||
'estimatedCost' => "200.00"); // convert_to_real($amount));
|
||||
|
||||
$membership = array(
|
||||
'upgrade' => False,
|
||||
'action' => "".SYSURL."",
|
||||
'levels' => $membership_levels);
|
||||
|
||||
$response_xml = xmlrpc_encode(array(
|
||||
'success' => True,
|
||||
'currency' => $currency,
|
||||
'membership' => $membership,
|
||||
'landUse' => $landUse,
|
||||
'currency' => $currency,
|
||||
'confirm' => $confirmvalue));
|
||||
|
||||
header("Content-type: text/xml");
|
||||
print $response_xml;
|
||||
}
|
||||
else
|
||||
{
|
||||
header("Content-type: text/xml");
|
||||
$response_xml = xmlrpc_encode(array(
|
||||
'success' => False,
|
||||
'errorMessage' => "\n\nUnable to Authenticate\n\nClick URL for more info.",
|
||||
'errorURI' => "".SYSURL.""));
|
||||
|
||||
print $response_xml;
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
$request_xml = file_get_contents('php://input');
|
||||
xmlrpc_server_call_method($xmlrpc_server, $request_xml, '');
|
||||
xmlrpc_server_destroy($xmlrpc_server);
|
||||
|
||||
?>
|
|
@ -1,29 +0,0 @@
|
|||
<?php
|
||||
$membership_levels = array(
|
||||
'levels' => array(
|
||||
'id' => "00000000-0000-0000-0000-000000000000",
|
||||
'description' => "some level"));
|
||||
|
||||
$landUse = array(
|
||||
'upgrade' => False,
|
||||
'action' => "");
|
||||
|
||||
$currency = array(
|
||||
'estimatedCost' => "200.00"); // convert_to_real($amount));
|
||||
|
||||
$membership = array(
|
||||
'upgrade' => False,
|
||||
'action' => "",
|
||||
'levels' => $membership_levels);
|
||||
|
||||
$response_xml = xmlrpc_encode(array(
|
||||
'success' => True,
|
||||
'currency' => $currency,
|
||||
'membership' => $membership,
|
||||
'landUse' => $landUse,
|
||||
'currency' => $currency,
|
||||
'confirm' => "200.00"));
|
||||
|
||||
header("Content-type: text/xml");
|
||||
print $response_xml;
|
||||
?>
|
|
@ -1,5 +0,0 @@
|
|||
1148b04d-7a93-19e9-b3c9-ea1cdeec38f7
|
||||
1148b04d-7a93-29e9-b3c9-ea1cdeec38f7
|
||||
1148b04d-7a93-39e9-b3c9-ea1cdeec38f7
|
||||
1148b04d-7a93-49e9-b3c9-ea1cdeec38f7
|
||||
1148b04d-7a93-59e9-b3c9-ea1cdeec38f7
|
|
@ -1,36 +0,0 @@
|
|||
<html>
|
||||
<head>
|
||||
<meta http-equiv="refresh" content="15">
|
||||
</head>
|
||||
<body style="background-image: url('./style/images/fabric-pattern.png')">
|
||||
<?php
|
||||
|
||||
$statement = $RUNTIME['PDO']->prepare("SELECT UserID,RegionID FROM Presence WHERE RegionID != '00000000-0000-0000-0000-000000000000' ORDER BY RegionID ASC");
|
||||
$statement->execute();
|
||||
|
||||
if($statement->rowCount() == 0)
|
||||
{
|
||||
echo "<h1>Es ist niemand online!</h1>";
|
||||
}else{
|
||||
|
||||
echo '<table style="width:350px;margin-left:auto;margin-right:auto;margin-top:25px"><tr><th align="left" style="background-color: #FF8000;">Name</th><th align="left" style="background-color: #FF8000;">Region</th></tr>';
|
||||
$entryColor = TRUE;
|
||||
include 'app/OpenSim.php';
|
||||
$opensim = new OpenSim();
|
||||
while($row = $statement->fetch())
|
||||
{
|
||||
if($entryColor == TRUE)
|
||||
$entry = '<tr style="background-color: #F2F2F2;"><td>'.trim($opensim->getUserName($row['UserID'])).'</td><td>'.$opensim->getRegionName($row['RegionID']).'</td></tr>';
|
||||
|
||||
if($entryColor == FALSE)
|
||||
$entry = '<tr style="background-color: #E6E6E6;"><td>'.trim($opensim->getUserName($row['UserID'])).'</td><td>'.$opensim->getRegionName($row['RegionID']).'</td></tr>';
|
||||
|
||||
echo $entry;
|
||||
$entryColor = !$entryColor;
|
||||
}
|
||||
|
||||
echo '</table>';
|
||||
}
|
||||
?>
|
||||
</body>
|
||||
</html>
|
|
@ -1,35 +0,0 @@
|
|||
<?php
|
||||
include 'app/OpenSim.php';
|
||||
$opensim = new OpenSim();
|
||||
|
||||
$HTML = new HTML();
|
||||
$HTML->setHTMLTitle("Spalsh");
|
||||
$HTML->importHTML("viewerWelcomeImages.html");
|
||||
|
||||
$IMAGES = array();
|
||||
if ($handle = opendir('./data/viewerWelcomeImages'))
|
||||
{
|
||||
while (false !== ($entry = readdir($handle)))
|
||||
{
|
||||
if ($entry != "." && $entry != "..")
|
||||
{
|
||||
$IMAGES = array_merge($IMAGES, array("./data/viewerWelcomeImages/".$entry));
|
||||
}
|
||||
}
|
||||
|
||||
closedir($handle);
|
||||
}
|
||||
|
||||
shuffle($IMAGES);
|
||||
|
||||
$HTML->ReplaceLayoutInhalt("%%JSONIMAGEARRAY%%", json_encode($IMAGES));
|
||||
$HTML->ReplaceLayoutInhalt("%%GRIDNAME%%", $RUNTIME['GRID']['NAME']);
|
||||
$HTML->ReplaceLayoutInhalt("%%SHOWNEWS%%", $RUNTIME['GRID']['MAIN_NEWS']);
|
||||
|
||||
|
||||
$HTML->ReplaceLayoutInhalt("%%SHOWSTATS%%", "Registrierte User: ".$opensim->getUserCount()."<br>Regionen: ".$opensim->getRegionCount()."<br>Aktuell Online: ".($opensim->getOnlineCount()-1));
|
||||
|
||||
|
||||
$HTML->build();
|
||||
echo $HTML->ausgabe();
|
||||
?>
|
|
@ -0,0 +1,11 @@
|
|||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Mcp;
|
||||
|
||||
use PDO;
|
||||
|
||||
interface ConnectionProvider
|
||||
{
|
||||
public function db(): PDO;
|
||||
}
|
|
@ -1,29 +1,35 @@
|
|||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Mcp;
|
||||
|
||||
class FormValidator {
|
||||
|
||||
private array $fieldValidation;
|
||||
|
||||
public function __construct(array $fieldValidation) {
|
||||
public function __construct(array $fieldValidation)
|
||||
{
|
||||
$this->fieldValidation = $fieldValidation;
|
||||
}
|
||||
|
||||
public function isValid(array $req) {
|
||||
if(!isset($req['csrf']) || $req['csrf'] !== $_SESSION['csrf']) {
|
||||
public function isValid(array $req): bool
|
||||
{
|
||||
if (!isset($req['csrf']) || $req['csrf'] !== $_SESSION['csrf']) {
|
||||
return false;
|
||||
}
|
||||
|
||||
foreach($this->fieldValidation as $field => $params) {
|
||||
if(isset($req[$field]) && strlen(trim($req[$field])) > 0) {
|
||||
if(isset($params['regex'])) {
|
||||
if(!preg_match($params['regex'], $req[$field])) {
|
||||
foreach ($this->fieldValidation as $field => $params) {
|
||||
if (isset($req[$field]) && strlen(trim($req[$field])) > 0) {
|
||||
if (isset($params['regex'])) {
|
||||
if (!preg_match($params['regex'], $req[$field])) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if(isset($params['equals']) && $params['equals'] !== $req[$field]) {
|
||||
elseif (isset($params['equals']) && $params['equals'] !== $req[$field]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if(isset($params['required']) && $params['required']) {
|
||||
elseif (isset($params['required']) && $params['required']) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -32,4 +38,3 @@ class FormValidator {
|
|||
}
|
||||
|
||||
}
|
||||
?>
|
249
app/HTML.php
249
app/HTML.php
|
@ -1,249 +0,0 @@
|
|||
<?php
|
||||
class HTML
|
||||
{
|
||||
//Hier wird der HTML Code zum Ausgeben vorbereitet.
|
||||
//Dieser kann aus einer fertigen HTML Seite ausgelesen werden, oder aber auch st<73>ck f<>r St<53>ck
|
||||
//Zusammen gebaut werden.
|
||||
|
||||
//Die Einzelnen Daten k<>nnen nicht direkt von Au<41>en ver<65>ndert werden, sondern m<>ssen durch die Bereitgestellten Optionen gesetzt werden.
|
||||
|
||||
private $HTMLTitle = " "; //Wird in den <header> als <title> Geschrieben.
|
||||
private $StatusMeldung = " "; //Falls Vorhenden eine Statusmeldung vom Script im HTML Text.
|
||||
private $DasMenu = " "; //Beinhaltet das Fertige Men<65>
|
||||
private $DerInhalt = " "; //Beinhaltet den Fertigen Inhalt
|
||||
private $HTMLDatei = " "; //Der inhalt der eingelesen wurde.
|
||||
private $HTMLHeader = " "; //Der HTML HEADER der eingelesen wurde.
|
||||
private $FertigesHTML = " "; //Das Fertige HTML bereit zum Ausgeben.
|
||||
private $isBuild = false; //Hier wird festgehalten ob $FertigesHTML aktuell ist oder nicht.
|
||||
|
||||
//Der <title> wird Generiert.(%%EchoTitle%%)
|
||||
//Dieser wird im HTML Code sp<73>ter als %%HTMLTitle%% aufgerufen.
|
||||
|
||||
public function setHTMLTitle($neuerTitle){
|
||||
//Der Bisherige Title wird komplett <20>berschrieben und gleichzeitig ein neuer Gesetzt.
|
||||
$this->HTMLTitle = $neuerTitle;
|
||||
$this->isBuild = false;
|
||||
}
|
||||
|
||||
public function addHTMLTitle($Hinzufugen){
|
||||
//Zu dem Bisherigen Titel wird noch etwas am ende hinzugef<65>gt.
|
||||
$this->HTMLTitle = $this->HTMLTitle.$Hinzufugen;
|
||||
$this->isBuild = false;
|
||||
}
|
||||
|
||||
public function RemoveHTMLTitle(){
|
||||
//Der Titel wird Komplett gel<65>scht.
|
||||
$this->HTMLTitle = " ";
|
||||
$this->isBuild = false;
|
||||
}
|
||||
|
||||
|
||||
//Der HTML HEADER wird Generiert.(%%echoHeader%%)
|
||||
//Dieser wird im HTML Code sp<73>ter als %%echoHeader%% aufgerufen.
|
||||
|
||||
public function setHTMLHeader($neuerHeader){
|
||||
//Der Bisherige Header wird komplett <20>berschrieben und gleichzeitig ein neuer Gesetzt.
|
||||
$this->HTMLHeader = $neuerHeader;
|
||||
$this->isBuild = false;
|
||||
}
|
||||
|
||||
public function addHTMLHeader($Hinzufugen){
|
||||
//Zu dem Bisherigen Header wird noch etwas am ende hinzugef<65>gt.
|
||||
$this->HTMLHeader = $this->HTMLHeader.$Hinzufugen;
|
||||
$this->isBuild = false;
|
||||
}
|
||||
|
||||
public function RemoveHTMLHeader(){
|
||||
//Der Header wird Komplett gel<65>scht.
|
||||
$this->HTMLHeader = " ";
|
||||
$this->isBuild = false;
|
||||
}
|
||||
|
||||
public function importHTMLHeader($file){
|
||||
global $RUNTIME;
|
||||
//Der HTML Header wird aus einer Datei eingelesen und der bisherige gel<65>scht.
|
||||
$this->HTMLHeader = file_get_contents($RUNTIME['BASEDIR'].'/templates/'.$file);
|
||||
$this->isBuild = false;
|
||||
}
|
||||
|
||||
//Der StatusText wird ge<67>ndert.(%%StatusMeldung%%)
|
||||
//Dieser wird im HTML Code sp<73>ter als %%StatusMeldung%% aufgerufen.
|
||||
|
||||
public function setStatusMeldung($neueMeldung){
|
||||
//Die bisherige Status meldung wird komplett <20>berschrieben und gleichzeitig ein neuer Gesetzt.
|
||||
$this->StatusMeldung = $neueMeldung;
|
||||
$this->isBuild = false;
|
||||
}
|
||||
|
||||
public function RemoveStatusMeldung(){
|
||||
//Die Meldung wird Komplett gel<65>scht.
|
||||
$this->StatusMeldung = " ";
|
||||
$this->isBuild = false;
|
||||
}
|
||||
|
||||
//Ab hier wird das Men<65> Zusammengebaut. (%%EchoMenu%%)
|
||||
|
||||
public function importTextMenu($neuesMenu){
|
||||
//Das Komplette Men<65> wird direkt importiert und das alte <20>berschreiben.
|
||||
$this->DasMenu = $neuesMenu;
|
||||
$this->isBuild = false;
|
||||
}
|
||||
|
||||
public function importHTMLMenu($file){
|
||||
global $RUNTIME;
|
||||
//Das Komplette Men<65> wird aus einer Datei ausgelesen und das alte <20>berschrieben.
|
||||
$this->DasMenu = file_get_contents($RUNTIME['BASEDIR'].'/templates/'.$file);
|
||||
$this->isBuild = false;
|
||||
}
|
||||
|
||||
public function addToMenu($html){
|
||||
//Es wird noch etwas ans Men<65> angehengt.
|
||||
$this->DasMenu = $this->DasMenu.$html;
|
||||
$this->isBuild = false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
//Der Seiten HTML Quelcode wird eingelesen.
|
||||
|
||||
public function importHTML($file){
|
||||
global $RUNTIME;
|
||||
//Der HTML Quelltext wird aus einer Datei eingelesen.
|
||||
$this->HTMLDatei = file_get_contents($RUNTIME['BASEDIR'].'/templates/'.$file);
|
||||
$this->isBuild = false;
|
||||
}
|
||||
|
||||
public function setHTML($htmlCode){
|
||||
//Der HTML Quelltext wird direkt gesetzt.
|
||||
$this->HTMLDatei = $htmlCode;
|
||||
$this->isBuild = false;
|
||||
}
|
||||
|
||||
public function addNachHTML($htmlCode){
|
||||
//Der HTML Quelltext wird direkt gesetzt.
|
||||
$this->HTMLDatei = $this->HTMLDatei.$htmlCode;
|
||||
$this->isBuild = false;
|
||||
}
|
||||
|
||||
public function addVorHTML($htmlCode){
|
||||
//Der HTML Quelltext wird direkt gesetzt.
|
||||
$this->HTMLDatei = $htmlCode.$this->HTMLDatei;
|
||||
$this->isBuild = false;
|
||||
}
|
||||
|
||||
public function DeleteHTML(){
|
||||
//Der HTML Quelltext wird gel<65>scht.
|
||||
$this->HTMLDatei = " ";
|
||||
$this->isBuild = false;
|
||||
}
|
||||
|
||||
//Der inhalt der Seite wird zusammen gesetzt (nicht der quelltext) (%%EchoInhalt%%)
|
||||
|
||||
public function importSeitenInhalt($file){
|
||||
global $RUNTIME;
|
||||
//L<>d einen fertigen Text aus einer datei.
|
||||
$this->DerInhalt = file_get_contents($RUNTIME['BASEDIR'].'/templates/'.$file);
|
||||
$this->isBuild = false;
|
||||
}
|
||||
|
||||
public function setSeitenInhalt($html){
|
||||
//Setz den Seiteninhalt und L<>scht den alten Komplett.
|
||||
$this->DerInhalt = $html;
|
||||
$this->isBuild = false;
|
||||
}
|
||||
|
||||
public function importAndAddSeitenInhalt($file){
|
||||
global $RUNTIME;
|
||||
//L<>d einen fertigen Text aus einer datei.
|
||||
$this->DerInhalt = $this->DerInhalt.file_get_contents($RUNTIME['BASEDIR'].'/templates/'.$file);
|
||||
$this->isBuild = false;
|
||||
}
|
||||
|
||||
public function addToSeitenInhalt($html){
|
||||
//Es wird noch weitere Text an den Seiteninhalt angeh<65>ngt.
|
||||
$this->DerInhalt = $this->DerInhalt.$html;
|
||||
$this->isBuild = false;
|
||||
}
|
||||
|
||||
public function GetSeitenInhalt(){
|
||||
//Der Seiteninhalt wird zur<75>ckgegeben.
|
||||
return $this->DerInhalt;
|
||||
}
|
||||
|
||||
public function DeleteSeitenInhalt(){
|
||||
//L<>scht den Seiten inhalt.
|
||||
$this->DerInhalt = " ";
|
||||
$this->isBuild = false;
|
||||
}
|
||||
|
||||
public function ReplaceSeitenInhalt($tag, $text){
|
||||
//Ersezt Seiten Inhalt
|
||||
$this->DerInhalt = str_replace($tag, $text, $this->DerInhalt);
|
||||
}
|
||||
|
||||
public function ReplaceLayoutInhalt($tag, $text){
|
||||
//Ersezt Layout Inhalt
|
||||
$this->HTMLDatei = str_replace($tag, $text, $this->HTMLDatei);
|
||||
}
|
||||
|
||||
public function CompressHTML(){
|
||||
if($this->isBuild){
|
||||
$this->FertigesHTML = str_replace(" ", "", $this->FertigesHTML);
|
||||
|
||||
$this->FertigesHTML = str_replace(" ", "", $this->FertigesHTML);
|
||||
}else{
|
||||
die("Es kann nur Fertiger HTML Code kompremiert werden.");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
//Hier wird der Fertige HTML Code generiert.
|
||||
//Und alle 3 Teile, Men<65> Titel und inhalt zusammengef<65>gt.
|
||||
public function build(){
|
||||
//Der HTML Code wird zusammen gesetzt.
|
||||
|
||||
$this->FertigesHTML = null; //Der Speicher wird gellert, falls schon einmal Quelltext generiert wurde.
|
||||
$this->FertigesHTML = $this->HTMLDatei; //Und der Unverarbeitete HTML Quelltext eingelesen.
|
||||
|
||||
//Das Men<65> wird in den HTML Quellcode eingef<65>gt.
|
||||
$this->FertigesHTML = str_replace("%%EchoMenu%%", $this->DasMenu, $this->FertigesHTML);
|
||||
|
||||
//Der inhalt wird in den HTML Quellcode eingef<65>gt.
|
||||
$this->FertigesHTML = str_replace("%%EchoInhalt%%", $this->DerInhalt, $this->FertigesHTML);
|
||||
|
||||
//Die Status Meldung wird in den HTML Quellcode eingef<65>gt.
|
||||
$this->FertigesHTML = str_replace("%%StatusMeldung%%", $this->StatusMeldung, $this->FertigesHTML);
|
||||
|
||||
//Der Titel wird in den HTML Quellcode eingef<65>gt.
|
||||
$this->FertigesHTML = str_replace("%%EchoTitle%%", $this->HTMLTitle, $this->FertigesHTML);
|
||||
|
||||
//Der HTML Header wird in den HTML Quellcode eingef<65>gt.
|
||||
$this->FertigesHTML = str_replace("%%echoHeader%%", $this->HTMLHeader, $this->FertigesHTML);
|
||||
|
||||
//Der Titel wird in den HTML Quellcode eingef<65>gt.
|
||||
$this->FertigesHTML = str_replace("%%datum%%", date("Y-m-dTH:i+2"), $this->FertigesHTML);
|
||||
|
||||
//Der Counter wird in den HTML Quellcode eingef<65>gt.
|
||||
$this->FertigesHTML = str_replace("%%GET_SITE%%", isset($_GET['seite']) ? $_GET['seite'] : ' ', $this->FertigesHTML);
|
||||
|
||||
//Die IP Adresse wird in den HTML Quellcode eingef<65>gt.
|
||||
$this->FertigesHTML = str_replace("%%GET_IP%%", isset($_SERVER["REMOTE_ADDR"]) ? $_SERVER['REMOTE_ADDR'] : ' ', $this->FertigesHTML);
|
||||
|
||||
// Add CSRF token
|
||||
$this->FertigesHTML = str_replace("%%CSRF%%", '<input type="hidden" name="csrf" value="'.(isset($_SESSION['csrf']) ? $_SESSION['csrf'] : '').'">', $this->FertigesHTML);
|
||||
|
||||
$this->isBuild = true;
|
||||
}
|
||||
|
||||
//Hier wird der Fertige HTML ausgegeben
|
||||
public function ausgabe(){
|
||||
if($this->isBuild){
|
||||
return $this->FertigesHTML;
|
||||
}else{
|
||||
die("Bitte erst den HTML Code zusammensetzen.");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
?>
|
|
@ -0,0 +1,149 @@
|
|||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Mcp;
|
||||
|
||||
use Exception;
|
||||
use PDO;
|
||||
|
||||
class Mcp implements ConnectionProvider
|
||||
{
|
||||
|
||||
private ?PDO $db = null;
|
||||
private array $config;
|
||||
private string $dataDir;
|
||||
private string $templateDir;
|
||||
|
||||
const ROUTES = [
|
||||
'api' => [
|
||||
'economy' => 'Api\\Economy',
|
||||
'economylandtool' => 'Api\\EconomyLandTool',
|
||||
'economylandtool.php' => 'Api\\EconomyLandTool',
|
||||
'getAccessList' => 'Api\\GetAccessList',
|
||||
'onlineDisplay' => 'Api\\OnlineDisplay',
|
||||
'viewerWelcomeSite' => 'Api\\ViewerWelcomePage',
|
||||
'runCron' => 'Api\\CronStarter',
|
||||
'downloadIar' => 'Api\\DownloadIar'
|
||||
],
|
||||
'page' => [
|
||||
'dashboard' => 'Page\\Dashboard',
|
||||
'forgot' => 'Page\\ForgotPassword',
|
||||
'friends' => 'Page\\Friends',
|
||||
'groups' => 'Page\\Groups',
|
||||
'identities' => 'Page\\Identities',
|
||||
'login' => 'Page\\Login',
|
||||
'profile' => 'Page\\Profile',
|
||||
'regions' => 'Page\\Regions',
|
||||
'register' => 'Page\\Register',
|
||||
'reset-password' => 'Page\\ResetPassword',
|
||||
'user-online-state' => 'Page\\OnlineUsers',
|
||||
'users' => 'Page\\ManageUsers'
|
||||
]
|
||||
];
|
||||
|
||||
public function __construct($basedir)
|
||||
{
|
||||
$this->templateDir = $basedir.DIRECTORY_SEPARATOR.'templates';
|
||||
$this->dataDir = $basedir.DIRECTORY_SEPARATOR.'data';
|
||||
$this->config = array();
|
||||
try {
|
||||
$config = parse_ini_file($basedir.DIRECTORY_SEPARATOR.'config.ini', true);
|
||||
foreach ($config['general'] as $key => $val) {
|
||||
$this->config[$key] = $val;
|
||||
}
|
||||
unset($config['general']);
|
||||
$this->config = array_merge($config, $this->config);
|
||||
} catch (Exception $e) {
|
||||
error_log('Could not load config, aborting. Error: '.$e->getMessage());
|
||||
http_response_code(503);
|
||||
exit();
|
||||
}
|
||||
|
||||
$migrate = new MigrationManager($basedir.DIRECTORY_SEPARATOR.'data'.DIRECTORY_SEPARATOR.'migrate_ver');
|
||||
if (!$migrate->isMigrated() && !$migrate->migrate($this->db())) {
|
||||
error_log('Migration to latest DB structure version failed, aborting.');
|
||||
http_response_code(503);
|
||||
exit();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Connects to the MySQL database (if not done already) and returns the connection.
|
||||
*/
|
||||
public function db(): PDO
|
||||
{
|
||||
if ($this->db == null) {
|
||||
$this->db = new PDO('mysql:host='.$this->config['mysql']['host'].';dbname='.$this->config['mysql']['db'],
|
||||
$this->config['mysql']['user'],
|
||||
$this->config['mysql']['password']);
|
||||
}
|
||||
|
||||
return $this->db;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value associated with the specified key in this config, as either a string, an integer or an array.
|
||||
* Keys are lower-cased for compatibility reasons.
|
||||
*
|
||||
* If there is no entry with this key, an empty array is returned.
|
||||
*/
|
||||
public function config($key): string|array|int
|
||||
{
|
||||
$realKey = strtolower($key);
|
||||
return isset($this->config[$realKey]) ? $this->config[$realKey] : array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a hidden form field with the current CSRF token set.
|
||||
*/
|
||||
public function csrfField(): string
|
||||
{
|
||||
return '<input type="hidden" name="csrf" value="'.(isset($_SESSION['csrf']) ? $_SESSION['csrf'] : '').'">';
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a TemplateBuilder instance for the specified template file, setting some basic variables.
|
||||
*/
|
||||
public function template($name): TemplateBuilder
|
||||
{
|
||||
return (new TemplateBuilder($this->templateDir, $name))->vars([
|
||||
'domain' => $this->config['domain'],
|
||||
'title' => 'MCP',
|
||||
'admin' => isset($_SESSION['LEVEL']) && $_SESSION['LEVEL'] > 100
|
||||
])->unsafeVar('csrf', $this->csrfField());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the path of the data/ directory, mostly used for dynamically created assets.
|
||||
*/
|
||||
public function getDataDir(): string
|
||||
{
|
||||
return $this->dataDir;
|
||||
}
|
||||
|
||||
public function handleRequest()
|
||||
{
|
||||
$reqClass = 'Mcp\\Page\\Error';
|
||||
if (empty($_GET)) {
|
||||
$reqClass = 'Mcp\\'.$this::ROUTES['page'][array_key_first($this::ROUTES['page'])];
|
||||
} else {
|
||||
if (isset($_GET['logout'])) {
|
||||
session_start();
|
||||
session_destroy();
|
||||
header('Location: /');
|
||||
return;
|
||||
}
|
||||
|
||||
foreach ($this::ROUTES as $type => $routes) {
|
||||
if (isset($_GET[$type])) {
|
||||
if (strlen($_GET[$type]) <= 100 && preg_match('/^[0-9a-zA-Z-_.]+$/', $_GET[$type]) && isset($routes[$_GET[$type]])) {
|
||||
$reqClass = 'Mcp\\'.$routes[$_GET[$type]];
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
(new $reqClass($this))->handleRequest();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,126 @@
|
|||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Mcp;
|
||||
|
||||
use Exception;
|
||||
use PDO;
|
||||
|
||||
class MigrationManager
|
||||
{
|
||||
private const INIT = [
|
||||
'CREATE TABLE IF NOT EXISTS `mcp_user_identities` (`PrincipalID` CHAR(36) NOT NULL, `IdentityID` CHAR(36) NOT NULL, PRIMARY KEY (`PrincipalID`, `IdentityID`)) ENGINE=MyISAM CHARSET=utf8mb3 COLLATE=utf8mb3_general_ci',
|
||||
'CREATE TABLE IF NOT EXISTS `mcp_password_reset` (`PrincipalID` CHAR(36) NOT NULL, `Token` CHAR(32) NOT NULL, `RequestTime` BIGINT NOT NULL, PRIMARY KEY(`PrincipalID`), UNIQUE(`Token`)) ENGINE MyISAM DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_general_ci',
|
||||
'CREATE TABLE IF NOT EXISTS `mcp_invites` (`InviteCode` CHAR(64) NOT NULL, PRIMARY KEY (`InviteCode`)) ENGINE InnoDB',
|
||||
'CREATE TABLE IF NOT EXISTS `mcp_offlineim_send` (`id` int(6) NOT NULL DEFAULT 0) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci',
|
||||
'CREATE TABLE IF NOT EXISTS `mcp_regions_info` (`regionID` CHAR(36) NOT NULL COLLATE utf8_unicode_ci, `RegionVersion` VARCHAR(128) NOT NULL DEFAULT "" COLLATE utf8_unicode_ci, `ProcMem` INT(11) NOT NULL, `Prims` INT(11) NOT NULL, `SimFPS` INT(11) NOT NULL, `PhyFPS` INT(11) NOT NULL, `OfflineTimer` INT(11) NOT NULL DEFAULT 0, PRIMARY KEY (`regionID`) USING BTREE) COLLATE=utf8_unicode_ci ENGINE=InnoDB',
|
||||
'CREATE TABLE IF NOT EXISTS `mcp_cron_runs` (`Name` VARCHAR(50) NOT NULL, `LastRun` INT(11) UNSIGNED NOT NULL, PRIMARY KEY(`Name`)) ENGINE InnoDB',
|
||||
'CREATE TABLE IF NOT EXISTS `mcp_iar_state` (`userID` CHAR(36) NOT NULL COLLATE utf8_unicode_ci, `filesize` BIGINT(20) NOT NULL DEFAULT 0, `iarfilename` VARCHAR(64) NOT NULL COLLATE utf8_unicode_ci, `state` TINYINT(1) UNSIGNED NOT NULL DEFAULT 0, `created` INT(11) UNSIGNED NOT NULL DEFAULT 0, PRIMARY KEY (`userID`) USING BTREE) COLLATE=utf8_unicode_ci ENGINE=InnoDB',
|
||||
'CREATE TRIGGER IF NOT EXISTS del_id_trig AFTER DELETE ON UserAccounts FOR EACH ROW DELETE FROM mcp_user_identities WHERE mcp_user_identities.PrincipalID = OLD.PrincipalID OR mcp_user_identities.IdentityID = OLD.PrincipalID',
|
||||
'CREATE TRIGGER IF NOT EXISTS del_pwres_trig AFTER DELETE ON UserAccounts FOR EACH ROW DELETE FROM mcp_password_reset WHERE mcp_password_reset.PrincipalID = OLD.PrincipalID'
|
||||
];
|
||||
|
||||
private const MIGRATIONS = [
|
||||
1 => [
|
||||
'RENAME TABLE IF EXISTS UserIdentitys TO mcp_user_identities, PasswordResetTokens TO mcp_password_reset, InviteCodes TO mcp_invites, im_offline_send TO mcp_offlineim_send, regions_info TO mcp_regions_info',
|
||||
'ALTER TABLE mcp_invites MODIFY COLUMN InviteCode CHAR(64) NOT NULL',
|
||||
'ALTER TABLE mcp_regions_info MODIFY COLUMN regionID CHAR(36), MODIFY COLUMN ProcMem INT(11) UNSIGNED NOT NULL, MODIFY COLUMN Prims INT(11) UNSIGNED NOT NULL, MODIFY COLUMN SimFPS FLOAT NOT NULL, MODIFY COLUMN PhyFPS FLOAT NOT NULL, MODIFY COLUMN OfflineTimer BIGINT UNSIGNED NOT NULL DEFAULT 0',
|
||||
'ALTER TABLE mcp_user_identities MODIFY COLUMN PrincipalID CHAR(36) COLLATE utf8mb3_general_ci, MODIFY COLUMN IdentityID CHAR(36) COLLATE utf8mb3_general_ci',
|
||||
'CREATE TRIGGER IF NOT EXISTS del_id_trig AFTER DELETE ON UserAccounts FOR EACH ROW DELETE FROM mcp_user_identities WHERE mcp_user_identities.PrincipalID = OLD.PrincipalID OR mcp_user_identities.IdentityID = OLD.PrincipalID',
|
||||
'CREATE TRIGGER IF NOT EXISTS del_pwres_trig AFTER DELETE ON UserAccounts FOR EACH ROW DELETE FROM mcp_password_reset WHERE mcp_password_reset.PrincipalID = OLD.PrincipalID'
|
||||
],
|
||||
2 => [
|
||||
'CREATE TABLE IF NOT EXISTS `mcp_cron_runs` (`Name` VARCHAR(50) NOT NULL, `LastRun` INT(11) UNSIGNED NOT NULL, PRIMARY KEY(`Name`)) ENGINE InnoDB'
|
||||
],
|
||||
3 => [
|
||||
'RENAME TABLE IF EXISTS iarstates TO mcp_iar_state',
|
||||
'ALTER TABLE mcp_iar_state MODIFY COLUMN userID CHAR(36) NOT NULL COLLATE utf8_unicode_ci, DROP COLUMN running, ADD COLUMN `state` TINYINT(1) UNSIGNED NOT NULL DEFAULT 0 AFTER iarfilename, ADD COLUMN created INT(11) UNSIGNED NOT NULL DEFAULT 0 AFTER `state`'
|
||||
]
|
||||
];
|
||||
|
||||
private const MIGRATE_VERSION_CURRENT = 4;
|
||||
|
||||
private int $migrateVersion;
|
||||
private string $migrateVersionFile;
|
||||
|
||||
public function __construct(string $migrateVersionFile)
|
||||
{
|
||||
$this->migrateVersionFile = $migrateVersionFile;
|
||||
$this->migrateVersion = 0;
|
||||
$apcu = false;
|
||||
if ($this->apcuAvailable()) {
|
||||
$this->migrateVersion = apcu_exists('mcp_migrate_version') ? apcu_fetch('mcp_migrate_version') : 0;
|
||||
$apcu = true;
|
||||
}
|
||||
|
||||
if ($this->migrateVersion == 0 && file_exists($migrateVersionFile)) {
|
||||
$migrateVer = file_get_contents($migrateVersionFile);
|
||||
if (preg_match('/^\d+$/', $migrateVer)) {
|
||||
$this->migrateVersion = intval($migrateVer);
|
||||
if ($apcu) {
|
||||
apcu_store('mcp_migrate_version', $this->migrateVersion);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function isMigrated(): bool
|
||||
{
|
||||
return $this->migrateVersion == $this::MIGRATE_VERSION_CURRENT;
|
||||
}
|
||||
|
||||
public function migrate(PDO $db): bool
|
||||
{
|
||||
if ($this->migrateVersion == 0) {
|
||||
// MCP < v2.x.x might be initialized without migration data
|
||||
$checkLegacy = $db->prepare('SHOW TABLES LIKE ?');
|
||||
$checkLegacy->execute(['UserIdentitys']);
|
||||
if ($checkLegacy->rowCount() > 0) {
|
||||
$this->migrateVersion = 1;
|
||||
}
|
||||
else {
|
||||
return $this->runStatements($db, $this::INIT) && $this->updateVersion();
|
||||
}
|
||||
}
|
||||
|
||||
for ($ver = $this->migrateVersion; $ver <= count($this::MIGRATIONS); $ver++) {
|
||||
if (!isset($this::MIGRATIONS[$ver])) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (!$this->runStatements($db, $this::MIGRATIONS[$ver])) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
$this->updateVersion();
|
||||
return true;
|
||||
}
|
||||
|
||||
private function updateVersion(): bool
|
||||
{
|
||||
file_put_contents($this->migrateVersionFile, $this::MIGRATE_VERSION_CURRENT);
|
||||
if ($this->apcuAvailable()) {
|
||||
apcu_store('mcp_migrate_version', $this::MIGRATE_VERSION_CURRENT);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private function runStatements(PDO $db, array $stmts): bool
|
||||
{
|
||||
try {
|
||||
foreach ($stmts as $stmt) {
|
||||
$db->exec($stmt);
|
||||
}
|
||||
return true;
|
||||
} catch (Exception $e) {
|
||||
error_log('Could not execute statements: '.$e->getMessage()."\n".$e->getTraceAsString());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private function apcuAvailable(): bool
|
||||
{
|
||||
return function_exists('apcu_fetch') && apcu_enabled();
|
||||
}
|
||||
}
|
487
app/OpenSim.php
487
app/OpenSim.php
|
@ -1,221 +1,280 @@
|
|||
<?php
|
||||
class OpenSim
|
||||
{
|
||||
public function isLoginValid($name, $password)
|
||||
{
|
||||
global $RUNTIME;
|
||||
declare(strict_types=1);
|
||||
|
||||
$nameParts = explode(" ", trim($name));
|
||||
if(count($nameParts) != 2) {
|
||||
return false;
|
||||
}
|
||||
namespace Mcp;
|
||||
|
||||
$statementUser = $RUNTIME['PDO']->prepare("SELECT PrincipalID FROM UserAccounts WHERE FirstName = ? AND LastName = ? LIMIT 1");
|
||||
$statementUser->execute($nameParts);
|
||||
use Exception;
|
||||
use PDO;
|
||||
|
||||
while($rowUser = $statementUser->fetch())
|
||||
{
|
||||
$statementAuth = $RUNTIME['PDO']->prepare("SELECT passwordHash,passwordSalt FROM auth WHERE UUID = ? LIMIT 1");
|
||||
$statementAuth->execute(array($rowUser['PrincipalID']));
|
||||
class OpenSim
|
||||
{
|
||||
|
||||
while($rowAuth = $statementAuth->fetch())
|
||||
{
|
||||
return md5(md5($_POST['password']).":".$rowAuth['passwordSalt']) == $rowAuth['passwordHash'];
|
||||
}
|
||||
}
|
||||
private PDO $pdo;
|
||||
private bool $apcu;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public function getUserName($userID)
|
||||
{
|
||||
global $RUNTIME;
|
||||
|
||||
if($userID == "00000000-0000-0000-0000-000000000000")
|
||||
return "Unknown User";
|
||||
|
||||
if(isset($RUNTIME['CACHE']['USERNAME'][$userID]))
|
||||
return $RUNTIME['CACHE']['USERNAME'][$userID];
|
||||
|
||||
$statementUser = $RUNTIME['PDO']->prepare("SELECT FirstName,LastName FROM UserAccounts WHERE PrincipalID = ?");
|
||||
$statementUser->execute(array($userID));
|
||||
|
||||
while($rowUser = $statementUser->fetch())
|
||||
{
|
||||
$RUNTIME['CACHE']['USERNAME'][$userID] = $rowUser['FirstName']." ".$rowUser['LastName'];
|
||||
return $rowUser['FirstName']." ".$rowUser['LastName'];
|
||||
}
|
||||
|
||||
$statementGridUser = $RUNTIME['PDO']->prepare("SELECT UserID FROM GridUser");
|
||||
$statementGridUser->execute();
|
||||
|
||||
while($rowGridUser = $statementGridUser->fetch())
|
||||
{
|
||||
$UserData = explode(";", $rowGridUser['UserID']);
|
||||
|
||||
if(count($UserData) >= 3)
|
||||
{
|
||||
$DBUserID = $UserData[0];
|
||||
$DBUserName = $UserData[2];
|
||||
|
||||
$RUNTIME['CACHE']['USERNAME'][$userID] = $DBUserName;
|
||||
|
||||
if($DBUserID == $userID)
|
||||
return $DBUserName;
|
||||
}
|
||||
}
|
||||
|
||||
$statementFriends = $RUNTIME['PDO']->prepare("SELECT PrincipalID FROM Friends");
|
||||
$statementFriends->execute();
|
||||
|
||||
while($rowFriends = $statementFriends->fetch())
|
||||
{
|
||||
$UserData = explode(";", $rowFriends['PrincipalID']);
|
||||
|
||||
if(count($UserData) == 4)
|
||||
{
|
||||
$DBUserID = $UserData[0];
|
||||
$DBUserName = $UserData[2];
|
||||
|
||||
$RUNTIME['CACHE']['USERNAME'][$userID] = $DBUserName;
|
||||
|
||||
if($DBUserID == $userID)
|
||||
return $DBUserName;
|
||||
}
|
||||
}
|
||||
|
||||
return "Unknown User";
|
||||
}
|
||||
|
||||
public function getUserUUID($UserName)
|
||||
{
|
||||
global $RUNTIME;
|
||||
|
||||
$statementUser = $RUNTIME['PDO']->prepare("SELECT PrincipalID,FirstName,LastName FROM UserAccounts");
|
||||
$statementUser->execute();
|
||||
|
||||
while($rowUser = $statementUser->fetch())
|
||||
{
|
||||
$SQLUserName = $rowUser['FirstName']." ".$rowUser['LastName'];
|
||||
|
||||
if($SQLUserName == $UserName)
|
||||
{
|
||||
return $rowUser['PrincipalID'];
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public function getRegionName($regionID)
|
||||
{
|
||||
global $RUNTIME;
|
||||
|
||||
$statementRegion = $RUNTIME['PDO']->prepare("SELECT regionName FROM regions WHERE uuid = ?");
|
||||
$statementRegion->execute(array($regionID));
|
||||
|
||||
while($rowRegion = $statementRegion->fetch())
|
||||
{
|
||||
return $rowRegion['regionName'];
|
||||
}
|
||||
|
||||
return "Unknown Region";
|
||||
}
|
||||
|
||||
public function getPartner($userID)
|
||||
{
|
||||
global $RUNTIME;
|
||||
|
||||
$statement = $RUNTIME['PDO']->prepare("SELECT profilePartner FROM userprofile WHERE useruuid = ?");
|
||||
$statement->execute(array($userID));
|
||||
|
||||
while($row = $statement->fetch())
|
||||
{
|
||||
if($row['profilePartner'] != "00000000-0000-0000-0000-000000000000")
|
||||
return $row['profilePartner'];
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public function allowOfflineIM($userID)
|
||||
{
|
||||
global $RUNTIME;
|
||||
|
||||
$statement = $RUNTIME['PDO']->prepare("SELECT imviaemail FROM usersettings WHERE useruuid = ?");
|
||||
$statement->execute(array($userID));
|
||||
|
||||
while($row = $statement->fetch())
|
||||
{
|
||||
return strtoupper($row['imviaemail']);
|
||||
}
|
||||
|
||||
return "FALSE";
|
||||
}
|
||||
|
||||
public function getUserMail($userID)
|
||||
{
|
||||
global $RUNTIME;
|
||||
|
||||
$statement = $RUNTIME['PDO']->prepare("SELECT Email FROM UserAccounts WHERE PrincipalID = ?");
|
||||
$statement->execute(array($userID));
|
||||
|
||||
while($row = $statement->fetch())
|
||||
{
|
||||
return $row['Email'];
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
public function getUserCount()
|
||||
{
|
||||
global $RUNTIME;
|
||||
|
||||
$statementUser = $RUNTIME['PDO']->prepare("SELECT COUNT(*) FROM UserAccounts");
|
||||
$statementUser->execute();
|
||||
return $statementUser->fetchColumn();
|
||||
}
|
||||
|
||||
public function getRegionCount()
|
||||
{
|
||||
global $RUNTIME;
|
||||
|
||||
$statementUser = $RUNTIME['PDO']->prepare("SELECT COUNT(*) FROM regions");
|
||||
$statementUser->execute();
|
||||
return $statementUser->fetchColumn();
|
||||
}
|
||||
|
||||
public function getOnlineCount()
|
||||
{
|
||||
global $RUNTIME;
|
||||
|
||||
$statementUser = $RUNTIME['PDO']->prepare("SELECT COUNT(*) FROM Presence");
|
||||
$statementUser->execute();
|
||||
return $statementUser->fetchColumn();
|
||||
}
|
||||
|
||||
public function gen_uuid()
|
||||
{
|
||||
return sprintf( '%04x%04x-%04x-%04x-%04x-%04x%04x%04x',
|
||||
// 32 bits for "time_low"
|
||||
mt_rand( 0, 0xffff ), mt_rand( 0, 0xffff ),
|
||||
|
||||
// 16 bits for "time_mid"
|
||||
mt_rand( 0, 0xffff ),
|
||||
|
||||
// 16 bits for "time_hi_and_version",
|
||||
// four most significant bits holds version number 4
|
||||
mt_rand( 0, 0x0fff ) | 0x4000,
|
||||
|
||||
// 16 bits, 8 bits for "clk_seq_hi_res",
|
||||
// 8 bits for "clk_seq_low",
|
||||
// two most significant bits holds zero and one for variant DCE1.1
|
||||
mt_rand( 0, 0x3fff ) | 0x8000,
|
||||
|
||||
// 48 bits for "node"
|
||||
mt_rand( 0, 0xffff ), mt_rand( 0, 0xffff ), mt_rand( 0, 0xffff )
|
||||
);
|
||||
}
|
||||
public function __construct(PDO $pdo)
|
||||
{
|
||||
$this->pdo = $pdo;
|
||||
$this->apcu = function_exists('apcu_fetch') && apcu_enabled();
|
||||
}
|
||||
?>
|
||||
|
||||
private function getUserNameFromGridData($userID, $table, $row): ?string
|
||||
{
|
||||
$statementGridUser = $this->pdo->prepare('SELECT '.$row.' FROM '.$table.' WHERE '.$row.' LIKE ?');
|
||||
$statementGridUser->execute(array($userID.';%'));
|
||||
|
||||
while ($rowGridUser = $statementGridUser->fetch()) {
|
||||
$userData = explode(";", $rowGridUser[$row]);
|
||||
|
||||
if (count($userData) >= 3) {
|
||||
$dbUserID = $userData[0];
|
||||
$dbUserName = $userData[2];
|
||||
|
||||
if ($dbUserID == $userID) {
|
||||
if ($this->apcu) {
|
||||
apcu_store('os_username_'.$userID, $dbUserName, 600);
|
||||
}
|
||||
return $dbUserName;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public function getUserName($userID): string
|
||||
{
|
||||
if ($userID == "00000000-0000-0000-0000-000000000000") {
|
||||
return "Unknown User";
|
||||
}
|
||||
|
||||
if ($this->apcu && apcu_exists('os_username_'.$userID)) {
|
||||
return apcu_fetch('os_username_'.$userID);
|
||||
}
|
||||
|
||||
$statementUser = $this->pdo->prepare('SELECT FirstName,LastName FROM UserAccounts WHERE PrincipalID = ?');
|
||||
$statementUser->execute(array($userID));
|
||||
|
||||
if ($rowUser = $statementUser->fetch()) {
|
||||
$name = $rowUser['FirstName'].' '.$rowUser['LastName'];
|
||||
if ($this->apcu) {
|
||||
apcu_store('os_username_'.$userID, $name, 300);
|
||||
}
|
||||
|
||||
return $name;
|
||||
}
|
||||
|
||||
$res = $this->getUserNameFromGridData($userID, 'GridUser', 'UserID');
|
||||
if ($res == null) {
|
||||
$res = $this->getUserNameFromGridData($userID, 'Friends', 'PrincipalID');
|
||||
}
|
||||
|
||||
return $res == null ? "Unknown User" : $res;
|
||||
}
|
||||
|
||||
public function getUserUUID($userName): ?string
|
||||
{
|
||||
$statementUser = $this->pdo->prepare('SELECT PrincipalID,FirstName,LastName FROM UserAccounts WHERE FirstName = ? AND LastName = ?');
|
||||
$statementUser->execute(explode(' ', $userName));
|
||||
|
||||
if ($rowUser = $statementUser->fetch()) {
|
||||
return $rowUser['PrincipalID'];
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public function getRegionName($regionID): string
|
||||
{
|
||||
$statementRegion = $this->pdo->prepare("SELECT regionName FROM regions WHERE uuid = ?");
|
||||
$statementRegion->execute(array($regionID));
|
||||
|
||||
if ($rowRegion = $statementRegion->fetch()) {
|
||||
return $rowRegion['regionName'];
|
||||
}
|
||||
|
||||
return "Unknown Region";
|
||||
}
|
||||
|
||||
public function getPartner($userID): string
|
||||
{
|
||||
$statement = $this->pdo->prepare("SELECT profilePartner FROM userprofile WHERE useruuid = ?");
|
||||
$statement->execute(array($userID));
|
||||
|
||||
while ($row = $statement->fetch()) {
|
||||
if ($row['profilePartner'] != "00000000-0000-0000-0000-000000000000") {
|
||||
return $row['profilePartner'];
|
||||
}
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
public function allowOfflineIM($userID): string
|
||||
{
|
||||
$statement = $this->pdo->prepare("SELECT imviaemail FROM usersettings WHERE useruuid = ?");
|
||||
$statement->execute(array($userID));
|
||||
|
||||
if ($row = $statement->fetch()) {
|
||||
return strtoupper($row['imviaemail']);
|
||||
}
|
||||
|
||||
return "FALSE";
|
||||
}
|
||||
|
||||
public function getUserMail($userID): string
|
||||
{
|
||||
$statement = $this->pdo->prepare("SELECT Email FROM UserAccounts WHERE PrincipalID = ?");
|
||||
$statement->execute(array($userID));
|
||||
|
||||
if ($row = $statement->fetch()) {
|
||||
return $row['Email'];
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
private function getEntryCount($table): int
|
||||
{
|
||||
$statementCount = $this->pdo->prepare('SELECT COUNT(*) AS Count FROM '.$table);
|
||||
$statementCount->execute();
|
||||
if ($row = $statementCount->fetch()) {
|
||||
return $row['Count'];
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
public function getUserCount(): int
|
||||
{
|
||||
return $this->getEntryCount('UserAccounts');
|
||||
}
|
||||
|
||||
public function getRegionCount(): int
|
||||
{
|
||||
return $this->getEntryCount('regions');
|
||||
}
|
||||
|
||||
public function getOnlineCount(): int
|
||||
{
|
||||
return $this->getEntryCount('Presence');
|
||||
}
|
||||
|
||||
public function deleteUser($uuid): bool
|
||||
{
|
||||
try {
|
||||
$this->pdo->beginTransaction();
|
||||
|
||||
$statementAuth = $this->pdo->prepare('DELETE FROM auth WHERE UUID = ?');
|
||||
$statementAuth->execute([$uuid]);
|
||||
|
||||
$statementAgentPrefs = $this->pdo->prepare('DELETE FROM AgentPrefs WHERE PrincipalID = ?');
|
||||
$statementAgentPrefs->execute([$uuid]);
|
||||
|
||||
$statementAvatars = $this->pdo->prepare('DELETE FROM Avatars WHERE PrincipalID = ?');
|
||||
$statementAvatars->execute([$uuid]);
|
||||
|
||||
$statementGridUser = $this->pdo->prepare('DELETE FROM GridUser WHERE UserID = ?');
|
||||
$statementGridUser->execute([$uuid]);
|
||||
|
||||
$statementEstateUser = $this->pdo->prepare('DELETE FROM estate_users WHERE uuid = ?');
|
||||
$statementEstateUser->execute([$uuid]);
|
||||
|
||||
$statementEstateBan = $this->pdo->prepare('DELETE FROM estateban WHERE bannedUUID = ?');
|
||||
$statementEstateBan->execute([$uuid]);
|
||||
|
||||
$statementHgTraveling = $this->pdo->prepare('DELETE FROM hg_traveling_data WHERE UserID = ?');
|
||||
$statementHgTraveling->execute([$uuid]);
|
||||
|
||||
$statementUserIdentitys = $this->pdo->prepare('DELETE FROM mcp_user_identities WHERE PrincipalID = ?');
|
||||
$statementUserIdentitys->execute([$uuid]);
|
||||
|
||||
$statementFriends = $this->pdo->prepare('DELETE FROM Friends WHERE PrincipalID = ? OR Friend = ?');
|
||||
$statementFriends->execute([$uuid, $uuid]);
|
||||
|
||||
$statementImOffline = $this->pdo->prepare('DELETE FROM im_offline WHERE PrincipalID = ?');
|
||||
$statementImOffline->execute([$uuid]);
|
||||
|
||||
$statementInventoryFolders = $this->pdo->prepare('DELETE FROM inventoryfolders WHERE agentID = ?');
|
||||
$statementInventoryFolders->execute([$uuid]);
|
||||
|
||||
$statementInventoryItems = $this->pdo->prepare('DELETE FROM inventoryitems WHERE avatarID = ?');
|
||||
$statementInventoryItems->execute([$uuid]);
|
||||
|
||||
$statementGroupMembership = $this->pdo->prepare('DELETE FROM os_groups_membership WHERE PrincipalID = ?');
|
||||
$statementGroupMembership->execute([$uuid]);
|
||||
|
||||
$statementGroupRoles = $this->pdo->prepare('DELETE FROM os_groups_rolemembership WHERE PrincipalID = ?');
|
||||
$statementGroupRoles->execute([$uuid]);
|
||||
|
||||
$statementGroupRoles = $this->pdo->prepare('DELETE FROM Presence WHERE UserID = ?');
|
||||
$statementGroupRoles->execute([$uuid]);
|
||||
|
||||
$statementMute = $this->pdo->prepare('DELETE FROM MuteList WHERE AgentID = ? OR MuteID = ?');
|
||||
$statementMute->execute([$uuid, $uuid]);
|
||||
|
||||
$statementUserAccounts = $this->pdo->prepare('DELETE FROM UserAccounts WHERE PrincipalID = ?');
|
||||
$statementUserAccounts->execute([$uuid]);
|
||||
|
||||
$statementUserData = $this->pdo->prepare('DELETE FROM userdata WHERE UserId = ?');
|
||||
$statementUserData->execute([$uuid]);
|
||||
|
||||
$statementUserNotes = $this->pdo->prepare('DELETE FROM usernotes WHERE targetuuid = ?');
|
||||
$statementUserNotes->execute([$uuid]);
|
||||
|
||||
$statementUserProfile = $this->pdo->prepare('DELETE FROM userprofile WHERE useruuid = ?');
|
||||
$statementUserProfile->execute([$uuid]);
|
||||
|
||||
$statementUserSettings = $this->pdo->prepare('DELETE FROM usersettings WHERE useruuid = ?');
|
||||
$statementUserSettings->execute([$uuid]);
|
||||
|
||||
$this->pdo->commit();
|
||||
|
||||
return true;
|
||||
} catch (Exception $pdoException) {
|
||||
$this->pdo->rollBack();
|
||||
error_log('Could not delete account '.$uuid.': '.$pdoException->getMessage());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public function deleteIdentity($uuid, $identId): bool
|
||||
{
|
||||
$statementValidate = $this->pdo->prepare('SELECT 1 FROM mcp_user_identities WHERE PrincipalID = ? AND IdentityID = ?');
|
||||
$statementValidate->execute([$uuid, $identId]);
|
||||
|
||||
if($statementValidate->fetch()) {
|
||||
$statementDelete = $this->pdo->prepare('DELETE FROM UserAccounts WHERE PrincipalID = ?');
|
||||
$statementDelete->execute([$identId]);
|
||||
|
||||
$statementUserProfile = $this->pdo->prepare('DELETE FROM userprofile WHERE useruuid = ?');
|
||||
$statementUserProfile->execute([$identId]);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public function generateUuid(): string
|
||||
{
|
||||
return sprintf( '%04x%04x-%04x-%04x-%04x-%04x%04x%04x',
|
||||
// 32 bits for "time_low"
|
||||
mt_rand( 0, 0xffff ), mt_rand( 0, 0xffff ),
|
||||
|
||||
// 16 bits for "time_mid"
|
||||
mt_rand( 0, 0xffff ),
|
||||
|
||||
// 16 bits for "time_hi_and_version",
|
||||
// four most significant bits holds version number 4
|
||||
mt_rand( 0, 0x0fff ) | 0x4000,
|
||||
|
||||
// 16 bits, 8 bits for "clk_seq_hi_res",
|
||||
// 8 bits for "clk_seq_low",
|
||||
// two most significant bits holds zero and one for variant DCE1.1
|
||||
mt_rand( 0, 0x3fff ) | 0x8000,
|
||||
|
||||
// 48 bits for "node"
|
||||
mt_rand( 0, 0xffff ), mt_rand( 0, 0xffff ), mt_rand( 0, 0xffff )
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,54 @@
|
|||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Mcp;
|
||||
|
||||
use Exception;
|
||||
use Mcp\Middleware\Middleware;
|
||||
|
||||
abstract class RequestHandler
|
||||
{
|
||||
|
||||
protected Mcp $app;
|
||||
private ?Middleware $middleware;
|
||||
|
||||
public function __construct(Mcp $app, Middleware $mw = null)
|
||||
{
|
||||
$this->app = $app;
|
||||
$this->middleware = $mw;
|
||||
}
|
||||
|
||||
public function handleRequest(): void
|
||||
{
|
||||
if ($_SERVER['REQUEST_METHOD'] != 'GET' && $_SERVER['REQUEST_METHOD'] != 'POST') {
|
||||
http_response_code(400);
|
||||
exit();
|
||||
}
|
||||
|
||||
if ($this->middleware != null) {
|
||||
try {
|
||||
if (!$this->middleware->canAccess()) {
|
||||
$this->middleware->handleUnauthorized();
|
||||
exit();
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
error_log("Middleware handling raised an exception: " + $e->getMessage());
|
||||
http_response_code(500);
|
||||
exit();
|
||||
}
|
||||
}
|
||||
|
||||
$_SERVER['REQUEST_METHOD'] == 'GET' ? $this->get() : $this->post();
|
||||
}
|
||||
|
||||
public function get(): void
|
||||
{
|
||||
http_response_code(405);
|
||||
}
|
||||
|
||||
public function post(): void
|
||||
{
|
||||
http_response_code(405);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,78 @@
|
|||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Mcp;
|
||||
|
||||
use Mcp\Util\TemplateVarArray;
|
||||
|
||||
class TemplateBuilder
|
||||
{
|
||||
|
||||
private string $basedir;
|
||||
private string $name;
|
||||
private ?string $parent = null;
|
||||
private array $vars = [];
|
||||
|
||||
public function __construct(string $basedir, string $name)
|
||||
{
|
||||
$this->basedir = $basedir;
|
||||
$this->name = $name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets another template to be the "parent" of this one.
|
||||
*
|
||||
* The template specified in this TemplateBuilder's constructor will be included into the parent.
|
||||
*/
|
||||
public function parent(string $parent): TemplateBuilder
|
||||
{
|
||||
$this->parent = $parent;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets multiple variables after escaping them.
|
||||
*/
|
||||
public function vars(array $vars): TemplateBuilder
|
||||
{
|
||||
foreach ($vars as $key => $val) {
|
||||
$this->vars[$key] = htmlspecialchars(strval($val));
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the specified variable for this template, after escaping it.
|
||||
*/
|
||||
public function var(string $key, string $val): TemplateBuilder
|
||||
{
|
||||
$this->vars[$key] = htmlspecialchars($val);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the specified variable for this template WITHOUT escaping it.
|
||||
*
|
||||
* User input included this way has to be manually sanitized before.
|
||||
*/
|
||||
public function unsafeVar(string $key, string $val): TemplateBuilder
|
||||
{
|
||||
$this->vars[$key] = $val;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays the template(s) with the current set of variables.
|
||||
*/
|
||||
public function render(): void
|
||||
{
|
||||
$v = new TemplateVarArray($this->vars);
|
||||
$basepath = $this->basedir.DIRECTORY_SEPARATOR;
|
||||
if ($this->parent == null) {
|
||||
require $basepath.$this->name;
|
||||
} else {
|
||||
$v['child-template'] = $basepath.$this->name;
|
||||
require $basepath.$this->parent;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,50 @@
|
|||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Mcp\Api;
|
||||
|
||||
use Mcp\RequestHandler;
|
||||
|
||||
class CronStarter extends RequestHandler
|
||||
{
|
||||
|
||||
private const CRONJOBS_INTERNAL = ['SessionCleanup'];
|
||||
|
||||
public function get(): void
|
||||
{
|
||||
if ($this->app->config('cron-restriction') == 'key' && !(isset($_GET['key']) && hash_equals($this->app->config('cron-key'), $_GET['key']))) {
|
||||
http_response_code(403);
|
||||
return;
|
||||
}
|
||||
|
||||
$cronJobs = array_merge($this->app->config('cronjobs'), $this::CRONJOBS_INTERNAL);
|
||||
|
||||
$cronStatement = $this->app->db()->prepare('SELECT Name,LastRun FROM mcp_cron_runs');
|
||||
$cronStatement->execute();
|
||||
|
||||
$jobRuns = array();
|
||||
while ($row = $cronStatement->fetch()) {
|
||||
$jobRuns[$row['Name']] = $row['LastRun'];
|
||||
}
|
||||
|
||||
$resArray = [];
|
||||
$cronUpdateStatement = $this->app->db()->prepare('REPLACE INTO mcp_cron_runs(Name,LastRun) VALUES (?,?)');
|
||||
foreach ($cronJobs as $jobName) {
|
||||
$jobClass = "Mcp\\Cron\\".$jobName;
|
||||
if (in_array($jobName, $cronJobs)) {
|
||||
$job = (new $jobClass($this->app));
|
||||
$now = time();
|
||||
$nextRun = $job->getNextRun(isset($jobRuns[$jobName]) ? $jobRuns[$jobName] : $now - 60);
|
||||
if ($now >= $nextRun && $job->run()) {
|
||||
$cronUpdateStatement->execute([$jobName, time()]);
|
||||
$resArray[$jobName] = ['result' => 'ok', 'nextRun' => $job->getNextRun(time())];
|
||||
}
|
||||
else {
|
||||
$resArray[$jobName] = ['result' => 'failed'];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
echo json_encode($resArray);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Mcp\Api;
|
||||
|
||||
class DownloadIar extends \Mcp\RequestHandler
|
||||
{
|
||||
|
||||
public function get(): void
|
||||
{
|
||||
if (preg_match('/^[a-f0-9]{32}$/', $_GET['id'])) {
|
||||
$path = $this->app->getDataDir().DIRECTORY_SEPARATOR.'iars'.DIRECTORY_SEPARATOR.$_GET['id'].'.iar';
|
||||
if (file_exists($path)) {
|
||||
header('Content-Type: '.mime_content_type($path));
|
||||
header('Content-Disposition: attachment; filename='.$_GET['id'].'.iar');
|
||||
header('Content-Length: '.filesize($path));
|
||||
readfile($path);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
http_response_code(404);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,119 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Mcp\Api;
|
||||
|
||||
class Economy extends \Mcp\RequestHandler
|
||||
{
|
||||
|
||||
private const SYSURL = ""; // ???
|
||||
|
||||
# Copyright (c)Melanie Thielker and Teravus Ovares (http://opensimulator.org/)
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions are met:
|
||||
# * Redistributions of source code must retain the above copyright
|
||||
# notice, this list of conditions and the following disclaimer.
|
||||
# * Redistributions in binary form must reproduce the above copyright
|
||||
# notice, this list of conditions and the following disclaimer in the
|
||||
# documentation and/or other materials provided with the distribution.
|
||||
# * Neither the name of the OpenSim Project nor the
|
||||
# names of its contributors may be used to endorse or promote products
|
||||
# derived from this software without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
|
||||
# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
# DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
|
||||
# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#
|
||||
|
||||
# updated for Robust installations: BlueWall 2011
|
||||
# further minor changes by justincc (http://justincc.org)
|
||||
# Adapted to use PDO and the MCP API by a 4Creative contributor
|
||||
public function handleRequest(): void
|
||||
{
|
||||
# XMLRPC
|
||||
$xmlrpc_server = xmlrpc_server_create();
|
||||
xmlrpc_server_register_method($xmlrpc_server, "preflightBuyLandPrep", function($method_name, $params, $app_data) {
|
||||
$confirmvalue = "";
|
||||
$req = $params[0];
|
||||
$agentid = $req['agentId'];
|
||||
$sessionid = $req['secureSessionId'];
|
||||
$amount = $req['currencyBuy'];
|
||||
$billableArea = $req['billableArea'];
|
||||
|
||||
$id = $this->validateUser($agentid, $sessionid);
|
||||
|
||||
if ($id) {
|
||||
$membership_levels = array(
|
||||
'levels' => array(
|
||||
'id' => "00000000-0000-0000-0000-000000000000",
|
||||
'description' => "some level"
|
||||
)
|
||||
);
|
||||
|
||||
$landUse = array(
|
||||
'upgrade' => false,
|
||||
'action' => "" . $this::SYSURL . ""
|
||||
);
|
||||
|
||||
$currency = array(
|
||||
'estimatedCost' => "200.00"
|
||||
); // convert_to_real($amount));
|
||||
|
||||
$membership = array(
|
||||
'upgrade' => false,
|
||||
'action' => "" . $this::SYSURL . "",
|
||||
'levels' => $membership_levels
|
||||
);
|
||||
|
||||
$response_xml = xmlrpc_encode(array(
|
||||
'success' => true,
|
||||
'currency' => $currency,
|
||||
'membership' => $membership,
|
||||
'landUse' => $landUse,
|
||||
'currency' => $currency,
|
||||
'confirm' => $confirmvalue
|
||||
));
|
||||
|
||||
header("Content-type: text/xml");
|
||||
print $response_xml;
|
||||
} else {
|
||||
header("Content-type: text/xml");
|
||||
$response_xml = xmlrpc_encode(array(
|
||||
'success' => false,
|
||||
'errorMessage' => "\n\nUnable to Authenticate\n\nClick URL for more info.",
|
||||
'errorURI' => "" . $this::SYSURL . ""
|
||||
));
|
||||
|
||||
print $response_xml;
|
||||
}
|
||||
|
||||
return "";
|
||||
});
|
||||
|
||||
$request_xml = file_get_contents('php://input');
|
||||
xmlrpc_server_call_method($xmlrpc_server, $request_xml, '');
|
||||
xmlrpc_server_destroy($xmlrpc_server);
|
||||
}
|
||||
|
||||
private function validateUser($agent_id, $s_session_id)
|
||||
{
|
||||
$stmt = $this->app->db()->prepare("SELECT UserID FROM Presence WHERE UserID=? AND SecureSessionID = ?");
|
||||
$stmt->execute(array($agent_id, $s_session_id));
|
||||
|
||||
if ($stmt->rowCount() == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$res = $stmt->fetch();
|
||||
return $res['UserID'];
|
||||
}
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Mcp\Api;
|
||||
|
||||
class EconomyLandTool extends \Mcp\RequestHandler
|
||||
{
|
||||
public function handleRequest(): void
|
||||
{
|
||||
$membership_levels = array(
|
||||
'levels' => array(
|
||||
'id' => "00000000-0000-0000-0000-000000000000",
|
||||
'description' => "some level"));
|
||||
|
||||
$landUse = array(
|
||||
'upgrade' => false,
|
||||
'action' => "");
|
||||
|
||||
$currency = array(
|
||||
'estimatedCost' => "200.00"); // convert_to_real($amount));
|
||||
|
||||
$membership = array(
|
||||
'upgrade' => false,
|
||||
'action' => "",
|
||||
'levels' => $membership_levels);
|
||||
|
||||
$response_xml = xmlrpc_encode(array(
|
||||
'success' => true,
|
||||
'currency' => $currency,
|
||||
'membership' => $membership,
|
||||
'landUse' => $landUse,
|
||||
'currency' => $currency,
|
||||
'confirm' => "200.00"));
|
||||
|
||||
header("Content-type: text/xml");
|
||||
print $response_xml;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Mcp\Api;
|
||||
|
||||
class GetAccessList extends \Mcp\RequestHandler
|
||||
{
|
||||
public function handleRequest(): void
|
||||
{
|
||||
for ($i = 0; $i < 5; $i++) {
|
||||
echo "1148b04d-7a93-29e9-b3c9-ea1cdeec38f7\n";
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Mcp\Api;
|
||||
|
||||
use \Mcp\OpenSim;
|
||||
|
||||
class OnlineDisplay extends \Mcp\RequestHandler
|
||||
{
|
||||
|
||||
public function get(): void
|
||||
{
|
||||
$statement = $this->app->db()->prepare("SELECT UserID,RegionID FROM Presence WHERE RegionID != '00000000-0000-0000-0000-000000000000' ORDER BY RegionID ASC");
|
||||
$statement->execute();
|
||||
|
||||
$tpl = $this->app->template('online-display.php');
|
||||
if ($statement->rowCount() == 0) {
|
||||
$tpl->unsafeVar('online-users', '<h1 style="text-align: center; margin-top: 60px">Es ist niemand online!</h1>');
|
||||
} else {
|
||||
$table = '<table style="width:350px;margin-left:auto;margin-right:auto;margin-top:25px"><tr><th align="left" style="background-color: #FF8000;">Name</th><th align="left" style="background-color: #FF8000;">Region</th></tr>';
|
||||
$entryColor = true;
|
||||
$opensim = new OpenSim($this->app->db());
|
||||
while ($row = $statement->fetch()) {
|
||||
$table = $table.'<tr style="background-color: '.($entryColor ? '#F2F2F2' : '#E6E6E6').';"><td>'.trim($opensim->getUserName($row['UserID'])).'</td><td>'.$opensim->getRegionName($row['RegionID']).'</td></tr>';
|
||||
$entryColor = !$entryColor;
|
||||
}
|
||||
|
||||
$tpl->unsafeVar('online-users', $table.'</table>');
|
||||
}
|
||||
|
||||
$tpl->render();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Mcp\Api;
|
||||
|
||||
use Mcp\OpenSim;
|
||||
|
||||
class ViewerWelcomePage extends \Mcp\RequestHandler
|
||||
{
|
||||
public function get(): void
|
||||
{
|
||||
$images = array();
|
||||
if ($handle = opendir('./img/viewerWelcomeImages')) {
|
||||
while (false !== ($entry = readdir($handle))) {
|
||||
if ($entry != "." && $entry != "..") {
|
||||
$images[] = "./img/viewerWelcomeImages/".$entry;
|
||||
}
|
||||
}
|
||||
|
||||
closedir($handle);
|
||||
}
|
||||
|
||||
shuffle($images);
|
||||
|
||||
$opensim = new OpenSim($this->app->db());
|
||||
|
||||
$this->app->template('viewerWelcomeImages.php')->vars([
|
||||
'title' => 'Splash',
|
||||
'grid-name' => $this->app->config('grid')['name'],
|
||||
'news' => $this->app->config('grid')['main-news']
|
||||
])->unsafeVar('json-image-array', json_encode($images))
|
||||
->unsafeVar('image-1', $images[0])->unsafeVar('image-2', $images[1])
|
||||
->unsafeVar('stats', "Registrierte User: ".$opensim->getUserCount()."<br>Regionen: ".$opensim->getRegionCount()."<br>Aktuell Online: ".($opensim->getOnlineCount()-1))
|
||||
->render();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
<?php
|
||||
namespace Mcp;
|
||||
|
||||
class Autoloader {
|
||||
|
||||
private string $appPath;
|
||||
private string $libPath;
|
||||
|
||||
public function __construct($basedir)
|
||||
{
|
||||
$this->appPath = $basedir.DIRECTORY_SEPARATOR.'app'.DIRECTORY_SEPARATOR;
|
||||
$this->libPath = $basedir.DIRECTORY_SEPARATOR.'lib'.DIRECTORY_SEPARATOR;
|
||||
}
|
||||
|
||||
public function load($className) {
|
||||
$parts = explode('\\', $className);
|
||||
$len = count($parts);
|
||||
|
||||
$res = $parts[0] === 'Mcp' ? $this->appPath : $this->libPath;
|
||||
for ($i = 1; $i < $len - 1; $i++) {
|
||||
$res = $res.strtolower($parts[$i]).DIRECTORY_SEPARATOR;
|
||||
}
|
||||
|
||||
require $res.$parts[$len - 1].'.php';
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,51 @@
|
|||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Mcp\Cron;
|
||||
|
||||
class AssetChecker extends CronJob
|
||||
{
|
||||
|
||||
public function __construct(\Mcp\Mcp $app)
|
||||
{
|
||||
parent::__construct($app, Frequency::MONTHLY);
|
||||
}
|
||||
|
||||
public function run(): bool
|
||||
{
|
||||
$statement = $this->app->db()->prepare("SELECT id,hash FROM fsassets ORDER BY create_time DESC");
|
||||
$statement->execute();
|
||||
|
||||
$count = 0;
|
||||
|
||||
while ($row = $statement->fetch()) {
|
||||
$fileNameParts = array();
|
||||
$fileNameParts[0] = substr($row['hash'], 0, 2);
|
||||
$fileNameParts[1] = substr($row['hash'], 2, 2);
|
||||
$fileNameParts[2] = substr($row['hash'], 4, 2);
|
||||
$fileNameParts[3] = substr($row['hash'], 6, 4);
|
||||
$fileNameParts[4] = $row['hash'] . ".gz";
|
||||
|
||||
$fileNameParts['UUID'] = $row['id'];
|
||||
$fileNameParts['FilePath'] = "/data/assets/base/" . $fileNameParts[0] . "/" . $fileNameParts[1] . "/" . $fileNameParts[2] . "/" . $fileNameParts[3] . "/" . $fileNameParts[4];
|
||||
|
||||
if (file_exists($fileNameParts['FilePath'])) {
|
||||
$filesize = filesize($fileNameParts['FilePath']);
|
||||
if ($filesize === false) {
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
$filesize = 0;
|
||||
}
|
||||
|
||||
$fileNameParts['FileSize'] = $filesize;
|
||||
$fileNameParts['Count'] = $count++;
|
||||
|
||||
if ($fileNameParts['FileSize'] == 0) {
|
||||
$add = $this->app->db()->prepare('DELETE FROM fsassets WHERE hash = :fileHash');
|
||||
$add->execute(['fileHash' => $row['hash']]);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Mcp\Cron;
|
||||
|
||||
class CheckInventory extends CronJob
|
||||
{
|
||||
public function __construct(\Mcp\Mcp $app)
|
||||
{
|
||||
parent::__construct($app, Frequency::MONTHLY);
|
||||
}
|
||||
|
||||
public function run(): bool
|
||||
{
|
||||
$invCheckStatement = $this->app->db()->prepare("UPDATE inventoryitems i SET i.inventoryName = concat('[DEFEKT] ', i.inventoryName)
|
||||
WHERE i.assetID IN (
|
||||
SELECT i.assetID FROM inventoryitems i WHERE
|
||||
NOT EXISTS(
|
||||
SELECT * FROM fsassets fs WHERE fs.id = i.assetID)
|
||||
AND NOT i.inventoryName LIKE '[DEFEKT] %' AND i.assetType <> 24
|
||||
)");
|
||||
|
||||
$invCheckStatement->execute();
|
||||
return true;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,52 @@
|
|||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Mcp\Cron;
|
||||
|
||||
use DateInterval;
|
||||
use DateTime;
|
||||
use Mcp\Mcp;
|
||||
|
||||
abstract class CronJob {
|
||||
|
||||
protected Mcp $app;
|
||||
private Frequency $freq;
|
||||
|
||||
public function __construct(Mcp $app, Frequency $freq)
|
||||
{
|
||||
$this->app = $app;
|
||||
$this->freq = $freq;
|
||||
}
|
||||
|
||||
public function getNextRun(int $lastRun)
|
||||
{
|
||||
$prevDate = getdate($lastRun);
|
||||
$res = new DateTime('@'.$lastRun);
|
||||
switch($this->freq) {
|
||||
case Frequency::EACH_MINUTE:
|
||||
$res->add(DateInterval::createFromDateString('1 minute'));
|
||||
break;
|
||||
case Frequency::HOURLY:
|
||||
$res->add(DateInterval::createFromDateString('1 hour'));
|
||||
break;
|
||||
case Frequency::DAILY:
|
||||
$res->add(DateInterval::createFromDateString('1 day'));
|
||||
$res->setTime(0, 0, 0);
|
||||
break;
|
||||
case Frequency::WEEKLY:
|
||||
$res->add(DateInterval::createFromDateString('1 week'));
|
||||
break;
|
||||
case Frequency::MONTHLY:
|
||||
$res->setDate($prevDate['year'] + ($prevDate['mon'] == 12 ? 1 : 0), $prevDate['mon'] == 12 ? 1 : $prevDate['mon'] + 1, 1);
|
||||
break;
|
||||
case Frequency::YEARLY:
|
||||
$res->setDate($prevDate['year'] + 1, 1, 1);
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
|
||||
return $res->getTimestamp();
|
||||
}
|
||||
|
||||
abstract public function run(): bool;
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Mcp\Cron;
|
||||
|
||||
enum Frequency
|
||||
{
|
||||
case YEARLY; // 01.01. of each year
|
||||
case MONTHLY; // 1st of each month
|
||||
case WEEKLY; // 1 week after last run
|
||||
case DAILY; // Next day after last run, at 00:00
|
||||
case HOURLY; // One hour after last run
|
||||
case EACH_MINUTE; // One minute after last run
|
||||
}
|
|
@ -0,0 +1,103 @@
|
|||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Mcp\Cron;
|
||||
|
||||
use Mcp\OpenSim;
|
||||
use Mcp\Opensim\RestConsole;
|
||||
use Mcp\Util\Util;
|
||||
|
||||
class IarMonitor extends CronJob
|
||||
{
|
||||
|
||||
private ?RestConsole $console = null;
|
||||
private bool $consoleAvailable = true;
|
||||
|
||||
public function __construct(\Mcp\Mcp $app)
|
||||
{
|
||||
parent::__construct($app, Frequency::EACH_MINUTE);
|
||||
}
|
||||
|
||||
public function run(): bool
|
||||
{
|
||||
$opensim = new OpenSim($this->app->db());
|
||||
|
||||
$dirPath = $this->app->getDataDir().DIRECTORY_SEPARATOR.'iars';
|
||||
if (!is_dir($dirPath)) {
|
||||
mkdir($dirPath);
|
||||
}
|
||||
|
||||
$statement = $this->app->db()->prepare("SELECT userID,iarfilename,filesize,state FROM mcp_iar_state WHERE state < ?");
|
||||
$statement->execute([2]);
|
||||
|
||||
if ($statement->rowCount() > 0) {
|
||||
while ($row = $statement->fetch()) {
|
||||
if ($row['state'] == 0) { // 0 - Request to OS pending
|
||||
if ($this->console() === false) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$name = explode(' ', $opensim->getUserName($row['userID']));
|
||||
if ($this->console()->sendCommand('save iar '.$name[0].' '.$name[1].' /* password '.$this->app->config('iarfetcher')['os-iar-path'].$row['iarfilename'])) {
|
||||
$statementUpdate = $this->app->db()->prepare('UPDATE mcp_iar_state SET state = ? WHERE userID = ?');
|
||||
$statementUpdate->execute([1, $row['userID']]);
|
||||
}
|
||||
} elseif ($row['state'] == 1) { // 1 - IAR Creation in progress
|
||||
$fullFilePath = $dirPath.DIRECTORY_SEPARATOR.$row['iarfilename'];
|
||||
if (file_exists($fullFilePath)) {
|
||||
$filesize = filesize($fullFilePath);
|
||||
|
||||
if ($filesize != $row['filesize']) {
|
||||
$statementUpdate = $this->app->db()->prepare('UPDATE mcp_iar_state SET filesize = ? WHERE userID = ?');
|
||||
$statementUpdate->execute([$filesize, $row['userID']]);
|
||||
} else {
|
||||
$statementUpdate = $this->app->db()->prepare('UPDATE mcp_iar_state SET state = ?, created = ? WHERE userID = ?');
|
||||
$statementUpdate->execute([2, time(), $row['userID']]);
|
||||
|
||||
Util::sendInworldIM("00000000-0000-0000-0000-000000000000", $row['userID'], "Inventory", $this->app->config('grid')['homeurl'], "Deine IAR ist fertig zum Download: https://".$this->app->config('domain').'/index.php?api=downloadIar&id='.substr($row['iarfilename'], 0, strlen($row['iarfilename']) - 4).' , sie ist mit dem Passwort "password" geschützt.');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($this->console != null) {
|
||||
$this->console->closeSession();
|
||||
}
|
||||
}
|
||||
|
||||
// 2 - IAR creation finished; delete if expired
|
||||
$weekOld = time() - 604800;
|
||||
$statementExpired = $this->app->db()->prepare('SELECT userID,iarfilename FROM mcp_iar_state WHERE state = ? AND created < ?');
|
||||
$statementExpired->execute([2, $weekOld]);
|
||||
$statementDeleteExpired = $this->app->db()->prepare('DELETE FROM mcp_iar_state WHERE state = ? AND userID = ?');
|
||||
while ($row = $statementExpired->fetch()) {
|
||||
$fullFilePath = $dirPath.DIRECTORY_SEPARATOR.$row['iarfilename'];
|
||||
if (file_exists($fullFilePath) && unlink($fullFilePath)) {
|
||||
$statementDeleteExpired->execute([2, $row['userID']]);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private function console(): RestConsole|bool
|
||||
{
|
||||
if (!$this->consoleAvailable) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($this->console == null) {
|
||||
$restCfg = $this->app->config('iarfetcher');
|
||||
$console = new RestConsole($restCfg['host'], intval($restCfg['port']));
|
||||
if ($console->startSession($restCfg['user'], $restCfg['password'])) {
|
||||
$this->console = $console;
|
||||
}
|
||||
else {
|
||||
$this->consoleAvailable = false;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return $this->console;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,89 @@
|
|||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Mcp\Cron;
|
||||
|
||||
use Mcp\OpenSim;
|
||||
use Mcp\Util\SmtpClient;
|
||||
|
||||
use SimpleXMLElement;
|
||||
|
||||
class OfflineIm extends CronJob
|
||||
{
|
||||
private const IM_TYPE = array(
|
||||
"0" => "eine Nachricht",
|
||||
"3" => "eine Gruppeneinladung",
|
||||
"4" => "ein Inventaritem",
|
||||
"5" => "eine Bestätigung zur Annahme von Inventar",
|
||||
"6" => "eine Information zur Ablehnung von Inventar",
|
||||
"7" => "eine Aufforderung zur Gruppenwahl",
|
||||
"9" => "ein Inventaritem von einem Script",
|
||||
"19" => "eine Nachricht von einem Script",
|
||||
"32" => "eine Gruppennachricht",
|
||||
"38" => "eine Freundschaftsanfrage",
|
||||
"39" => "eine Bestätigung über die Annahme der Freundschaft",
|
||||
"40" => "eine Information über das Ablehnen der Freundschaft"
|
||||
);
|
||||
|
||||
public function __construct(\Mcp\Mcp $app)
|
||||
{
|
||||
parent::__construct($app, Frequency::EACH_MINUTE);
|
||||
}
|
||||
|
||||
public function run(): bool
|
||||
{
|
||||
$statement = $this->app->db()->prepare("SELECT ID,PrincipalID,Message FROM im_offline");
|
||||
$statement->execute();
|
||||
|
||||
while ($row = $statement->fetch()) {
|
||||
$opensim = new OpenSim($this->app->db());
|
||||
|
||||
$email = $opensim->getUserMail($row['PrincipalID']);
|
||||
$allowOfflineIM = $opensim->allowOfflineIM($row['PrincipalID']);
|
||||
|
||||
if ($email != "" && $allowOfflineIM == "TRUE" && !$this->isMailAlreadySent($row['ID'])) {
|
||||
$statementSend = $this->app->db()->prepare('INSERT INTO mcp_offlineim_send (id) VALUES (:idnummer)');
|
||||
$statementSend->execute(['idnummer' => $row['ID']]);
|
||||
|
||||
$mailcfg = $this->app->config('smtp');
|
||||
$smtpClient = new SmtpClient($mailcfg['host'], intval($mailcfg['port']), $mailcfg['address'], $mailcfg['password']);
|
||||
|
||||
$xmlMessage = new SimpleXMLElement($row['Message']);
|
||||
|
||||
$imType = $this::IM_TYPE["" . $xmlMessage->dialog . ""];
|
||||
$htmlMessage = "Du hast " . $imType . " in " . $this->app->config('grid')['name'] . " bekommen. <br><p><ul><li>" . htmlspecialchars($xmlMessage->message) . "</li></ul></p>Gesendet von: ";
|
||||
|
||||
if (isset($xmlMessage->fromAgentName)) {
|
||||
$htmlMessage .= $xmlMessage->fromAgentName;
|
||||
}
|
||||
|
||||
if (isset($xmlMessage->RegionID) && isset($xmlMessage->Position)) {
|
||||
if ($xmlMessage->Position->X != 0 || $xmlMessage->Position->Y != 0 || $xmlMessage->Position->Z != 0) { //TODO
|
||||
$htmlMessage .= " @ " . $opensim->getRegionName($xmlMessage->RegionID) . "/" . $xmlMessage->Position->X . "/" . $xmlMessage->Position->Y . "/" . $xmlMessage->Position->Z;
|
||||
} else {
|
||||
$htmlMessage .= " @ " . $opensim->getRegionName($xmlMessage->RegionID);
|
||||
}
|
||||
}
|
||||
|
||||
$tpl = $this->app->template('mail.php')->vars([
|
||||
'title' => substr($imType, strpos($imType, ' '))
|
||||
])->unsafeVar('message', $htmlMessage);
|
||||
$smtpClient->sendHtml($mailcfg['address'], $mailcfg['name'], $email, "Du hast " . $imType . " in " . $this->app->config('grid')['name'] . ".", $tpl);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private function isMailAlreadySent($id): bool
|
||||
{
|
||||
$statement = $this->app->db()->prepare("SELECT 1 FROM mcp_offlineim_send WHERE id = ? LIMIT 1");
|
||||
$statement->execute(array($id));
|
||||
|
||||
if ($statement->rowCount() != 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,59 @@
|
|||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Mcp\Cron;
|
||||
|
||||
use Mcp\OpenSim;
|
||||
use Mcp\Util\Util;
|
||||
|
||||
class RegionChecker extends CronJob
|
||||
{
|
||||
public function __construct(\Mcp\Mcp $app)
|
||||
{
|
||||
parent::__construct($app, Frequency::DAILY);
|
||||
}
|
||||
|
||||
public function run(): bool
|
||||
{
|
||||
$statement = $this->app->db()->prepare("SELECT uuid,regionName,owner_uuid,serverURI,OfflineTimer FROM regions LEFT JOIN mcp_regions_info ON regions.uuid = mcp_regions_info.regionID COLLATE utf8mb3_unicode_ci");
|
||||
$statement->execute();
|
||||
|
||||
while ($row = $statement->fetch()) {
|
||||
$curl = curl_init($row['serverURI'] . 'jsonSimStats');
|
||||
curl_setopt($curl, CURLOPT_TIMEOUT, 15);
|
||||
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
|
||||
$result = curl_exec($curl);
|
||||
|
||||
if ($result === false || strlen($result) == 0) {
|
||||
if ($row['OfflineTimer'] == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$opensim = new OpenSim($this->app->db());
|
||||
|
||||
$longOffline = ($row['OfflineTimer'] + 3600) <= time();
|
||||
echo "Die Region " . $row['regionName'] . " von " . $opensim->getUserName($row['owner_uuid']) . " ist " . ($longOffline ? "seit über einer Stunde" : "") . " nicht erreichbar.\n"; //TODO: Increase to 1-3 months
|
||||
|
||||
if ($longOffline) {
|
||||
if ($this->app->config('grid')['delete-inactive-regions']) {
|
||||
Util::sendInworldIM("00000000-0000-0000-0000-000000000000", $row['owner_uuid'], "Region", $this->app->config('grid')['homeurl'], "WARNUNG: Deine Region '" . $row['regionName'] . "' ist nicht erreichbar und wurde deshalb aus dem Grid entfernt.");
|
||||
|
||||
$statementUpdate = $this->app->db()->prepare('DELETE FROM regions WHERE uuid = :uuid');
|
||||
$statementUpdate->execute(['uuid' => $row['uuid']]);
|
||||
}
|
||||
$statementRemoveStats = $this->app->db()->prepare('DELETE FROM mcp_regions_info WHERE regionID = :uuid');
|
||||
$statementRemoveStats->execute(['uuid' => $row['uuid']]);
|
||||
} elseif ($this->app->config('grid')['warn-inactive-regions']) {
|
||||
Util::sendInworldIM("00000000-0000-0000-0000-000000000000", $row['owner_uuid'], "Region", $this->app->config('grid')['homeurl'], "WARNUNG: Deine Region '" . $row['regionName'] . "' ist nicht erreichbar!");
|
||||
}
|
||||
} else {
|
||||
$regionData = json_decode($result);
|
||||
|
||||
$statementAccounts = $this->app->db()->prepare('REPLACE INTO `mcp_regions_info` (`regionID`, `RegionVersion`, `ProcMem`, `Prims`, `SimFPS`, `PhyFPS`, `OfflineTimer`) VALUES (:regionID, :RegionVersion, :ProcMem, :Prims, :SimFPS, :PhyFPS, :OfflineTimer)');
|
||||
$statementAccounts->execute(['regionID' => $row['uuid'], 'RegionVersion' => $regionData->Version, 'ProcMem' => intval(str_replace(',', '', $regionData->ProcMem)), 'Prims' => $regionData->Prims, 'SimFPS' => $regionData->SimFPS, 'PhyFPS' => $regionData->PhyFPS, 'OfflineTimer' => time()]);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Mcp\Cron;
|
||||
|
||||
class SessionCleanup extends CronJob
|
||||
{
|
||||
public function __construct(\Mcp\Mcp $app)
|
||||
{
|
||||
parent::__construct($app, Frequency::HOURLY);
|
||||
}
|
||||
|
||||
public function run(): bool
|
||||
{
|
||||
error_log("Session GC");
|
||||
session_start();
|
||||
session_gc();
|
||||
return true;
|
||||
}
|
||||
}
|
|
@ -1,19 +0,0 @@
|
|||
<?php
|
||||
function sendMessageToWebhook($webhook, $title, $message)
|
||||
{
|
||||
$RAWmessage = file_get_contents("style/discordMessage.json");
|
||||
$RAWmessage = str_replace("%%message%%", $message, $RAWmessage);
|
||||
$RAWmessage = str_replace("%%title%%", $title, $RAWmessage);
|
||||
|
||||
$options = [
|
||||
'http' => [
|
||||
'method' => 'POST',
|
||||
'header' => 'Content-Type: application/json',
|
||||
'timeout' => 3,
|
||||
'content' => $RAWmessage
|
||||
]
|
||||
];
|
||||
|
||||
$result = file_get_contents($webhook, false, stream_context_create($options));
|
||||
}
|
||||
?>
|
|
@ -0,0 +1,16 @@
|
|||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Mcp\Middleware;
|
||||
|
||||
class AdminMiddleware extends LoginRequiredMiddleware
|
||||
{
|
||||
public function canAccess(): bool
|
||||
{
|
||||
if (parent::canAccess()) {
|
||||
return $_SESSION['LEVEL'] > 100;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Mcp\Middleware;
|
||||
|
||||
use Mcp\ConnectionProvider;
|
||||
|
||||
class LoginRequiredMiddleware extends SessionMiddleware
|
||||
{
|
||||
|
||||
private ConnectionProvider $connProvider;
|
||||
|
||||
public function __construct(ConnectionProvider $connProvider, string $cookieDomain)
|
||||
{
|
||||
parent::__construct($cookieDomain, 3600);
|
||||
$this->connProvider = $connProvider;
|
||||
}
|
||||
|
||||
public function canAccess(): bool
|
||||
{
|
||||
parent::handleSession();
|
||||
if (isset($_SESSION['UUID'])) {
|
||||
// User level or existence of account may have changed since session was created
|
||||
$getLevel = $this->connProvider->db()->prepare('SELECT UserLevel FROM UserAccounts WHERE PrincipalID = ?');
|
||||
$getLevel->execute([$_SESSION['UUID']]);
|
||||
if ($row = $getLevel->fetch()) {
|
||||
$_SESSION['LEVEL'] = $row['UserLevel'];
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
session_unset();
|
||||
session_destroy();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public function handleUnauthorized(): void
|
||||
{
|
||||
header('Location: index.php?page=login');
|
||||
}
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Mcp\Middleware;
|
||||
|
||||
/**
|
||||
* Middleware implementations can be registered for a RequestHandler.
|
||||
*
|
||||
* If this is done, request processing continues only if Middleware::canAccess() returns true.
|
||||
*/
|
||||
interface Middleware
|
||||
{
|
||||
/**
|
||||
* Returns true if the request should be processed, i.e. if the client has permissionn to perform this request.
|
||||
*/
|
||||
public function canAccess(): bool;
|
||||
|
||||
/**
|
||||
* Called when canAcces() returns false, e.g. to redirect unauthorized users.
|
||||
*/
|
||||
public function handleUnauthorized(): void;
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Mcp\Middleware;
|
||||
|
||||
class PreSessionMiddleware extends SessionMiddleware
|
||||
{
|
||||
public function __construct(string $cookieDomain)
|
||||
{
|
||||
parent::__construct($cookieDomain, 0);
|
||||
}
|
||||
|
||||
public function canAccess(): bool
|
||||
{
|
||||
parent::handleSession();
|
||||
return !isset($_SESSION['LOGIN']);
|
||||
}
|
||||
|
||||
public function handleUnauthorized(): void
|
||||
{
|
||||
header('Location: index.php');
|
||||
}
|
||||
}
|
|
@ -0,0 +1,45 @@
|
|||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Mcp\Middleware;
|
||||
|
||||
use UnexpectedValueException;
|
||||
|
||||
abstract class SessionMiddleware implements Middleware
|
||||
{
|
||||
|
||||
private string $cookieDomain;
|
||||
private int $cookieLifetime;
|
||||
|
||||
public function __construct(string $cookieDomain, int $cookieLifetime)
|
||||
{
|
||||
$this->cookieDomain = $cookieDomain;
|
||||
$this->cookieLifetime = $cookieLifetime;
|
||||
}
|
||||
|
||||
protected function handleSession(): void
|
||||
{
|
||||
switch(session_status()) {
|
||||
case PHP_SESSION_DISABLED:
|
||||
throw new UnexpectedValueException("Session functionality is disabled");
|
||||
break;
|
||||
case PHP_SESSION_NONE:
|
||||
session_set_cookie_params([
|
||||
'lifetime' => $this->cookieLifetime,
|
||||
'path' => '/',
|
||||
'domain' => $this->cookieDomain,
|
||||
'httponly' => true,
|
||||
'secure' => true,
|
||||
'samesite' => 'Strict'
|
||||
]);
|
||||
session_start();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if(!isset($_SESSION['csrf']) || !preg_match('/^[0-9a-f]{64}$/', $_SESSION['csrf'])) {
|
||||
$_SESSION['csrf'] = bin2hex(random_bytes(32));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,133 @@
|
|||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Mcp\Opensim;
|
||||
|
||||
use XMLReader;
|
||||
|
||||
class RestConsole
|
||||
{
|
||||
private string $baseUrl;
|
||||
private ?string $sessionId;
|
||||
|
||||
public function __construct(string $host, int $port)
|
||||
{
|
||||
$this->baseUrl = "http://".$host.':'.$port;
|
||||
}
|
||||
|
||||
public function startSession(string $username, string $password): bool
|
||||
{
|
||||
$response = $this->sendRequest('/StartSession/', [
|
||||
'USER' => $username,
|
||||
'PASS' => $password
|
||||
]);
|
||||
|
||||
if ($this->detectError($response, '/StartSession/')) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$this->sessionId = $response['SessionID'];
|
||||
$this->readResponses();
|
||||
return true;
|
||||
}
|
||||
|
||||
public function closeSession(): void
|
||||
{
|
||||
$response = $this->sendRequest('/CloseSession/', [
|
||||
'ID' => $this->sessionId
|
||||
]);
|
||||
|
||||
$this->detectError($response, '/CloseSession/');
|
||||
}
|
||||
|
||||
public function readResponses(): array
|
||||
{
|
||||
if ($this->sessionId == null) {
|
||||
return array();
|
||||
}
|
||||
|
||||
$response = $this->sendRequest('/ReadResponses/'.$this->sessionId);
|
||||
if ($this->detectError($response, '/ReadResponses/')) {
|
||||
return array();
|
||||
}
|
||||
|
||||
return $response['Line'];
|
||||
}
|
||||
|
||||
public function sendCommand(string $command): bool
|
||||
{
|
||||
$response = $this->sendRequest('/SessionCommand/', [
|
||||
'ID' => $this->sessionId,
|
||||
'COMMAND' => $command
|
||||
]);
|
||||
|
||||
if ($this->detectError($response, '/SessionCommand/')) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $response['Result'] == 'OK';
|
||||
}
|
||||
|
||||
private function detectError(array|int $response, string $request): bool
|
||||
{
|
||||
if (gettype($response) == 'integer') {
|
||||
error_log('OS RestConsole request '.$this->baseUrl.$request.' failed, status: '.$response);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private function sendRequest(string $request, array $data = array()): array|int
|
||||
{
|
||||
$curl = curl_init($this->baseUrl.$request);
|
||||
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
|
||||
curl_setopt($curl, CURLOPT_POST, true);
|
||||
curl_setopt($curl, CURLOPT_USERAGENT, 'mcp-restconsole/0.0.1');
|
||||
curl_setopt($curl, CURLOPT_HTTPHEADER, [
|
||||
'Accept' => 'text/xml'
|
||||
]);
|
||||
|
||||
$postData = '';
|
||||
foreach ($data as $key => $val) {
|
||||
$postData = $postData.(strlen($postData) > 0 ? '&' : '').$key.'='.$val;
|
||||
}
|
||||
curl_setopt($curl, CURLOPT_POSTFIELDS, $postData);
|
||||
|
||||
$res = curl_exec($curl);
|
||||
$status = curl_getinfo($curl, CURLINFO_HTTP_CODE);
|
||||
if ($status != 200) {
|
||||
return $status;
|
||||
}
|
||||
|
||||
|
||||
return $this->parseXml($res);
|
||||
}
|
||||
|
||||
private function parseXml(string $response): array
|
||||
{
|
||||
$xmlReader = XMLReader::XML($response, "UTF-8");
|
||||
$res = array();
|
||||
if ($xmlReader->next()) {
|
||||
$consoleSession = $xmlReader->expand();
|
||||
if ($consoleSession->nodeName == 'ConsoleSession') {
|
||||
foreach ($consoleSession->childNodes as $childNode) {
|
||||
$name = $childNode->nodeName;
|
||||
if (isset($res[$name])) {
|
||||
if (gettype($res[$name]) == 'string') {
|
||||
$res[$name] = array($res[$name], $childNode->nodeValue);
|
||||
}
|
||||
else {
|
||||
$res[$name][] = $childNode->nodeValue;
|
||||
}
|
||||
}
|
||||
else {
|
||||
$res[$name] = $childNode->nodeValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $res;
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Mcp\Page;
|
||||
|
||||
use Mcp\Util\Util;
|
||||
|
||||
class Error extends \Mcp\RequestHandler
|
||||
{
|
||||
public function get(): void
|
||||
{
|
||||
http_response_code(404);
|
||||
Util::displayError($this->app, 'Die gewünschte Seite wurde nicht gefunden.');
|
||||
}
|
||||
}
|
|
@ -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 über unseren Discord-Server 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 mcp_password_reset 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 mcp_password_reset(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'], intval($smtp['port']), $smtp['address'], $smtp['password']))->sendHtml($smtp['address'], $smtp['name'], $email, 'Zurücksetzung des Passworts für '.$name, $tplMail);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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');
|
||||
}
|
||||
}
|
|
@ -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');
|
||||
}
|
||||
}
|
|
@ -0,0 +1,150 @@
|
|||
<?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 mcp_user_identities WHERE PrincipalID = ? LIMIT 1");
|
||||
$statementCheckForEntry->execute(array($_SESSION['UUID']));
|
||||
|
||||
if ($statementCheckForEntry->rowCount() == 0) {
|
||||
$statement = $this->app->db()->prepare('INSERT INTO `mcp_user_identities` (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 mcp_user_identities WHERE PrincipalID = ? ORDER BY IdentityID ASC");
|
||||
$statement->execute(array($_SESSION['UUID']));
|
||||
|
||||
$opensim = new OpenSim($this->app->db());
|
||||
|
||||
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 data-uuid="'.htmlspecialchars($row['IdentityID']).'"><button name="enableIdent" class="btn btn-success btn-sm" data-toggle="modal" data-target="#isc">Aktivieren</button> <button type="submit" name="deleteIdent" class="btn btn-danger btn-sm" data-toggle="modal" data-target="#idc">Löschen</button></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'],
|
||||
'activeIdent' => $_SESSION['FIRSTNAME'].' '.$_SESSION['LASTNAME'],
|
||||
'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 mcp_user_identities 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 mcp_user_identities 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]);
|
||||
|
||||
$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" => ""]);
|
||||
|
||||
$statementUserIdentitys = $this->app->db()->prepare('INSERT INTO mcp_user_identities (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');
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,112 @@
|
|||
<?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 mcp_user_identities JOIN UserAccounts ON UserAccounts.PrincipalID = mcp_user_identities.IdentityID WHERE mcp_user_identities.PrincipalID = ? AND mcp_user_identities.PrincipalID != mcp_user_identities.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')->vars([
|
||||
'title' => 'Benutzer',
|
||||
'username' => $_SESSION['DISPLAYNAME']
|
||||
])->unsafeVar('user-list', $table.'</tbody></table>');
|
||||
|
||||
if (isset($_SESSION['users-message'])) {
|
||||
$tpl->unsafeVar('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 `mcp_invites` (`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 mcp_password_reset(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');
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,260 @@
|
|||
<?php
|
||||
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)
|
||||
{
|
||||
parent::__construct($app, new LoginRequiredMiddleware($app, $app->config('domain')));
|
||||
}
|
||||
|
||||
public function get(): void
|
||||
{
|
||||
$tpl = $this->app->template('profile.php')->parent('__dashboard.php');
|
||||
|
||||
//Prüfe ob IAR grade erstellt wird.
|
||||
$iarRunning = false;
|
||||
|
||||
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>');
|
||||
unset($_SESSION['iar_created']);
|
||||
$iarRunning = true;
|
||||
} else {
|
||||
$statementIARCheck = $this->app->db()->prepare('SELECT iarfilename,state,created FROM mcp_iar_state WHERE userID =:userID');
|
||||
$statementIARCheck->execute(['userID' => $_SESSION['UUID']]);
|
||||
if ($row = $statementIARCheck->fetch()) {
|
||||
if ($row['state'] < 2) {
|
||||
$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>');
|
||||
$iarRunning = true;
|
||||
}
|
||||
else {
|
||||
$tpl->unsafeVar('iar-message', '<div class="alert alert-success role="alert">Du kannst dir deine IAR (erstellt am '.date('d.m.Y', $row['created']).') <a href="https://'.$this->app->config('domain').'/index.php?api=downloadIar&id='.substr($row['iarfilename'], 0, strlen($row['iarfilename']) - 4).'">hier</a> herunterladen. Sie ist mit dem Passwort <i>password</i> geschützt.</div>');
|
||||
}
|
||||
}
|
||||
$statementIARCheck->closeCursor();
|
||||
}
|
||||
|
||||
if ($iarRunning) {
|
||||
$tpl->var('iar-button-state', 'disabled');
|
||||
}
|
||||
|
||||
$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'],
|
||||
'username' => $_SESSION['DISPLAYNAME'],
|
||||
'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)) {
|
||||
$validRequest = true;
|
||||
|
||||
$statementIarFile = $this->app->db()->prepare('SELECT iarfilename,state,created FROM mcp_iar_state WHERE userID = ?');
|
||||
$statementIarFile->execute([$_SESSION['UUID']]);
|
||||
if ($row = $statementIarFile->fetch()) {
|
||||
if ($row['state'] == 2) {
|
||||
unlink($this->app->getDataDir().DIRECTORY_SEPARATOR.'iars'.DIRECTORY_SEPARATOR.$row['iarfilename']);
|
||||
}
|
||||
else {
|
||||
$validRequest = false;
|
||||
}
|
||||
}
|
||||
|
||||
if ($validRequest) {
|
||||
$iarname = md5(time().$_SESSION['UUID'] . rand()).".iar";
|
||||
|
||||
$statementIARSTART = $this->app->db()->prepare('INSERT INTO mcp_iar_state (userID, filesize, iarfilename) VALUES (:userID, :filesize, :iarfilename) ON DUPLICATE KEY UPDATE filesize = :replFilesize, state = :replState');
|
||||
$statementIARSTART->execute(['userID' => $_SESSION['UUID'], 'filesize' => 0, 'iarfilename' => $iarname, 'replFilesize' => 0, 'replState' => 0]);
|
||||
|
||||
$_SESSION['iar_created'] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
elseif (isset($_POST['saveProfileData'])) {
|
||||
$validator = new FormValidator(array(
|
||||
'formInputFeldVorname' => array('regex' => '/^[^\\/<>\s]{1,64}$/'),
|
||||
'formInputFeldNachname' => array('regex' => '/^[^\\/<>\s]{1,64}$/'),
|
||||
'formInputFeldEMail' => array('regex' => '/^\S{1,64}@\S{1,250}.\S{2,64}$/'),
|
||||
'formInputFeldOfflineIM' => array('regex' => '/^(|on)$/'),
|
||||
'formInputFeldPartnerName' => array('regex' => '/^[^\\/<>\s]{1,64} [^\\/<>\s]{1,64}$/')
|
||||
));
|
||||
|
||||
if ($validator->isValid($_POST)) {
|
||||
if(isset($_POST['formInputFeldVorname'])) {
|
||||
$newFirstName = trim($_POST['formInputFeldVorname']);
|
||||
|
||||
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']);
|
||||
}
|
||||
else {
|
||||
$_SESSION['profile_info'] = 'Der gewählte Name ist bereits vergeben.';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($_POST['formInputFeldNachname'])) {
|
||||
$newLastName = trim($_POST['formInputFeldNachname']);
|
||||
|
||||
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 {
|
||||
$_SESSION['profile_info'] = 'Der gewählte Name ist bereits vergeben.';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($_POST['formInputFeldEMail'])) {
|
||||
$newEmail = trim($_POST['formInputFeldEMail']);
|
||||
|
||||
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 = $this->app->db()->prepare('UPDATE usersettings SET email = :Email WHERE useruuid = :PrincipalID');
|
||||
$statement->execute(['Email' => $newEmail, 'PrincipalID' => $_SESSION['UUID']]);
|
||||
|
||||
$_SESSION['EMAIL'] = $newEmail;
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($_POST['formInputFeldOfflineIM']) && $_POST['formInputFeldOfflineIM'] == "on") {
|
||||
$statement = $this->app->db()->prepare('UPDATE usersettings SET imviaemail = :IMState WHERE useruuid = :PrincipalID');
|
||||
$statement->execute(['IMState' => 'true', 'PrincipalID' => $_SESSION['UUID']]);
|
||||
} else {
|
||||
$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'] != "") {
|
||||
$opensim = new OpenSim($this->app->db());
|
||||
|
||||
$newPartner = trim($_POST['formInputFeldPartnerName']);
|
||||
$currentPartner = $opensim->getPartner($_SESSION['UUID']);
|
||||
|
||||
if ($currentPartner != "") {
|
||||
$currentPartner = $opensim->getUserName($currentPartner);
|
||||
}
|
||||
|
||||
if ($newPartner != "" && $currentPartner != $newPartner) {
|
||||
$newPartnerUUID = $opensim->getUserUUID($newPartner);
|
||||
|
||||
if ($newPartnerUUID != null) {
|
||||
$statement = $this->app->db()->prepare('UPDATE userprofile SET profilePartner = :profilePartner WHERE useruuid = :PrincipalID');
|
||||
$statement->execute(['profilePartner' => $newPartnerUUID, 'PrincipalID' => $_SESSION['UUID']]);
|
||||
}
|
||||
} else {
|
||||
$statement = $this->app->db()->prepare('UPDATE userprofile SET profilePartner = :profilePartner WHERE useruuid = :PrincipalID');
|
||||
$statement->execute(['profilePartner' => '00000000-0000-0000-0000-000000000000', 'PrincipalID' => $_SESSION['UUID']]);
|
||||
}
|
||||
}
|
||||
}
|
||||
} elseif (isset($_POST['savePassword'])) {
|
||||
$validator = new FormValidator(array(
|
||||
'oldPassword' => array('required' => true, 'regex' => '/^.{1,1000}$/'),
|
||||
'newPassword' => array('required' => true, 'regex' => '/^.{1,1000}$/'),
|
||||
'newPasswordRepeat' => array('required' => true, 'regex' => '/^.{1,1000}$/')
|
||||
));
|
||||
|
||||
if ($validator->isValid($_POST)) {
|
||||
if ($_POST['newPasswordRepeat'] == $_POST['newPassword']) {
|
||||
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 = $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;
|
||||
$_SESSION['profile_info'] = 'Neues Passwort gespeichert.';
|
||||
} else {
|
||||
$_SESSION['profile_info'] = 'Das alte Passwort ist nicht richtig!';
|
||||
}
|
||||
} else {
|
||||
$_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!';
|
||||
}
|
||||
} else {
|
||||
$_SESSION['profile_info'] = 'Bitte fülle das Formular vollständig aus.';
|
||||
}
|
||||
} elseif (isset($_POST['deleteAccount'])) {
|
||||
$validator = new FormValidator(array(
|
||||
'delete-confirm-password' => array('required' => true, 'regex' => '/^.{1,1000}$/'),
|
||||
'delete-confirm' => array('required' => true, 'regex' => '/^(|on)$/')
|
||||
));
|
||||
|
||||
if ($validator->isValid($_POST)) {
|
||||
if (hash_equals(md5(md5($_POST['delete-confirm-password']).':'.$_SESSION['SALT']), $_SESSION['PASSWORD'])) {
|
||||
$os = new OpenSim($this->app->db());
|
||||
if ($os->deleteUser($_SESSION['UUID'])) {
|
||||
$_SESSION['LOGIN'] = false;
|
||||
session_destroy();
|
||||
header('Location: index.php');
|
||||
die();
|
||||
} else {
|
||||
$_SESSION['profile_info'] = 'Bei der Accountlöschung ist ein Fehler aufgetreten. Bitte versuche es später erneut.';
|
||||
}
|
||||
}
|
||||
else {
|
||||
$_SESSION['profile_info'] = 'Zur Bestätigung der Accountlöschung musst du dein Passwort richtig eingeben.';
|
||||
}
|
||||
}
|
||||
else {
|
||||
$_SESSION['profile_info'] = 'Um deinen Account zu löschen, ist dein aktuelles Passwort und die Bestätigung des Vorgangs erforderlich.';
|
||||
}
|
||||
}
|
||||
|
||||
header('Location: index.php?page=profile');
|
||||
}
|
||||
|
||||
private function setNamePart(string $part, string $value, string $otherPart, string $otherValue): bool
|
||||
{
|
||||
$query = $this->app->db()->prepare('SELECT 1 FROM UserAccounts WHERE '.$part.' = ? AND '.$otherPart.' = ?');
|
||||
$query->execute(array($value, $otherValue));
|
||||
|
||||
if ($query->rowCount() == 0) {
|
||||
$statement = $this->app->db()->prepare('UPDATE UserAccounts SET '.$part.' = ? WHERE PrincipalID = ?');
|
||||
$statement->execute(array($value, $_SESSION['UUID']));
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,96 @@
|
|||
<?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
|
||||
{
|
||||
private bool $showAll;
|
||||
|
||||
public function __construct(\Mcp\Mcp $app)
|
||||
{
|
||||
$this->showAll = isset($_GET['SHOWALL']) && $_GET['SHOWALL'] == "1";
|
||||
parent::__construct($app, $this->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>';
|
||||
|
||||
|
||||
$statement = $this->app->db()->prepare("SELECT uuid,regionName,owner_uuid,locX,locY FROM regions ".($this->showAll ? "ORDER BY owner_uuid ASC" : "WHERE owner_uuid = ? ORDER BY uuid ASC"));
|
||||
$statement->execute($this->showAll ? array() : array($_SESSION['UUID']));
|
||||
|
||||
$opensim = new OpenSim($this->app->db());
|
||||
|
||||
$csrf = $this->app->csrfField();
|
||||
$urlShowall = $this->showAll ? '&SHOWALL=1' : '';
|
||||
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'.$urlShowall.'" 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' => $this->showAll ? 'Regionen verwalten' : 'Deine Regionen',
|
||||
'username' => $_SESSION['DISPLAYNAME']
|
||||
])->unsafeVar('child-content', $table.'</tbody></table>')->render();
|
||||
}
|
||||
|
||||
public function post(): void
|
||||
{
|
||||
$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 (isset($_POST['remove']) && $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'.($this->showAll ? '&SHOWALL=1' : ''));
|
||||
}
|
||||
|
||||
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 mcp_regions_info WHERE regionID = ?");
|
||||
$statement->execute([$regionID]);
|
||||
|
||||
if ($row = $statement->fetch()) {
|
||||
$return = array();
|
||||
$return['Prims'] = strval($row['Prims']);
|
||||
$return['SimFPS'] = strval($row['SimFPS']);
|
||||
$return['PhyFPS'] = strval($row['PhyFPS']);
|
||||
$return['ProcMem'] = $this->cleanSize($row['ProcMem']);
|
||||
$return['RegionVersion'] = trim($row['RegionVersion']);
|
||||
|
||||
return $return;
|
||||
}
|
||||
|
||||
return array();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,180 @@
|
|||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Mcp\Page;
|
||||
|
||||
use Mcp\FormValidator;
|
||||
use Mcp\OpenSim;
|
||||
use Mcp\RequestHandler;
|
||||
use Mcp\Middleware\PreSessionMiddleware;
|
||||
|
||||
use Exception;
|
||||
use Mcp\Util\Util;
|
||||
|
||||
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.");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
$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.');
|
||||
return;
|
||||
}
|
||||
|
||||
$email = trim($_POST['email']);
|
||||
|
||||
$avatar = null;
|
||||
if (isset($this->app->config('default-avatar')[$_POST['avatar']])) {
|
||||
$avatar = trim($_POST['avatar']);
|
||||
} else {
|
||||
$this->displayPage("Der gewählte Standardavatar existiert nicht.");
|
||||
return;
|
||||
}
|
||||
|
||||
$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 mcp_invites WHERE InviteCode = :code');
|
||||
$statementInviteDeleter->execute(['code' => $_REQUEST['code']]);
|
||||
if ($statementInviteDeleter->rowCount() == 0) {
|
||||
Util::displayError($this->app, "Der angegebene Einladungscode ist nicht mehr gültig.");
|
||||
return;
|
||||
}
|
||||
|
||||
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.');
|
||||
return;
|
||||
}
|
||||
|
||||
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 checkInvite(): bool
|
||||
{
|
||||
if (!isset($_REQUEST['code'])) {
|
||||
Util::displayError($this->app, "Du benötigst einen Einladungscode, um dich bei 4Creative zu registrieren.");
|
||||
} elseif (strlen($_REQUEST['code']) != 32 || !preg_match('/^[a-f0-9]+$/', $_REQUEST['code'])) {
|
||||
Util::displayError($this->app, "Der angegebene Einladungscode ist nicht gültig. Nutze genau den Link, der dir zugeschickt wurde.");
|
||||
} else {
|
||||
$statementInviteCode = $this->app->db()->prepare("SELECT 1 FROM mcp_invites WHERE InviteCode = ? LIMIT 1");
|
||||
$statementInviteCode->execute([$_REQUEST['code']]);
|
||||
|
||||
if ($statementInviteCode->rowCount() == 0) {
|
||||
Util::displayError($this->app, "Der angegebene Einladungscode ist nicht gültig. Nutze genau den Link, der dir zugeschickt wurde.");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,111 @@
|
|||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Mcp\Page;
|
||||
|
||||
use Mcp\FormValidator;
|
||||
use Mcp\Middleware\PreSessionMiddleware;
|
||||
use Mcp\Util\SmtpClient;
|
||||
use Mcp\Util\Util;
|
||||
|
||||
class ResetPassword 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 über unseren Discord-Server 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 mcp_password_reset JOIN UserAccounts ON UserAccounts.PrincipalID = mcp_password_reset.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 mcp_password_reset 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'], intval($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',
|
||||
'error-message' => $message
|
||||
])->render();
|
||||
}
|
||||
|
||||
private function displayPage(string $message = ''): void
|
||||
{
|
||||
if (!isset($_GET['token']) || !preg_match('/^[a-z0-9A-Z]{32}$/', $_GET['token'])) {
|
||||
$this->displayTokenError($this::TOKEN_INVALID);
|
||||
return;
|
||||
}
|
||||
|
||||
$this->app->template('reset-password.php')->parent('__presession.php')->vars([
|
||||
'title' => 'Neues Passwort festlegen',
|
||||
'message' => $message,
|
||||
'reset-token' => $_GET['token']
|
||||
])->render();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Mcp\Util;
|
||||
|
||||
class DiscordUtil
|
||||
{
|
||||
public static function sendMessageToWebhook($webhook, $title, $message): void
|
||||
{
|
||||
$rawMessage = file_get_contents("data/discordMessage.json");
|
||||
$rawMessage = str_replace("%%message%%", $message, $rawMessage);
|
||||
$rawMessage = str_replace("%%title%%", $title, $rawMessage);
|
||||
|
||||
$options = [
|
||||
'http' => [
|
||||
'method' => 'POST',
|
||||
'header' => 'Content-Type: application/json',
|
||||
'timeout' => 3,
|
||||
'content' => $rawMessage
|
||||
]
|
||||
];
|
||||
|
||||
file_get_contents($webhook, false, stream_context_create($options));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,63 @@
|
|||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Mcp\Util;
|
||||
|
||||
use PHPMailer\PHPMailer\PHPMailer;
|
||||
use Exception;
|
||||
use Mcp\TemplateBuilder;
|
||||
|
||||
class SmtpClient
|
||||
{
|
||||
|
||||
private PHPMailer $mailer;
|
||||
|
||||
public function __construct(string $host, int $port, string $username, string $password)
|
||||
{
|
||||
$mailer = new PHPMailer(true);
|
||||
$mailer->isSMTP();
|
||||
$mailer->CharSet = 'UTF-8';
|
||||
$mailer->Host = $host;
|
||||
$mailer->Port = $port;
|
||||
$mailer->Username = $username;
|
||||
$mailer->Password = $password;
|
||||
$mailer->SMTPAuth = true;
|
||||
$mailer->SMTPSecure = $port == 465 ? PHPMailer::ENCRYPTION_SMTPS : PHPMailer::ENCRYPTION_STARTTLS;
|
||||
$this->mailer = $mailer;
|
||||
}
|
||||
|
||||
public function sendHtml(string $fromAddr, string $fromName, string $to, string $subject, TemplateBuilder $tpl): bool
|
||||
{
|
||||
try {
|
||||
$this->mailer->setFrom($fromAddr, $fromName);
|
||||
$this->mailer->addAddress($to);
|
||||
} catch (Exception $e) {
|
||||
error_log('Failed to prepare mail client (from: '.$fromAddr.', to: '.$to.')');
|
||||
return false;
|
||||
}
|
||||
|
||||
$this->mailer->isHTML(true);
|
||||
$this->mailer->Subject = $subject;
|
||||
ob_start();
|
||||
$tpl->render();
|
||||
$tplOut = ob_get_flush();
|
||||
$this->mailer->Body = $tplOut;
|
||||
$this->mailer->AltBody = $this::htmlToPlain($tplOut);
|
||||
|
||||
try {
|
||||
$this->mailer->send();
|
||||
return true;
|
||||
} catch (Exception $e) {
|
||||
error_log('Could not send email: '.$this->mailer->ErrorInfo);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private static function htmlToPlain($message): string
|
||||
{
|
||||
$messageNew = str_replace('<br/>', "\n", $message);
|
||||
$messageNew = strip_tags(preg_replace('/<a href="(.*)">(.*)<\\/a>/', "$2: $1", $messageNew));
|
||||
return $messageNew;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,39 @@
|
|||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Mcp\Util;
|
||||
|
||||
/**
|
||||
* This class can be used like a regular array, but is guaranteed to return a value.
|
||||
* Keys not set in the underlying array return an empty string.
|
||||
*/
|
||||
class TemplateVarArray implements \ArrayAccess
|
||||
{
|
||||
|
||||
private array $vars;
|
||||
|
||||
public function __construct(array $vars)
|
||||
{
|
||||
$this->vars = $vars;
|
||||
}
|
||||
|
||||
public function offsetExists(mixed $offset): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public function offsetGet(mixed $offset): mixed
|
||||
{
|
||||
return isset($this->vars[$offset]) ? $this->vars[$offset] : '';
|
||||
}
|
||||
|
||||
public function offsetSet(mixed $offset, mixed $value): void
|
||||
{
|
||||
$this->vars[$offset] = $value;
|
||||
}
|
||||
|
||||
public function offsetUnset(mixed $offset): void
|
||||
{
|
||||
unset($this->vars[$offset]);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,74 @@
|
|||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Mcp\Util;
|
||||
|
||||
use Exception;
|
||||
|
||||
class Util
|
||||
{
|
||||
public static function fillString($string, $targetlength)
|
||||
{
|
||||
if (gettype($string) != 'string') {
|
||||
$string = strval($string);
|
||||
}
|
||||
|
||||
while(strlen($string) < $targetlength)
|
||||
{
|
||||
$string = "0".$string;
|
||||
}
|
||||
|
||||
return $string;
|
||||
}
|
||||
|
||||
public static function left($str, $length)
|
||||
{
|
||||
return substr($str, 0, $length);
|
||||
}
|
||||
|
||||
public static function right($str, $length)
|
||||
{
|
||||
return substr($str, -$length);
|
||||
}
|
||||
|
||||
public static function generateToken($length): string
|
||||
{
|
||||
$chars = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
||||
$res = "";
|
||||
for($i = 0; $i < $length; $i++) {
|
||||
$index = random_int(0, strlen($chars) - 1);
|
||||
$res = $res.substr($chars, $index, 1);
|
||||
}
|
||||
return $res;
|
||||
}
|
||||
|
||||
public static function getDataFromHTTP($url, $content = "", $requestType = "application/text")
|
||||
{
|
||||
$curl = curl_init($url);
|
||||
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
|
||||
curl_setopt($curl, CURLOPT_TIMEOUT, 1);
|
||||
if ($content != "") {
|
||||
curl_setopt($curl, CURLOPT_POST, true);
|
||||
curl_setopt($curl, CURLOPT_POSTFIELDS, $content);
|
||||
curl_setopt($curl, CURLOPT_USERAGENT, 'mcp/0.0.1');
|
||||
curl_setopt($curl, CURLOPT_HTTPHEADER, [
|
||||
'Content-Type' => $requestType
|
||||
]);
|
||||
}
|
||||
return curl_exec($curl);
|
||||
}
|
||||
|
||||
public static function sendInworldIM($fromUUID, $toUUID, $fromName, $targetURL, $text)
|
||||
{
|
||||
$rawXML = "<?xml version=\"1.0\" encoding=\"utf-8\"?><methodCall><methodName>grid_instant_message</methodName><params><param><value><struct><member><name>position_x</name><value><string>0</string></value></member><member><name>position_y</name><value><string>0</string></value></member><member><name>position_z</name><value><string>0</string></value></member><member><name>to_agent_id</name><value><string>".$toUUID."</string></value></member><member><name>from_agent_session</name><value><string>00000000-0000-0000-0000-000000000000</string></value></member><member><name>im_session_id</name><value><string>".$fromUUID."</string></value></member><member><name>from_agent_name</name><value><string>".$fromName."</string></value></member><member><name>from_agent_id</name><value><string>".$fromUUID."</string></value></member><member><name>binary_bucket</name><value><string>AA==</string></value></member><member><name>region_handle</name><value><i4>0</i4></value></member><member><name>region_id</name><value><string>00000000-0000-0000-0000-000000000000</string></value></member><member><name>parent_estate_id</name><value><string>1</string></value></member><member><name>timestamp</name><value><string>".time()."</string></value></member><member><name>dialog</name><value><string>AA==</string></value></member><member><name>offline</name><value><string>AA==</string></value></member><member><name>from_group</name><value><string>FALSE</string></value></member><member><name>message</name><value><string>".$text."</string></value></member></struct></value></param></params></methodCall>";
|
||||
Util::getDataFromHTTP($targetURL, $rawXML, "text/xml");
|
||||
}
|
||||
|
||||
public static function displayError($app, $message): void
|
||||
{
|
||||
$app->template('error.php')->parent('__presession.php')->vars([
|
||||
'title' => 'Fehler',
|
||||
'error-message' => $message
|
||||
])->render();
|
||||
}
|
||||
}
|
101
app/utils.php
101
app/utils.php
|
@ -1,101 +0,0 @@
|
|||
<?php
|
||||
use PHPMailer\PHPMailer\Exception;
|
||||
use PHPMailer\PHPMailer\PHPMailer;
|
||||
|
||||
function fillString($string, $targetlength)
|
||||
{
|
||||
while(strlen($string) < $targetlength)
|
||||
{
|
||||
$string = "0".$string;
|
||||
}
|
||||
|
||||
return $string;
|
||||
}
|
||||
|
||||
function left($str, $length)
|
||||
{
|
||||
return substr($str, 0, $length);
|
||||
}
|
||||
|
||||
function right($str, $length)
|
||||
{
|
||||
return substr($str, -$length);
|
||||
}
|
||||
|
||||
function generateToken($length): string {
|
||||
$chars = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
||||
$res = "";
|
||||
for($i = 0; $i < $length; $i++) {
|
||||
$index = random_int(0, strlen($chars) - 1);
|
||||
$res = $res.substr($chars, $index, 1);
|
||||
}
|
||||
return $res;
|
||||
}
|
||||
|
||||
function htmlToPlain($message): string {
|
||||
$messageNew = str_replace('<br/>', "\n", $message);
|
||||
$messageNew = preg_replace('/<a href="(.*)">(.*)<\\/a>/', "$2: $1", $messageNew);
|
||||
return $messageNew;
|
||||
}
|
||||
|
||||
function sendMail($email, $message, $subject, $title, $preheader): bool {
|
||||
include_once('lib/phpmailer/Exception.php');
|
||||
include_once('lib/phpmailer/PHPMailer.php');
|
||||
include_once('lib/phpmailer/SMTP.php');
|
||||
include_once('app/HTML.php');
|
||||
global $RUNTIME;
|
||||
|
||||
$mailer = new PHPMailer(true);
|
||||
|
||||
try {
|
||||
$mailer->isSMTP();
|
||||
$mailer->Host = $RUNTIME['SMTP']['SERVER'];
|
||||
$mailer->Port = $RUNTIME['SMTP']['PORT'];
|
||||
$mailer->Username = $RUNTIME['SMTP']['ADDRESS'];
|
||||
$mailer->Password = $RUNTIME['SMTP']['PASS'];
|
||||
$mailer->SMTPAuth = true;
|
||||
$mailer->SMTPSecure = PHPMailer::ENCRYPTION_SMTPS;
|
||||
|
||||
$mailer->setFrom($RUNTIME['SMTP']['ADDRESS'], $RUNTIME['SMTP']['NAME']);
|
||||
$mailer->addAddress($email);
|
||||
|
||||
$mailer->isHTML(true);
|
||||
$mailer->Subject = $subject;
|
||||
$mailHtml = new HTML();
|
||||
$mailHtml->importHTML("mail.html");
|
||||
$mailHtml->setHTMLTitle($title);
|
||||
$mailHtml->ReplaceLayoutInhalt('%%MESSAGE%%', $message);
|
||||
$mailHtml->ReplaceLayoutInhalt('%%PREHEADER%%', $preheader);
|
||||
$mailHtml->build();
|
||||
$mailer->Body = $mailHtml->ausgabe();
|
||||
$mailer->AltBody = htmlToPlain($message);
|
||||
|
||||
$mailer->send();
|
||||
return true;
|
||||
} catch(Exception $e) {
|
||||
error_log('Could not send email: '.$mailer->ErrorInfo);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function getDataFromHTTP($URL, $contend = "", $requestTyp = "application/text")
|
||||
{
|
||||
try
|
||||
{
|
||||
if($contend != "")
|
||||
{
|
||||
return file_get_contents($URL, true, stream_context_create(array('http' => array('header' => 'Content-type: '.$requestTyp, 'method' => 'POST', 'timeout' => 0.5, 'content' => $contend))));
|
||||
}else{
|
||||
return file_get_contents($URL);
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
echo "(HTTP REQUEST) error while conntect to remote server. : ".$URL;
|
||||
}
|
||||
}
|
||||
|
||||
function sendInworldIM($fromUUID, $toUUID, $fromName, $targetURL, $text)
|
||||
{
|
||||
$rawXML = "<?xml version=\"1.0\" encoding=\"utf-8\"?><methodCall><methodName>grid_instant_message</methodName><params><param><value><struct><member><name>position_x</name><value><string>0</string></value></member><member><name>position_y</name><value><string>0</string></value></member><member><name>position_z</name><value><string>0</string></value></member><member><name>to_agent_id</name><value><string>".$toUUID."</string></value></member><member><name>from_agent_session</name><value><string>00000000-0000-0000-0000-000000000000</string></value></member><member><name>im_session_id</name><value><string>".$fromUUID."</string></value></member><member><name>from_agent_name</name><value><string>".$fromName."</string></value></member><member><name>from_agent_id</name><value><string>".$fromUUID."</string></value></member><member><name>binary_bucket</name><value><string>AA==</string></value></member><member><name>region_handle</name><value><i4>0</i4></value></member><member><name>region_id</name><value><string>00000000-0000-0000-0000-000000000000</string></value></member><member><name>parent_estate_id</name><value><string>1</string></value></member><member><name>timestamp</name><value><string>".time()."</string></value></member><member><name>dialog</name><value><string>AA==</string></value></member><member><name>offline</name><value><string>AA==</string></value></member><member><name>from_group</name><value><string>FALSE</string></value></member><member><name>message</name><value><string>".$text."</string></value></member></struct></value></param></params></methodCall>";
|
||||
getDataFromHTTP($targetURL, $rawXML, "text/xml");
|
||||
}
|
||||
?>
|
|
@ -0,0 +1,48 @@
|
|||
[general]
|
||||
; Domain, unter der das MCP erreichbar ist
|
||||
domain = example.com
|
||||
; Mindestlänge des Passworts, wird bei Registrierung und Änderung überprüft
|
||||
password-min-length = 8
|
||||
; URL der Nutzungsbedingungen des Grids
|
||||
tos-url = https://example.com/tos.html
|
||||
; Name und UUID eines oder mehrerer Standardavatare
|
||||
default-avatar[Twinster Kid] = 0817c915-293a-4041-b5a4-c7c53666bcc6
|
||||
; Liste von Domains, deren E-Mail-Adressen als nicht für Password-Reset-Mails nutzbar zu behandeln sind
|
||||
reset-blocked-domains[] = example.com
|
||||
reset-blocked-domains[] = invalid.net
|
||||
; Art der Einschränkung des Aufrufs von Cronjobs: key (API-Key benötigt) oder none (keine Einschränkung)
|
||||
cron-restriction = key
|
||||
; API-Key, der zum erfolgreichen Aufruf von Cronjobs übermittelt werden muss.
|
||||
cron-key = changeme
|
||||
|
||||
; Host, Name und Zugangsdaten zur MySQL-Datenbank. Muss mit der Datenbank der Robust-Instanz übereinstimmen.
|
||||
[mysql]
|
||||
host = localhost
|
||||
db = Robust
|
||||
user = OpenSim
|
||||
password = secret
|
||||
|
||||
; Zugangsdaten zum Mailserver
|
||||
[smtp]
|
||||
host = smtp.example.com
|
||||
port = 465
|
||||
address = noreply@example.com
|
||||
; Name, der neben der Absenderadresse stehen soll
|
||||
name = MyGrid Support
|
||||
password = secret
|
||||
|
||||
; Daten des Grids, die u.a. auf der Welcome-Page angezeigt werden
|
||||
[grid]
|
||||
name = OpenSim
|
||||
main-news = Yet another OpenSim Grid.
|
||||
homeurl = http://...:8002
|
||||
|
||||
; Benötigt für die Anforderung von IARs
|
||||
[iarfetcher]
|
||||
; Zugangsdaten der REST-Konsole von OpenSimulator
|
||||
host = example.com
|
||||
port = 9001 ; Einstellung console_port
|
||||
user = mcp
|
||||
password = secret
|
||||
; IAR-Verzeichnis aus Sicht der OpenSimulator-Instanz
|
||||
os-iar-path = /opt/opensim/iars/
|
|
@ -1,27 +0,0 @@
|
|||
<?php
|
||||
$RUNTIME['PDO'] = new PDO('mysql:host=...;dbname=...', '...', '...');
|
||||
|
||||
$RUNTIME['GRID']['NAME'] = "OpenSim";
|
||||
$RUNTIME['GRID']['MAIN_NEWS'] = "Yet an other OpenSim Grid.";
|
||||
$RUNTIME['GRID']['HOMEURL'] = "http://...:8002";
|
||||
|
||||
$RUNTIME['SMTP']['SERVER'] = "localhost";
|
||||
$RUNTIME['SMTP']['PORT'] = 25;
|
||||
$RUNTIME['SMTP']['ADDRESS'] = "noreply@localhost";
|
||||
$RUNTIME['SMTP']['NAME'] = "4Creative";
|
||||
$RUNTIME['SMTP']['PASS'] = "...";
|
||||
|
||||
$RUNTIME['TOOLS']['IMAGESERVICE'] = "https://image-service.4creative.net/";
|
||||
$RUNTIME['TOOLS']['TOS'] = "https://4creative.net/nutzung.html";
|
||||
|
||||
$RUNTIME['DEFAULTAVATAR']["AVATAR1"]['UUID'] = "0817c915-293a-4041-b5a4-c7c53666bcc6";
|
||||
|
||||
$RUNTIME['SIDOMAN']['URL'] = "https://sidoman.4creative.net/";
|
||||
$RUNTIME['SIDOMAN']['CONTAINER'] = "...";
|
||||
$RUNTIME['SIDOMAN']['PASSWORD'] = "...";
|
||||
|
||||
$RUNTIME['DOMAIN'] = "mcp.4creative.net";
|
||||
$RUNTIME['IAR']['BASEURL'] = "https://mcp.4creative.net/data/";
|
||||
|
||||
$RUNTIME['PASSWORD_MIN_LENGTH'] = 8;
|
||||
?>
|
|
@ -1,64 +0,0 @@
|
|||
<?php
|
||||
include 'app/OpenSim.php';
|
||||
$opensim = new OpenSim();
|
||||
|
||||
$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();
|
||||
|
||||
$statement = $RUNTIME['PDO']->prepare("SELECT userID,iarfilename,filesize FROM iarstates WHERE running = 1 LIMIT 1");
|
||||
$statement->execute();
|
||||
|
||||
if($row = $statement->fetch())
|
||||
{
|
||||
$email = $opensim->getUserMail($row['userID']);
|
||||
|
||||
$fullFilePath = "/var/www/html/data/".$row['iarfilename'];
|
||||
|
||||
echo "Aktive IAR für ".$opensim->getUserName($row['userID'])." gefunden. File: ".$fullFilePath."\n";
|
||||
|
||||
if(file_exists($fullFilePath))
|
||||
{
|
||||
$filesize = filesize($fullFilePath);
|
||||
|
||||
if($filesize != $row['filesize'])
|
||||
{
|
||||
$statementUpdate = $RUNTIME['PDO']->prepare('UPDATE iarstates SET filesize = :filesize WHERE userID = :userID');
|
||||
$statementUpdate->execute(['filesize' => $filesize, 'userID' => $row['userID']]);
|
||||
|
||||
echo "Status der IAR für ".$opensim->getUserName($row['userID']).": Speichert...\n";
|
||||
}else{
|
||||
$APIURL = $RUNTIME['SIDOMAN']['URL']."api.php?CONTAINER=".$RUNTIME['SIDOMAN']['CONTAINER']."&KEY=".$RUNTIME['SIDOMAN']['PASSWORD']."&METODE=RESTART";
|
||||
$APIResult = file_get_contents($APIURL);
|
||||
echo "Status der IAR für ".$opensim->getUserName($row['userID']).": Sende Mail...\n";
|
||||
$statementUpdate = $RUNTIME['PDO']->prepare('DELETE FROM iarstates WHERE userID = :userID');
|
||||
$statementUpdate->execute(['userID' => $row['userID']]);
|
||||
|
||||
sendInworldIM("00000000-0000-0000-0000-000000000000", $row['userID'], "Inventory", $RUNTIME['GRID']['HOMEURL'], "Deine IAR ist fertig zum Download: ".$RUNTIME['IAR']['BASEURL'].$row['iarfilename']);
|
||||
}
|
||||
}else{
|
||||
$name = explode(" ", $opensim->getUserName($row['userID']));
|
||||
|
||||
$APIURL = $RUNTIME['SIDOMAN']['URL']."api.php?CONTAINER=".$RUNTIME['SIDOMAN']['CONTAINER']."&KEY=".$RUNTIME['SIDOMAN']['PASSWORD']."&METODE=COMMAND&COMMAND=".urlencode("save iar ".$name[0]." ".$name[1]." /* PASSWORD /downloads/".$row['iarfilename']);
|
||||
$APIResult = file_get_contents($APIURL);
|
||||
|
||||
echo "IAR für ".$name[0]." ".$name[1]." wurde gestartet: Status: ".$APIResult."\n";
|
||||
}
|
||||
}else{
|
||||
$statement = $RUNTIME['PDO']->prepare("SELECT userID,iarfilename FROM iarstates WHERE running = 0 LIMIT 1");
|
||||
$statement->execute();
|
||||
|
||||
while($row = $statement->fetch())
|
||||
{
|
||||
$statementUpdate = $RUNTIME['PDO']->prepare('UPDATE iarstates SET running = :running WHERE userID = :userID');
|
||||
$statementUpdate->execute(['running' => 1, 'userID' => $row['userID']]);
|
||||
|
||||
$name = explode(" ", $opensim->getUserName($row['userID']));
|
||||
|
||||
$APIURL = $RUNTIME['SIDOMAN']['URL']."api.php?CONTAINER=".$RUNTIME['SIDOMAN']['CONTAINER']."&KEY=".$RUNTIME['SIDOMAN']['PASSWORD']."&METODE=COMMAND&COMMAND=".urlencode("save iar ".$name[0]." ".$name[1]." /* PASSWORD /downloads/".$row['iarfilename']);
|
||||
$APIResult = file_get_contents($APIURL);
|
||||
|
||||
echo "IAR für ".$name[0]." ".$name[1]." wurde gestartet: Status: ".$APIResult."\n";
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
|
@ -1,40 +0,0 @@
|
|||
<?php
|
||||
$statement = $RUNTIME['PDO']->prepare("SELECT id,hash FROM fsassets ORDER BY create_time DESC");
|
||||
$statement->execute();
|
||||
|
||||
$count = 0;
|
||||
|
||||
while($row = $statement->fetch())
|
||||
{
|
||||
$fileNameParts = array();
|
||||
$fileNameParts[0] = substr($row['hash'], 0, 2);
|
||||
$fileNameParts[1] = substr($row['hash'], 2, 2);
|
||||
$fileNameParts[2] = substr($row['hash'], 4, 2);
|
||||
$fileNameParts[3] = substr($row['hash'], 6, 4);
|
||||
$fileNameParts[4] = $row['hash'].".gz";
|
||||
|
||||
//$fileNameParts['Time'] = time();
|
||||
$fileNameParts['UUID'] = $row['id'];
|
||||
$fileNameParts['FilePath'] = "/data/assets/base/".$fileNameParts[0]."/".$fileNameParts[1]."/".$fileNameParts[2]."/".$fileNameParts[3]."/".$fileNameParts[4];
|
||||
|
||||
if(file_exists($fileNameParts['FilePath'])) {
|
||||
$filesize = filesize($fileNameParts['FilePath']);
|
||||
if($filesize === false) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else {
|
||||
$filesize = 0;
|
||||
}
|
||||
|
||||
$fileNameParts['FileSize'] = $filesize;
|
||||
$fileNameParts['Count'] = $count++;
|
||||
|
||||
if($fileNameParts['FileSize'] == 0)
|
||||
{
|
||||
$add = $RUNTIME['PDO']->prepare('DELETE FROM fsassets WHERE hash = :fileHash');
|
||||
$add->execute(['fileHash' => $row['hash']]);
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
|
@ -1,21 +0,0 @@
|
|||
<?php
|
||||
$InventarCheckStatement = $RUNTIME['PDO']->prepare("UPDATE inventoryitems i SET
|
||||
i.inventoryName = concat('[DEFEKT] ', i.inventoryName)
|
||||
WHERE
|
||||
i.assetID IN (
|
||||
SELECT
|
||||
i.assetID
|
||||
FROM inventoryitems i
|
||||
WHERE
|
||||
NOT EXISTS( SELECT *
|
||||
FROM fsassets fs
|
||||
WHERE
|
||||
fs.id = i.assetID
|
||||
)
|
||||
AND NOT i.inventoryName LIKE '[DEFEKT] %'
|
||||
AND i.assetType <> 24
|
||||
)");
|
||||
|
||||
$InventarCheckStatement->execute();
|
||||
|
||||
?>
|
|
@ -1,108 +0,0 @@
|
|||
<?php
|
||||
use PHPMailer\PHPMailer\PHPMailer;
|
||||
use PHPMailer\PHPMailer\SMTP;
|
||||
|
||||
include_once('lib/phpmailer/Exception.php');
|
||||
include_once('lib/phpmailer/PHPMailer.php');
|
||||
include_once('lib/phpmailer/SMTP.php');
|
||||
|
||||
$statement = $RUNTIME['PDO']->prepare("CREATE TABLE IF NOT EXISTS im_offline_send (`id` int(6) NOT NULL DEFAULT 0) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci");
|
||||
$statement->execute();
|
||||
|
||||
function isMailAllreadySend($id)
|
||||
{
|
||||
GLOBAL $RUNTIME;
|
||||
|
||||
$statement = $RUNTIME['PDO']->prepare("SELECT 1 FROM im_offline_send WHERE id = ? LIMIT 1");
|
||||
$statement->execute(array($id));
|
||||
|
||||
if($statement->rowCount() != 0)
|
||||
return TRUE;
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
$IMTYP = array(
|
||||
"0" => "eine Nachricht",
|
||||
"3" => "eine Gruppeneinladung",
|
||||
"4" => "ein Inventaritem",
|
||||
"5" => "eine Bestätigung zur Annahme von Inventar",
|
||||
"6" => "eine Information zur Ablehnung von Inventar",
|
||||
"7" => "eine Aufforderung zur Gruppenwahl",
|
||||
"9" => "ein Inventaritem von einem Script",
|
||||
"19" => "eine Nachricht von einem Script",
|
||||
"32" => "eine Gruppennachricht",
|
||||
"38" => "eine Freundschaftsanfrage",
|
||||
"39" => "eine Bestätigung über die Annahme der Freundschaft",
|
||||
"40" => "eine Information über das Ablehnen der Freundschaft"
|
||||
);
|
||||
|
||||
//$statement = $RUNTIME['PDO']->prepare("SELECT * FROM im_offline WHERE PrincipalID = '1148b04d-7a93-49e9-b3c9-ea0cdeec38f7'");
|
||||
$statement = $RUNTIME['PDO']->prepare("SELECT ID,PrincipalID,Message FROM im_offline");
|
||||
$statement->execute();
|
||||
|
||||
while($row = $statement->fetch())
|
||||
{
|
||||
include 'app/OpenSim.php';
|
||||
$opensim = new OpenSim();
|
||||
|
||||
$email = $opensim->getUserMail($row['PrincipalID']);
|
||||
$allowOfflineIM = $opensim->allowOfflineIM($row['PrincipalID']);
|
||||
|
||||
if($email != "" && $allowOfflineIM == "TRUE")
|
||||
{
|
||||
if(isMailAllreadySend($row['ID']) == FALSE)
|
||||
{
|
||||
$statementSend = $RUNTIME['PDO']->prepare('INSERT INTO im_offline_send (id) VALUES (:idnummer)');
|
||||
$statementSend->execute(['idnummer' => $row['ID']]);
|
||||
|
||||
$mail = new PHPMailer(true);
|
||||
|
||||
$mail->SMTPDebug = SMTP::DEBUG_SERVER;
|
||||
$mail->isSMTP();
|
||||
$mail->Host = $RUNTIME['SMTP']['SERVER'];
|
||||
$mail->Port = $RUNTIME['SMTP']['PORT'];
|
||||
$mail->SMTPAuth = false;
|
||||
|
||||
$mail->setFrom($RUNTIME['SMTP']['ADRESS'], $RUNTIME['GRID']['NAME']);
|
||||
$mail->addAddress($email, $opensim->getUserName($row['PrincipalID']));
|
||||
|
||||
$XMLMESSAGE = new SimpleXMLElement($row['Message']);
|
||||
|
||||
$HTMLMESSAGE = "Du hast ".$IMTYP["".$XMLMESSAGE->dialog.""]." in ".$RUNTIME['GRID']['NAME']." bekommen. <br><p><ul><li>".htmlspecialchars($XMLMESSAGE->message)."</li></ul></p>Gesendet von: ";
|
||||
|
||||
if(isset($XMLMESSAGE->fromAgentName))
|
||||
$HTMLMESSAGE .= $XMLMESSAGE->fromAgentName;
|
||||
|
||||
if(isset($XMLMESSAGE->RegionID) && isset($XMLMESSAGE->Position))
|
||||
{
|
||||
if($XMLMESSAGE->Position->X != 0 || $XMLMESSAGE->Position->X != 0 || $XMLMESSAGE->Position->X != 0)
|
||||
{
|
||||
$HTMLMESSAGE .= " @ ".$opensim->getRegionName($XMLMESSAGE->RegionID)."/".$XMLMESSAGE->Position->X."/".$XMLMESSAGE->Position->Y."/".$XMLMESSAGE->Position->Z;
|
||||
}else{
|
||||
$HTMLMESSAGE .= " @ ".$opensim->getRegionName($XMLMESSAGE->RegionID);
|
||||
}
|
||||
}
|
||||
|
||||
//die($HTMLMESSAGE);
|
||||
|
||||
$HTML = new HTML();
|
||||
$HTML->importHTML("mail.html");
|
||||
$HTML->setSeitenInhalt($HTMLMESSAGE);
|
||||
$HTML->build();
|
||||
|
||||
$mail->isHTML(true);
|
||||
$mail->Subject = "Du hast ".$IMTYP["".$XMLMESSAGE->dialog.""]." in ".$RUNTIME['GRID']['NAME'].".";
|
||||
$mail->Body = $HTML->ausgabe();
|
||||
$mail->AltBody = strip_tags($HTMLMESSAGE);
|
||||
|
||||
//print_r($mail);
|
||||
$mail->send();
|
||||
}else{
|
||||
//echo $row['ID']." wurde bereits gesendet.";
|
||||
}
|
||||
}else{
|
||||
//echo $row['PrincipalID']." möchte keine offline IM oder hat keine E-MAIL Adresse hinterlegt.";
|
||||
}
|
||||
}
|
||||
?>
|
|
@ -1,50 +0,0 @@
|
|||
<?php
|
||||
$createStatement = $RUNTIME['PDO']->prepare("CREATE TABLE IF NOT EXISTS `regions_info` (`regionID` VARCHAR(36) NOT NULL COLLATE 'utf8_unicode_ci', `RegionVersion` VARCHAR(128) NOT NULL DEFAULT '' COLLATE 'utf8_unicode_ci', `ProcMem` INT(11) NOT NULL, `Prims` INT(11) NOT NULL, `SimFPS` INT(11) NOT NULL, `PhyFPS` INT(11) NOT NULL, `OfflineTimer` INT(11) NOT NULL DEFAULT '0', PRIMARY KEY (`regionID`) USING BTREE) COLLATE='utf8_unicode_ci' ENGINE=InnoDB;");
|
||||
$createStatement->execute();
|
||||
|
||||
$statement = $RUNTIME['PDO']->prepare("SELECT uuid,regionName,owner_uuid,serverURI FROM regions");
|
||||
$statement->execute();
|
||||
|
||||
ini_set('default_socket_timeout', 3);
|
||||
|
||||
$ctx = stream_context_create(array('http'=>
|
||||
array(
|
||||
'timeout' => 3,
|
||||
)
|
||||
));
|
||||
|
||||
while($row = $statement->fetch())
|
||||
{
|
||||
$result = file_get_contents($row['serverURI']."jsonSimStats", false, $ctx);
|
||||
|
||||
if($result == FALSE || $result == "")
|
||||
{
|
||||
include 'app/OpenSim.php';
|
||||
|
||||
echo "Die Region ".$row['regionName']." von ".$opensim->getUserName($row['owner_uuid'])." ist nicht erreichbar.\n";
|
||||
|
||||
$infoStatement = $RUNTIME['PDO']->prepare("SELECT OfflineTimer FROM regions_info WHERE regionID = :regionID");
|
||||
$infoStatement->execute(['regionID' => $row['uuid']]);
|
||||
|
||||
if($infoRow = $infoStatement->fetch())
|
||||
{
|
||||
if(($infoRow['OfflineTimer'] + 3600) <= time())
|
||||
{
|
||||
echo "Die Region ".$row['regionName']." von ".$opensim->getUserName($row['owner_uuid'])." ist seit über eine Stunde nicht erreichbar!\n";
|
||||
|
||||
//sendInworldIM("00000000-0000-0000-0000-000000000000", $row['owner_uuid'], "Region", $RUNTIME['GRID']['HOMEURL'], "WARNUNG: Deine Region '".$row['regionName']."' ist nicht erreichbar und wurde deshalb aus dem Grid entfernt.");
|
||||
|
||||
//$statementUpdate = $RUNTIME['PDO']->prepare('DELETE FROM regions WHERE uuid = :uuid');
|
||||
//$statementUpdate->execute(['uuid' => $row['uuid']]);
|
||||
}else{
|
||||
//sendInworldIM("00000000-0000-0000-0000-000000000000", $row['owner_uuid'], "Region", $RUNTIME['GRID']['HOMEURL'], "WARNUNG: Deine Region '".$row['regionName']."' ist nicht erreichbar!");
|
||||
}
|
||||
}
|
||||
}else{
|
||||
$regionData = json_decode($result);
|
||||
|
||||
$statementAccounts = $RUNTIME['PDO']->prepare('REPLACE INTO `regions_info` (`regionID`, `RegionVersion`, `ProcMem`, `Prims`, `SimFPS`, `PhyFPS`, `OfflineTimer`) VALUES (:regionID, :RegionVersion, :ProcMem, :Prims, :SimFPS, :PhyFPS, :OfflineTimer)');
|
||||
$statementAccounts->execute(['regionID' => $row['uuid'], 'RegionVersion' => $regionData->Version, 'ProcMem' => $regionData->ProcMem, 'Prims' => $regionData->Prims, 'SimFPS' => $regionData->SimFPS, 'PhyFPS' => $regionData->PhyFPS, 'OfflineTimer' => time()]);
|
||||
}
|
||||
}
|
||||
?>
|
26
crone.php
26
crone.php
|
@ -1,26 +0,0 @@
|
|||
<?php
|
||||
date_default_timezone_set("Europe/Berlin");
|
||||
error_reporting(E_ALL);
|
||||
session_start();
|
||||
|
||||
$RUNTIME = array();
|
||||
$RUNTIME['BASEDIR'] = __DIR__;
|
||||
set_include_path('.:'.$RUNTIME['BASEDIR']);
|
||||
include_once("app/utils.php");
|
||||
include_once("app/HTML.php");
|
||||
include_once("config.php");
|
||||
|
||||
if ($handle = opendir('./cron/'))
|
||||
{
|
||||
while (false !== ($entry = readdir($handle)))
|
||||
{
|
||||
if ($entry != "." && $entry != "..")
|
||||
{
|
||||
include_once "./cron/".$entry;
|
||||
}
|
||||
}
|
||||
|
||||
closedir($handle);
|
||||
}
|
||||
|
||||
?>
|
83
index.php
83
index.php
|
@ -1,83 +0,0 @@
|
|||
<?php
|
||||
date_default_timezone_set("Europe/Berlin");
|
||||
error_reporting(E_ALL);
|
||||
include_once("config.php");
|
||||
$RUNTIME['BASEDIR'] = __DIR__;
|
||||
set_include_path('.:'.$RUNTIME['BASEDIR']);
|
||||
|
||||
session_set_cookie_params([
|
||||
'lifetime' => 86400,
|
||||
'path' => '/',
|
||||
'domain' => $RUNTIME['DOMAIN'],
|
||||
'httponly' => true,
|
||||
'secure' => true,
|
||||
'samesite' => 'Lax'
|
||||
]);
|
||||
|
||||
session_start();
|
||||
if(!isset($_SESSION['csrf']) || strlen($_SESSION['csrf']) != 64) {
|
||||
$_SESSION['csrf'] = bin2hex(random_bytes(32));
|
||||
}
|
||||
|
||||
include_once("app/utils.php");
|
||||
include_once("app/HTML.php");
|
||||
|
||||
function isValidEndpoint(string $pageName, string $dirPrefix) {
|
||||
return preg_match('/^[a-zA-Z0-9\.]{1,100}$/', $pageName) && file_exists("./".$dirPrefix."/".$pageName.".php");
|
||||
}
|
||||
|
||||
function needsLogin(?string $pageName) {
|
||||
return $pageName != 'register' && $pageName != 'forgot' && $pageName != 'reset-password' && $pageName != 'login';
|
||||
}
|
||||
|
||||
//TODO: add API keys and/or rate limiting
|
||||
if(isset($_GET['api'])) {
|
||||
if(isValidEndpoint($_GET['api'], 'api')) {
|
||||
include "./api/".$_GET['api'].".php";
|
||||
} else {
|
||||
die("ERROR; ENDPOINT NOT EXIST");
|
||||
}
|
||||
|
||||
die();
|
||||
}
|
||||
|
||||
if ($handle = opendir('./plugins/')) {
|
||||
while (false !== ($entry = readdir($handle))) {
|
||||
if ($entry != "." && $entry != "..") {
|
||||
include_once "./plugins/".$entry;
|
||||
}
|
||||
}
|
||||
|
||||
closedir($handle);
|
||||
}
|
||||
|
||||
if(isset($_GET['logout']) && $_GET['logout'] == '1') {
|
||||
$_SESSION = array();
|
||||
header('Location: index.php');
|
||||
}
|
||||
|
||||
if(isset($_SESSION['LOGIN']) && $_SESSION['LOGIN'] == 'true') {
|
||||
if(!isset($_GET['page'])) {
|
||||
include './pages/dashboard.php';
|
||||
} else if(isValidEndpoint($_GET['page'], 'pages')) {
|
||||
include "./pages/".$_GET['page'].".php";
|
||||
} else {
|
||||
include "./pages/error.php";
|
||||
}
|
||||
|
||||
die();
|
||||
}
|
||||
else {
|
||||
$page = isset($_GET['page']) ? $_GET['page'] : 'login';
|
||||
|
||||
if(needsLogin($page)) {
|
||||
$_SESSION['loginMessage'] = 'Du musst dich einloggen, um das MCP nutzen zu können';
|
||||
$_SESSION['loginMessageColor'] = 'red';
|
||||
header('Location: index.php?page=login');
|
||||
}
|
||||
else {
|
||||
include "./pages/".$page.".php";
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,33 @@
|
|||
{
|
||||
"name": "mcp-frontend",
|
||||
"description": "Frontend components for the 4Creative MCP",
|
||||
"version": "1.0.0",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"build": "npm run css && npm run js && npm run fonts",
|
||||
"css-compile-dash": "sass --style compressed --no-error-css --no-source-map --load-path=node_modules scss/dashboard/sb-admin.scss:public/style/sb-admin.min.css",
|
||||
"css-compile-login": "sass --style compressed --no-error-css --no-source-map --load-path=node_modules scss/login/login.scss:public/style/login.min.css",
|
||||
"css-lint": "stylelint scss/",
|
||||
"css-prefix": "postcss --replace public/style/* --use autoprefixer --no-map",
|
||||
"css": "npm run css-compile-dash && npm run css-compile-login && npm run css-prefix",
|
||||
"js": "cp node_modules/bootstrap/dist/js/bootstrap.bundle.min.js public/js/vendor/bootstrap.bundle.min.js && cp node_modules/jquery/dist/jquery.min.js public/js/vendor/jquery.min.js && cp node_modules/jquery.easing/jquery.easing.min.js public/js/vendor/jquery.easing.min.js",
|
||||
"fonts": "cp -r node_modules/@fortawesome/fontawesome-free/webfonts public/fonts/fontawesome-free",
|
||||
"server": "http-server ./public -c-1 -a 127.0.0.1",
|
||||
"start": "npm run watch & npm run server",
|
||||
"watch": "nodemon -e html,scss,js --ignore public/js -x \"npm run build\""
|
||||
},
|
||||
"dependencies": {
|
||||
"@fortawesome/fontawesome-free": "^6.4.2",
|
||||
"bootstrap": "^4.6.2",
|
||||
"jquery": "^3.7.1",
|
||||
"jquery.easing": "^1.4.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"autoprefixer": "^10.4.14",
|
||||
"http-server": "^14.1.1",
|
||||
"nodemon": "^3.0.1",
|
||||
"postcss": "^8.4.24",
|
||||
"postcss-cli": "^10.1.0",
|
||||
"sass": "^1.63.6"
|
||||
}
|
||||
}
|
|
@ -1 +0,0 @@
|
|||
Deny from all
|
|
@ -1,15 +0,0 @@
|
|||
<?php
|
||||
include '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();
|
||||
?>
|
|
@ -1,7 +0,0 @@
|
|||
<?php
|
||||
$HTML->setHTMLTitle("Seite nicht gefunden");
|
||||
|
||||
$HTML->build();
|
||||
http_response_code(404);
|
||||
echo $HTML->ausgabe();
|
||||
?>
|
|
@ -1,71 +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();
|
||||
}
|
||||
|
||||
?>
|
|
@ -1,58 +0,0 @@
|
|||
<?php
|
||||
if($_SERVER['REQUEST_METHOD'] == 'POST')
|
||||
{
|
||||
if(isset($_POST['remove'])) {
|
||||
include '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']]);
|
||||
|
||||
while($row = $statement->fetch())
|
||||
{
|
||||
$PrincipalID = explode(";", $row['PrincipalID'])[0];
|
||||
$FriendData = explode(";", $row['Friend']);
|
||||
$Friend = $FriendData[0];
|
||||
|
||||
include 'app/OpenSim.php';
|
||||
$opensim = new OpenSim();
|
||||
|
||||
$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();
|
||||
?>
|
|
@ -1,42 +0,0 @@
|
|||
<?php
|
||||
if($_SERVER['REQUEST_METHOD'] == 'POST')
|
||||
{
|
||||
if(isset($_POST['leave'])) {
|
||||
include '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 '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();
|
||||
?>
|
|
@ -1,138 +0,0 @@
|
|||
<?php
|
||||
$statementCreateTable = $RUNTIME['PDO']->prepare("CREATE TABLE IF NOT EXISTS `UserIdentitys` (`PrincipalID` VARCHAR(38) NOT NULL, `IdentityID` VARCHAR(38) NOT NULL, PRIMARY KEY (`IdentityID`))");
|
||||
$statementCreateTable->execute();
|
||||
|
||||
if($_SERVER['REQUEST_METHOD'] == 'POST') {
|
||||
include 'app/FormValidator.php';
|
||||
if(isset($_POST['enableIdent'])) {
|
||||
$validator = new FormValidator(array(
|
||||
'newuuid' => 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' => $_REQUEST['newuuid']]);
|
||||
|
||||
$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' => $_REQUEST['newuuid'], 'PrincipalID' => $_SESSION['UUID']]);
|
||||
|
||||
$statementUserIdentitys = $RUNTIME['PDO']->prepare('UPDATE UserIdentitys SET PrincipalID = :IdentityID WHERE PrincipalID = :PrincipalID');
|
||||
$statementUserIdentitys->execute(['IdentityID' => $_REQUEST['newuuid'], 'PrincipalID' => $_SESSION['UUID']]);
|
||||
|
||||
$statementFriends = $RUNTIME['PDO']->prepare('UPDATE Friends SET PrincipalID = :IdentityID WHERE PrincipalID = :PrincipalID');
|
||||
$statementFriends->execute(['IdentityID' => $_REQUEST['newuuid'], 'PrincipalID' => $_SESSION['UUID']]);
|
||||
|
||||
//$statementReFriends = $RUNTIME['PDO']->prepare('UPDATE Friends SET Friend = :IdentityID WHERE Friend = :PrincipalID');
|
||||
//$statementReFriends->execute(['IdentityID' => $_REQUEST['newuuid'], 'PrincipalID' => $_SESSION['UUID']]);
|
||||
|
||||
$statementInventoryFolders = $RUNTIME['PDO']->prepare('UPDATE inventoryfolders SET agentID = :IdentityID WHERE agentID = :PrincipalID AND type != :InventarTyp');
|
||||
$statementInventoryFolders->execute(['IdentityID' => $_REQUEST['newuuid'], 'PrincipalID' => $_SESSION['UUID'], 'InventarTyp' => 46]);
|
||||
|
||||
$statementInventoryItems = $RUNTIME['PDO']->prepare('UPDATE inventoryitems SET avatarID = :IdentityID WHERE avatarID = :PrincipalID');
|
||||
$statementInventoryItems->execute(['IdentityID' => $_REQUEST['newuuid'], 'PrincipalID' => $_SESSION['UUID']]);
|
||||
|
||||
$statementGroupMembership = $RUNTIME['PDO']->prepare('UPDATE os_groups_membership SET PrincipalID = :IdentityID WHERE PrincipalID = :PrincipalID');
|
||||
$statementGroupMembership->execute(['IdentityID' => $_REQUEST['newuuid'], 'PrincipalID' => $_SESSION['UUID']]);
|
||||
|
||||
$statementGroupRoles = $RUNTIME['PDO']->prepare('UPDATE os_groups_rolemembership SET PrincipalID = :IdentityID WHERE PrincipalID = :PrincipalID');
|
||||
$statementGroupRoles->execute(['IdentityID' => $_REQUEST['newuuid'], '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.';
|
||||
}
|
||||
}
|
||||
}
|
||||
else if(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($_REQUEST['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 '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.';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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 '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="newuuid" value="'.htmlspecialchars($row['IdentityID']).'"><button type="submit" name="enableIdent" class="btn btn-success btn-sm">Aktivieren</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();
|
||||
?>
|
|
@ -1,19 +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();
|
||||
?>
|
|
@ -1,59 +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'] = trim($rowUser['FirstName']);
|
||||
$_SESSION['LASTNAME'] = trim($rowUser['LastName']);
|
||||
$_SESSION['EMAIL'] = trim($rowUser['Email']);
|
||||
$_SESSION['PASSWORD'] = $rowAuth['passwordHash'];
|
||||
$_SESSION['SALT'] = $rowAuth['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']));
|
||||
}
|
||||
}
|
||||
else if(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();
|
||||
?>
|
|
@ -1,208 +0,0 @@
|
|||
<?php
|
||||
function setNamePart(string $part, string $value, string $otherPart, string $otherValue) {
|
||||
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;
|
||||
}
|
||||
|
||||
$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();
|
||||
|
||||
//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();
|
||||
|
||||
if($_SERVER['REQUEST_METHOD'] == 'POST') {
|
||||
include 'app/FormValidator.php';
|
||||
|
||||
if(isset($_POST['createIAR'])) {
|
||||
$validator = new FormValidator(array()); // CSRF validation only
|
||||
if($validator->isValid($_POST) && $IARRUNNING == FALSE) {
|
||||
$iarname = md5(time().$_SESSION['UUID'] . rand()).".iar";
|
||||
|
||||
$statementIARSTART = $RUNTIME['PDO']->prepare('INSERT INTO iarstates (userID, filesize, iarfilename) VALUES (:userID, :filesize, :iarfilename)');
|
||||
$statementIARSTART->execute(['userID' => $_SESSION['UUID'], 'filesize' => 0, 'iarfilename' => $iarname]);
|
||||
|
||||
$_SESSION['iar_created'] = true;
|
||||
}
|
||||
}
|
||||
else if(isset($_POST['saveProfileData'])) {
|
||||
$validator = new FormValidator(array(
|
||||
'formInputFeldVorname' => array('regex' => '/^[^\\/<>\s]{1,64}$/'),
|
||||
'formInputFeldNachname' => array('regex' => '/^[^\\/<>\s]{1,64}$/'),
|
||||
'formInputFeldEMail' => array('regex' => '/^\S{1,64}@\S{1,250}.\S{2,64}$/'),
|
||||
'formInputFeldOfflineIM' => array('regex' => '/^(|on)$/'),
|
||||
'formInputFeldPartnerName' => array('regex' => '/^[^\\/<>\s]{1,64} [^\\/<>\s]{1,64}$/')
|
||||
));
|
||||
|
||||
if($validator->isValid($_POST)) {
|
||||
if(isset($_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;
|
||||
$_SESSION['USERNAME'] = $_SESSION['FIRSTNAME']." ".$_SESSION['LASTNAME'];
|
||||
$_SESSION['DISPLAYNAME'] = strtoupper($_SESSION['USERNAME']);
|
||||
}
|
||||
else {
|
||||
$_SESSION['profile_info'] = 'Der gewählte Name ist bereits vergeben.';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(isset($_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;
|
||||
$_SESSION['USERNAME'] = $_SESSION['FIRSTNAME']." ".$_SESSION['LASTNAME'];
|
||||
$_SESSION['DISPLAYNAME'] = strtoupper($_SESSION['USERNAME']);
|
||||
}
|
||||
else {
|
||||
$_SESSION['profile_info'] = 'Der gewählte Name ist bereits vergeben.';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(isset($_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']]);
|
||||
|
||||
$statement = $RUNTIME['PDO']->prepare('UPDATE usersettings SET email = :Email WHERE useruuid = :PrincipalID');
|
||||
$statement->execute(['Email' => $NewEMail, 'PrincipalID' => $_SESSION['UUID']]);
|
||||
|
||||
$_SESSION['EMAIL'] = $NewEMail;
|
||||
}
|
||||
}
|
||||
|
||||
if(isset($_POST['formInputFeldOfflineIM']) && $_POST['formInputFeldOfflineIM'] == "on") {
|
||||
$statement = $RUNTIME['PDO']->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->execute(['IMState' => 'false', 'PrincipalID' => $_SESSION['UUID']]);
|
||||
}
|
||||
|
||||
if(isset($_POST['formInputFeldPartnerName']) && $_POST['formInputFeldPartnerName'] != "") {
|
||||
include_once 'app/OpenSim.php';
|
||||
$opensim = new OpenSim();
|
||||
|
||||
$NewPartner = trim($_POST['formInputFeldPartnerName']);
|
||||
$CurrentPartner = $opensim->getPartner($_SESSION['UUID']);
|
||||
|
||||
if($CurrentPartner != "")$CurrentPartner = $opensim->getUserName($CurrentPartner);
|
||||
|
||||
if($NewPartner != "" && $CurrentPartner != $NewPartner) {
|
||||
$newPartnerUUID = $opensim->getUserUUID($NewPartner);
|
||||
|
||||
if($newPartnerUUID != null) {
|
||||
$statement = $RUNTIME['PDO']->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->execute(['profilePartner' => '00000000-0000-0000-0000-000000000000', 'PrincipalID' => $_SESSION['UUID']]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if(isset($_POST['savePassword'])) {
|
||||
$validator = new FormValidator(array(
|
||||
'oldPassword' => array('required' => true, 'regex' => '/^.{1,1000}$/'),
|
||||
'newPassword' => array('required' => true, 'regex' => '/^.{1,1000}$/'),
|
||||
'newPasswordRepeat' => array('required' => true, 'regex' => '/^.{1,1000}$/')
|
||||
));
|
||||
|
||||
if($validator->isValid($_POST)) {
|
||||
if($_POST['newPasswordRepeat'] == $_POST['newPassword']) {
|
||||
if(strlen(trim($_POST['newPassword'])) >= $RUNTIME['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->execute(['PasswordHash' => $hash, 'PasswordSalt' => $salt, 'PrincipalID' => $_SESSION['UUID']]);
|
||||
$_SESSION['PASSWORD'] = $hash;
|
||||
$_SESSION['SALT'] = $salt;
|
||||
$_SESSION['profile_info'] = 'Neues Passwort gespeichert.';
|
||||
}
|
||||
else {
|
||||
$_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.';
|
||||
}
|
||||
}
|
||||
else {
|
||||
$_SESSION['profile_info'] = 'Die neuen Passwörter stimmen nicht überein!';
|
||||
}
|
||||
}
|
||||
else {
|
||||
$_SESSION['profile_info'] = 'Bitte fülle das Formular vollständig aus.';
|
||||
}
|
||||
}
|
||||
|
||||
header('Location: index.php?page=profile');
|
||||
die();
|
||||
}
|
||||
|
||||
$HTML->setHTMLTitle("Dein Profile");
|
||||
$HTML->importSeitenInhalt("profile.html");
|
||||
|
||||
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>');
|
||||
}
|
||||
$HTML->ReplaceSeitenInhalt("%%IARBUTTONSTATE%%", 'disabled');
|
||||
}
|
||||
|
||||
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();
|
||||
?>
|
|
@ -1,86 +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 '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 'app/OpenSim.php';
|
||||
$opensim = new OpenSim();
|
||||
|
||||
while($row = $statement->fetch())
|
||||
{
|
||||
$stats = getRegionStatsData($row['uuid']);
|
||||
|
||||
$entry = '<tr><td>'.htmlspecialchars($row['regionName']).'<div class="blockquote-footer">Prims: '.$stats['Prims'].'; RAM-Nutzung: '.$stats['ProcMem'].'; SIM/PHYS FPS: '.$stats['SimFPS'].'/'.$stats['PhyFPS'].' ('.$stats['RegionVersion'].')</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();
|
||||
?>
|
|
@ -1,150 +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();
|
||||
}
|
||||
|
||||
if(!isset($_REQUEST['code']))
|
||||
die("MISSING INVITE CODE!");
|
||||
|
||||
if(strlen($_REQUEST['code']) != 32 || !preg_match('/^[a-f0-9]+$/', $_REQUEST['code'])) {
|
||||
die("INVALID INVITE CODE!");
|
||||
}
|
||||
|
||||
$statementInviteCode = $RUNTIME['PDO']->prepare("SELECT 1 FROM InviteCodes WHERE InviteCode = ? LIMIT 1");
|
||||
$statementInviteCode->execute([$_REQUEST['code']]);
|
||||
|
||||
if($statementInviteCode->rowCount() == 0) {
|
||||
die("INVALID INVITE CODE!");
|
||||
}
|
||||
|
||||
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 '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) {
|
||||
header('Location: index.php');
|
||||
die();
|
||||
}
|
||||
|
||||
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();
|
||||
?>
|
|
@ -1,89 +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('');
|
||||
?>
|
|
@ -1,27 +0,0 @@
|
|||
<?php
|
||||
include '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();
|
||||
?>
|
|
@ -1,70 +0,0 @@
|
|||
<?php
|
||||
$HTML->setHTMLTitle("Benutzer");
|
||||
$HTML->importSeitenInhalt("users.html");
|
||||
|
||||
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 'app/OpenSim.php';
|
||||
$opensim = new OpenSim();
|
||||
|
||||
if($_SERVER['REQUEST_METHOD'] == 'POST') {
|
||||
include 'app/FormValidator.php';
|
||||
if(isset($_POST['genpw'])) {
|
||||
$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)) {
|
||||
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($_REQUEST['userid'])).' kann in den nächsten 24 Stunden über diesen Link zurückgesetzt werden: <b>'.$resetLink.'</b></div>');
|
||||
}
|
||||
}
|
||||
else 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$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>';
|
||||
|
||||
$statement = $RUNTIME['PDO']->prepare("SELECT FirstName,LastName,UserLevel,PrincipalID FROM UserAccounts ORDER BY Created ASC");
|
||||
$statement->execute();
|
||||
|
||||
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></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();
|
||||
?>
|
|
@ -1,13 +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']) : '');
|
||||
}
|
||||
?>
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue