databseRequired = false;
}
}
}
namespace Documents\Install {
class Head extends \Elements\Head {
public function __construct($document) {
parent::__construct($document);
}
protected function initSources() {
$this->loadJQuery();
$this->loadBootstrap();
$this->loadFontawesome();
$this->addJS(\Elements\Script::CORE);
$this->addCSS(\Elements\Link::CORE);
$this->addJS(\Elements\Script::INSTALL);
}
protected function initMetas() {
return array(
array('name' => 'viewport', 'content' => 'width=device-width, initial-scale=1.0'),
array('name' => 'format-detection', 'content' => 'telephone=yes'),
array('charset' => 'utf-8'),
array("http-equiv" => 'expires', 'content' => '0'),
array("name" => 'robots', 'content' => 'noarchive'),
);
}
protected function initRawFields() {
return array();
}
protected function initTitle() {
return "WebBase - Installation";
}
}
class Body extends \Elements\Body {
// Status enum
const NOT_STARTED = 0;
const PENDING = 1;
const SUCCESFULL = 2;
const ERROR = 3;
// Step enum
const CHECKING_REQUIRMENTS = 1;
const DATABASE_CONFIGURATION = 2;
const CREATE_USER = 3;
const ADD_MAIL_SERVICE = 4;
const FINISH_INSTALLATION = 5;
//
private $configDirectory;
private $databaseScript;
private $errorString;
function __construct($document) {
parent::__construct($document);
// TODO: make better
$this->configDirectory = getWebRoot() . '/core/Configuration';
$this->databaseScript = getWebRoot() . '/core/Configuration/database.sql';
$this->errorString = "";
}
private function getParameter($name) {
if(isset($_REQUEST[$name]) && is_string($_REQUEST[$name])) {
return trim($_REQUEST[$name]);
}
return NULL;
}
private function getCurrentStep() {
if(!$this->checkRequirements()) {
return self::CHECKING_REQUIRMENTS;
}
$user = $this->getDocument()->getUser();
$config = $user->getConfiguration();
// Check if database configuration exists
if(!$config->getDatabase()) {
return self::DATABASE_CONFIGURATION;
}
$query = "SELECT * FROM User";
$sql = $user->getSQL();
if(!is_null($sql) && $sql->isConnected()) {
$res = $sql->query($query);
if($res) {
if($res->num_rows === 0) {
$step = self::CREATE_USER;
} else {
$step = self::ADD_MAIL_SERVICE;
}
}
} else {
$step = self::DATABASE_CONFIGURATION;
}
if($step == self::ADD_MAIL_SERVICE && $config->isFilePresent("Mail")) {
$step = self::FINISH_INSTALLATION;
if(!$config->isFilePresent("JWT") && $config->create("JWT", generateRandomString(32))) {
$this->errorString = "Unable to create jwt file";
}
}
return $step;
}
private function checkRequirements() {
$msg = $this->errorString;
$success = true;
$failedRequirements = array();
if(!is_writeable($this->configDirectory)) {
$failedRequirements[] = "$this->configDirectory is not writeable. Try running chmod 600";
$success = false;
}
if(!is_readable($this->databaseScript)) {
$failedRequirements[] = "$this->databaseScript is not readable.";
$success = false;
}
if(version_compare(PHP_VERSION, '7.1', '<')) {
$failedRequirements[] = "PHP Version >= 7.1 is required. Got: " . PHP_VERSION . "";
$success = false;
}
if(!function_exists('mysqli_connect')) {
$link = $this->createExternalLink("https://secure.php.net/manual/en/mysqli.setup.php");
$failedRequirements[] = "mysqli is not enabled yet. See: $link";
$success = false;
}
if(!$success) {
$msg = "The following requirements failed the check:
" .
$this->createUnorderedList($failedRequirements);
}
return array("success" => $success, "msg" => $msg);
}
private function databaseConfiguration() {
$host = $this->getParameter("host");
$port = $this->getParameter("port");
$username = $this->getParameter("username");
$password = $this->getParameter("password");
$database = $this->getParameter("database");
$success = true;
$missingInputs = array();
if(is_null($host) || empty($host)) {
$success = false;
$missingInputs[] = "Host";
}
if(is_null($port) || empty($port)) {
$success = false;
$missingInputs[] = "Port";
}
if(is_null($username) || empty($username)) {
$success = false;
$missingInputs[] = "Username";
}
if(is_null($password)) {
$success = false;
$missingInputs[] = "Password";
}
if(is_null($database) || empty($database)) {
$success = false;
$missingInputs[] = "Database";
}
if(!$success) {
$msg = "Please fill out the following inputs:
" .
$this->createUnorderedList($missingInputs);
} else if(!is_numeric($port) || ($port = intval($port)) < 1 || $port > 65535) {
$msg = "Port must be in range of 1-65535.";
$success = false;
} else {
$connectionData = new \Objects\ConnectionData($host, $port, $username, $password);
$connectionData->setProperty('database', $database);
$connectionData->setProperty('encoding', 'utf8');
$sql = new \Driver\SQL($connectionData);
$success = $sql->connect();
if(!$success) {
$msg = "Error connecting to database:
" . $sql->getLastError();
} else {
try {
$msg = "Error loading database script $this->databaseScript";
$commands = file_get_contents($this->databaseScript);
$success = $sql->executeMulti($commands);
if(!$success) {
$msg = $sql->getLastError();
} else if(!$this->getDocument()->getUser()->getConfiguration()->create("Database", $connectionData)) {
$success = false;
$msg = "Unable to write file";
} else {
$msg = "";
}
} catch(Exception $e) {
$success = false;
$msg .= ": " . $e->getMessage();
}
if($sql) {
$sql->close();
}
}
}
return array("success" => $success, "msg" => $msg);
}
private function createUser() {
$user = $this->getDocument()->getUser();
if($this->getParameter("prev") === "true") {
$success = $user->getConfiguration()->delete("Database");
$msg = $success ? "" : error_get_last();
return array("success" => $success, "msg" => $msg);
}
$username = $this->getParameter("username");
$password = $this->getParameter("password");
$confirmPassword = $this->getParameter("confirmPassword");
$msg = $this->errorString;
$success = true;
$missingInputs = array();
if(is_null($username) || empty($username)) {
$success = false;
$missingInputs[] = "Username";
}
if(is_null($password) || empty($password)) {
$success = false;
$missingInputs[] = "Password";
}
if(is_null($confirmPassword) || empty($confirmPassword)) {
$success = false;
$missingInputs[] = "Confirm Password";
}
if(!$success) {
$msg = "Please fill out the following inputs:
" .
$this->createUnorderedList($missingInputs);
} else if(strlen($username) < 5 || strlen($username) > 32) {
$msg = "The username should be between 5 and 32 characters long";
$success = false;
} else if(strcmp($password, $confirmPassword) !== 0) {
$msg = "The given passwords do not match";
$success = false;
} else if(strlen($password) < 6) {
$msg = "The password should be at least 6 characters long";
$success = false;
} else {
$salt = generateRandomString(16);
$hash = hash('sha256', $password . $salt);
$query = "INSERT INTO User (name, salt, password) VALUES (?,?,?)";
$req = new \Api\ExecuteStatement($user);
$success = $req->execute(array("query" => $query, $username, $salt, $hash));
$nsg = $req->getLastError();
}
return array("msg" => $msg, "success" => $success);
}
private function addMailService() {
$user = $this->getDocument()->getUser();
if($this->getParameter("prev") === "true") {
$req = new \Api\ExecuteStatement($user);
$success = $req->execute(array("query" => "TRUNCATE User"));
$msg = $req->getLastError();
return array("success" => $success, "msg" => $msg);
}
$success = true;
$msg = $this->errorString;
if($this->getParameter("skip") === "true") {
if(!$user->getConfiguration()->create("Mail", null)) {
$success = false;
$msg = "Unable to create file";
}
} else {
$address = $this->getParameter("address");
$port = $this->getParameter("port");
$username = $this->getParameter("username");
$password = $this->getParameter("password");
$success = true;
$missingInputs = array();
if(is_null($address) || empty($address)) {
$success = false;
$missingInputs[] = "SMTP Address";
}
if(is_null($port) || empty($port)) {
$success = false;
$missingInputs[] = "Port";
}
if(is_null($username) || empty($username)) {
$success = false;
$missingInputs[] = "Username";
}
if(is_null($password)) {
$success = false;
$missingInputs[] = "Password";
}
if(!$success) {
$msg = "Please fill out the following inputs:
" .
$this->createUnorderedList($missingInputs);
} else if(!is_numeric($port) || ($port = intval($port)) < 1 || $port > 65535) {
$msg = "Port must be in range of 1-65535.";
$success = false;
} else {
$success = false;
$mail = new \External\PHPMailer\PHPMailer(true);
$mail->IsSMTP();
$mail->SMTPAuth = true;
$mail->Username = $username;
$mail->Password = $password;
$mail->Host = $address;
$mail->Port = $port;
$mail->SMTPSecure = 'tls';
$mail->Timeout = 10;
try {
$success = $mail->SmtpConnect();
if(!$success) {
$error = empty($mail->ErrorInfo) ? "Unknown Error" : $mail->ErrorInfo;
$msg = "Could not connect to SMTP Server: $error";
} else {
$success = true;
$msg = "";
$mail->smtpClose();
}
} catch(\External\PHPMailer\Exception $error) {
$msg = "Could not connect to SMTP Server: " . $error->errorMessage();
}
if($success) {
$connectionData = new \Objects\ConnectionData($address, $port, $username, $password);
if(!$user->getConfiguration()->create("Mail", $connectionData)) {
$success = false;
$msg = "Unable to create file";
}
}
}
}
return array("success" => $success, "msg" => $msg);
}
private function performStep() {
switch($this->currentStep) {
case self::CHECKING_REQUIRMENTS:
return $this->checkRequirements();
case self::DATABASE_CONFIGURATION:
return $this->databaseConfiguration();
case self::CREATE_USER:
return $this->createUser();
case self::ADD_MAIL_SERVICE:
return $this->addMailService();
default:
return array(
"success" => false,
"msg" => "Invalid step number"
);
}
}
private function createProgressSidebar() {
$items = array();
foreach($this->steps as $num => $step) {
$title = $step["title"];
$status = $step["status"];
$currentStep = ($num == $this->currentStep) ? " id=\"currentStep\"" : "";
switch($status) {
case self::PENDING:
$statusIcon = '';
$statusText = "Loading…";
$statusColor = "muted";
break;
case self::SUCCESFULL:
$statusIcon = '';
$statusText = "Successfull";
$statusColor = "success";
break;
case self::ERROR:
$statusIcon = '';
$statusText = "Failed";
$statusColor = "danger";
break;
case self::NOT_STARTED:
default:
$statusIcon = '';
$statusText = "Pending";
$statusColor = "muted";
break;
}
$items[] = "
Process the following steps and fill out the required forms to install your WebBase-Installation.