Fixes + ApiKeys

This commit is contained in:
Roman Hergenreder 2020-02-10 12:16:34 +01:00
parent 1853756db4
commit 6f8b3f93e9
13 changed files with 354 additions and 4 deletions

@ -3,3 +3,4 @@ Options -Indexes
RewriteEngine On RewriteEngine On
RewriteRule ^api/(.*)?$ index.php?api=$1&$2 [L,QSA] RewriteRule ^api/(.*)?$ index.php?api=$1&$2 [L,QSA]
RewriteRule ^(?!((js|css|img|fonts|api)($|\/)))(.*)?$ index.php?site=$1&$2 [L,QSA]

@ -0,0 +1,31 @@
<?php
namespace Api;
class CreateApiKey extends Request {
public function __construct($user, $externCall = false) {
parent::__construct($user, $externCall, array());
$this->apiKeyAllowed = false;
$this->loginRequired = true;
}
public function execute($values = array()) {
if(!parent::execute($values)) {
return false;
}
$apiKey = generateRandomString(64);
$query = "INSERT INTO ApiKey (uidUser, api_key, valid_until) VALUES (?,?,(SELECT DATE_ADD(now(), INTERVAL 30 DAY)))";
$request = new ExecuteStatement($this->user);
$this->success = $request->execute(array("query" => $query, $this->user->getId(), $apiKey));
$this->lastError = $request->getLastError();
$this->result["api_key"] = $apiKey;
$this->result["valid_until"] = "TODO";
$this->result["uid"] = $this->user->getSQL()->getLastInsertId();
return $this->success;
}
};
?>

82
core/Api/External/RequestData.class.php vendored Normal file

@ -0,0 +1,82 @@
<?php
namespace Api\External;
use \Api\Parameter\Parameter;
use \Api\Parameter\StringType;
class RequestData extends \Api\Request {
public function __construct($user, $externCall = false) {
parent::__construct($user, $externCall, array(
"url" => new StringType("url", 256)
));
$this->isPublic = false;
}
private function requestURL() {
$url = $this->getParam("url");
$ckfile = tempnam("/tmp", 'cookiename');
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
// curl_setopt($ch, CURLOPT_HEADER, 1);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
curl_setopt($ch, CURLOPT_COOKIESESSION, true);
curl_setopt($ch, CURLOPT_COOKIEJAR, $ckfile);
curl_setopt($ch, CURLOPT_COOKIEFILE, $ckfile);
$data = curl_exec($ch);
$statusCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
$success = false;
if(curl_errno($ch)) {
$this->lastError = curl_error($ch);
} else if($statusCode != 200) {
$this->lastError = "External Site returned status code: " . $statusCode;
} else {
$this->result["data"] = $data;
$this->result["cached"] = false;
$success = true;
}
unlink($ckfile);
curl_close ($ch);
return $success;
}
public function execute($values = array()) {
if(!parent::execute($values)) {
return false;
}
$url = $this->getParam("url");
$expires = $this->getParam("expires");
$query = "SELECT data, expires FROM ExternalSiteCache WHERE url=?";
$req = new \Api\ExecuteSelect($this->user);
$this->success = $req->execute(array("query" => $query, $url));
$this->lastError = $req->getLastError();
if($this->success) {
$mustRevalidate = true;
if(!empty($req->getResult()['rows'])) {
$row = $req->getResult()['rows'][0];
if($row["expires"] == null || !isinPast($row["expires"])) {
$mustRevalidate = false;
$this->result["data"] = $row["data"];
$this->result["expires"] = $row["expires"];
$this->result["cached"] = true;
}
}
if($mustRevalidate) {
$this->success = $this->requestURL();
}
}
return $this->success;
}
};
?>

44
core/Api/External/WriteData.class.php vendored Normal file

@ -0,0 +1,44 @@
<?php
namespace Api\External;
use Api\Parameter\Parameter;
use Api\Parameter\StringType;
class WriteData extends \Api\Request {
public function __construct($user, $externCall = false) {
parent::__construct($user, $externCall, array(
"url" => new StringType("url", 256),
"data" => new StringType("data", -1),
"expires" => new Parameter("expires", Parameter::TYPE_INT, false, 0),
));
$this->isPublic = false;
}
public function execute($values = array()) {
if(!parent::execute($values)) {
return false;
}
$url = $this->getParam("url");
$data = $this->getParam("data");
$expires = $this->getParam("expires");
if($expires > 0) {
$expires = getDateTime(new \DateTime("+${expires} seconds"));
} else {
$expires = null;
}
$query = "INSERT INTO ExternalSiteCache (url, data, expires) VALUES(?,?,?)
ON DUPLICATE KEY UPDATE data=?, expires=?";
$request = new \Api\ExecuteStatement($this->user);
$this->success = $request->execute(array("query" => $query, $url, $data, $expires, $data, $expires));
$this->lastError = $request->getLastError();
return $this->lastError;
}
}
?>

@ -0,0 +1,33 @@
<?php
namespace Api;
class GetApiKeys extends Request {
public function __construct($user, $externCall = false) {
parent::__construct($user, $externCall, array());
$this->loginRequired = true;
}
public function execute($values = array()) {
if(!parent::execute($values)) {
return false;
}
$query = "SELECT ApiKey.uid, ApiKey.api_key, ApiKey.valid_until
FROM ApiKey
WHERE ApiKey.uidUser = ?
AND ApiKey.valid_until > now()";
$request = new ExecuteSelect($this->user);
$this->success = $request->execute(array("query" => $query, $this->user->getId()));
$this->lastError = $request->getLastError();
if($this->success) {
$this->result["api_keys"] = $request->getResult()['rows'];
}
return $this->success;
}
};
?>

@ -0,0 +1,48 @@
<?php
namespace Api;
use \Api\Parameter\Parameter;
class RefreshApiKey extends Request {
public function __construct($user, $externCall = false) {
parent::__construct($user, $externCall, array(
"id" => new Parameter("id", Parameter::TYPE_INT),
));
$this->loginRequired = true;
}
private function apiKeyExists() {
$id = $this->getParam("id");
$query = "SELECT * FROM ApiKey WHERE uid = ? AND uidUser = ? AND valid_until > now()";
$request = new ExecuteSelect($this->user);
$this->success = $request->execute(array("query" => $query, $id, $this->user->getId()));
$this->lastError = $request->getLastError();
if($this->success && count($request->getResult()['rows']) == 0) {
$this->success = false;
$this->lastError = "This API-Key does not exist.";
}
return $this->success;
}
public function execute($values = array()) {
if(!parent::execute($values)) {
return false;
}
$id = $this->getParam("id");
if(!$this->apiKeyExists())
return false;
$query = "UPDATE ApiKey SET valid_until = (SELECT DATE_ADD(now(), INTERVAL 30 DAY)) WHERE uid = ? AND uidUser = ? AND valid_until > now()";
$request = new ExecuteStatement($this->user);
$this->success = $request->execute(array("query" => $query, $id, $this->user->getId()));
$this->lastError = $request->getLastError();
return $this->success;
}
};
?>

@ -0,0 +1,48 @@
<?php
namespace Api;
use \Api\Parameter\Parameter;
class RevokeApiKey extends Request {
public function __construct($user, $externCall = false) {
parent::__construct($user, $externCall, array(
"id" => new Parameter("id", Parameter::TYPE_INT),
));
$this->loginRequired = true;
}
private function apiKeyExists() {
$id = $this->getParam("id");
$query = "SELECT * FROM ApiKey WHERE uid = ? AND uidUser = ? AND valid_until > now()";
$request = new ExecuteSelect($this->user);
$this->success = $request->execute(array("query" => $query, $id, $this->user->getId()));
$this->lastError = $request->getLastError();
if($this->success && count($request->getResult()['rows']) == 0) {
$this->success = false;
$this->lastError = "This API-Key does not exist.";
}
return $this->success;
}
public function execute($aValues = array()) {
if(!parent::execute($aValues)) {
return false;
}
$id = $this->getParam("id");
if(!$this->apiKeyExists())
return false;
$query = "DELETE FROM ApiKey WHERE valid_until < now() OR (uid = ? AND uidUser = ?)";
$request = new ExecuteStatement($this->user);
$this->success = $request->execute(array("query" => $query, $id, $this->user->getId()));
$this->lastError = $request->getLastError();
return $this->success;
}
};
?>

@ -0,0 +1,58 @@
<?php
namespace Api;
use Api\Parameter\Parameter;
use Api\Parameter\StringType;
class SendMail extends Request {
public function __construct($user, $externCall = false) {
parent::__construct($user, $externCall, array(
'from' => new Parameter('from', Parameter::TYPE_EMAIL),
'to' => new Parameter('to', Parameter::TYPE_EMAIL),
'subject' => new StringType('subject', -1),
'body' => new StringType('body', -1),
'fromName' => new StringType('fromName', -1, true, ''),
'replyTo' => new Parameter('to', Parameter::TYPE_EMAIL, true, ''),
));
$this->isPublic = false;
}
public function execute($values = array()) {
if(!parent::execute($values)) {
return false;
}
$mailData = getMailData();
$mail = new \External\PHPMailer\PHPMailer;
$mail->IsSMTP();
$mail->setFrom($this->getParam('from'), $this->getParam('fromName'));
$mail->addAddress($this->getParam('to'));
$mail->Subject = $this->getParam('subject');
$mail->SMTPDebug = 0;
$mail->Host = $mailData->getHost();
$mail->Port = $mailData->getPort();
$mail->SMTPAuth = true;
$mail->Username = $mailData->getLogin();
$mail->Password = $mailData->getPassword();
$mail->SMTPSecure = 'tls';
$mail->IsHTML(true);
$mail->CharSet = 'UTF-8';
$mail->Body = $this->getParam('body');
$replyTo = $this->getParam('replyTo');
if(!is_null($replyTo) && !empty($replyTo)) {
$mail->AddReplyTo($replyTo, $this->getParam('fromName'));
}
$this->success = @$mail->Send();
if (!$this->success) {
$this->lastError = 'Error sending Mail: ' . $mail->ErrorInfo;
error_log("sendMail() failed: " . $mail->ErrorInfo);
}
return $this->success;
}
};
?>

@ -685,13 +685,13 @@ namespace Documents\Install {
die(json_encode($response)); die(json_encode($response));
} }
if($this->currentStep == self::CHECKING_REQUIRMENTS) { /*if($this->currentStep == self::CHECKING_REQUIRMENTS) {
$this->getDocument()->getHead()->addJSCode(" $this->getDocument()->getHead()->addJSCode("
$(document).ready(function() { $(document).ready(function() {
retry(); retry();
}); });
"); ");
} }*/
$progressSidebar = $this->createProgressSidebar(); $progressSidebar = $this->createProgressSidebar();
$progressMainview = $this->createProgessMainview(); $progressMainview = $this->createProgessMainview();

@ -43,7 +43,7 @@ class Login extends \View {
<div class=\"alert alert-danger hidden\" role=\"alert\" id=\"loginError\"></div> <div class=\"alert alert-danger hidden\" role=\"alert\" id=\"loginError\"></div>
</form> </form>
<span class=\"subtitle flags-container\"><span class=\"flags\">$flags</span></span> <span class=\"subtitle flags-container\"><span class=\"flags\">$flags</span></span>
<span class=\"subtitle\"><a class=\"link\" href=\"$protocol://$domain\">$iconBack$backToStartPage</a></span> <span class=\"subtitle\"><a class=\"link\" href=\"$protocol://$domain\">$iconBack&nbsp;$backToStartPage</a></span>
$accountCreated $accountCreated
</div> </div>
</div>"; </div>";

@ -25,7 +25,7 @@
} }
function getProtocol() { function getProtocol() {
return stripos($_SERVER['SERVER_PROTOCOL'],'https') === 0 ? 'https://' : 'http://'; return stripos($_SERVER['SERVER_PROTOCOL'],'https') === 0 ? 'https' : 'http';
} }
function includeDir($dir, $aIgnore = array(), $recursive = false) { function includeDir($dir, $aIgnore = array(), $recursive = false) {

@ -41,14 +41,19 @@ if(isset($_GET["api"]) && is_string($_GET["api"])) {
header("403 Forbidden"); header("403 Forbidden");
$response = ""; $response = "";
} else if(!preg_match("/[a-zA-Z]+(\/[a-zA-Z]+)*/", $apiFunction)) { } else if(!preg_match("/[a-zA-Z]+(\/[a-zA-Z]+)*/", $apiFunction)) {
header("400 Bad Request");
$response = createError("Invalid Method"); $response = createError("Invalid Method");
} else { } else {
$apiFunction = strtoupper($apiFunction[0]) . substr($apiFunction, 1); $apiFunction = strtoupper($apiFunction[0]) . substr($apiFunction, 1);
$apiFunction = str_replace("/", "\\", $apiFunction);
$class = "\\Api\\$apiFunction"; $class = "\\Api\\$apiFunction";
$file = getClassPath($class); $file = getClassPath($class);
if(!file_exists($file)) { if(!file_exists($file)) {
header("404 Not Found"); header("404 Not Found");
$response = createError("Not found"); $response = createError("Not found");
} else if(!is_subclass_of($class, \Api\Request::class)) {
header("400 Bad Request");
$response = createError("Inalid Method");
} else { } else {
$request = new $class($user, true); $request = new $class($user, true);
$success = $request->execute(); $success = $request->execute();