v2.0-alpha
This commit is contained in:
@@ -3,15 +3,20 @@
|
||||
namespace Api {
|
||||
|
||||
use Driver\SQL\Condition\Compare;
|
||||
use Objects\Context;
|
||||
|
||||
abstract class ApiKeyAPI extends Request {
|
||||
|
||||
protected function apiKeyExists($id): bool {
|
||||
$sql = $this->user->getSQL();
|
||||
public function __construct(Context $context, bool $externalCall = false, array $params = array()) {
|
||||
parent::__construct($context, $externalCall, $params);
|
||||
}
|
||||
|
||||
protected function apiKeyExists(int $id): bool {
|
||||
$sql = $this->context->getSQL();
|
||||
$res = $sql->select($sql->count())
|
||||
->from("ApiKey")
|
||||
->where(new Compare("uid", $id))
|
||||
->where(new Compare("user_id", $this->user->getId()))
|
||||
->where(new Compare("id", $id))
|
||||
->where(new Compare("user_id", $this->context->getUser()->getId()))
|
||||
->where(new Compare("valid_until", $sql->currentTimestamp(), ">"))
|
||||
->where(new Compare("active", 1))
|
||||
->execute();
|
||||
@@ -32,37 +37,32 @@ namespace Api\ApiKey {
|
||||
|
||||
use Api\ApiKeyAPI;
|
||||
use Api\Parameter\Parameter;
|
||||
use Api\Request;
|
||||
use DateTime;
|
||||
use Driver\SQL\Condition\Compare;
|
||||
use Exception;
|
||||
use Driver\SQL\Condition\CondAnd;
|
||||
use Objects\Context;
|
||||
use Objects\DatabaseEntity\ApiKey;
|
||||
|
||||
class Create extends ApiKeyAPI {
|
||||
|
||||
public function __construct($user, $externalCall = false) {
|
||||
parent::__construct($user, $externalCall, array());
|
||||
public function __construct(Context $context, $externalCall = false) {
|
||||
parent::__construct($context, $externalCall, array());
|
||||
$this->apiKeyAllowed = false;
|
||||
$this->loginRequired = true;
|
||||
}
|
||||
|
||||
public function _execute(): bool {
|
||||
$apiKey = generateRandomString(64);
|
||||
$sql = $this->user->getSQL();
|
||||
$validUntil = (new \DateTime())->modify("+30 DAY");
|
||||
$sql = $this->context->getSQL();
|
||||
|
||||
$this->success = $sql->insert("ApiKey", array("user_id", "api_key", "valid_until"))
|
||||
->addRow($this->user->getId(), $apiKey, $validUntil)
|
||||
->returning("uid")
|
||||
->execute();
|
||||
$apiKey = new ApiKey();
|
||||
$apiKey->apiKey = generateRandomString(64);
|
||||
$apiKey->validUntil = (new \DateTime())->modify("+30 DAY");
|
||||
$apiKey->user = $this->context->getUser();
|
||||
|
||||
$this->success = $apiKey->save($sql);
|
||||
$this->lastError = $sql->getLastError();
|
||||
|
||||
if ($this->success) {
|
||||
$this->result["api_key"] = array(
|
||||
"api_key" => $apiKey,
|
||||
"valid_until" => $validUntil->format("Y-m-d H:i:s"),
|
||||
"uid" => $sql->getLastInsertId(),
|
||||
);
|
||||
$this->result["api_key"] = $apiKey->jsonSerialize();
|
||||
}
|
||||
|
||||
return $this->success;
|
||||
@@ -71,39 +71,33 @@ namespace Api\ApiKey {
|
||||
|
||||
class Fetch extends ApiKeyAPI {
|
||||
|
||||
public function __construct($user, $externalCall = false) {
|
||||
parent::__construct($user, $externalCall, array(
|
||||
public function __construct(Context $context, $externalCall = false) {
|
||||
parent::__construct($context, $externalCall, array(
|
||||
"showActiveOnly" => new Parameter("showActiveOnly", Parameter::TYPE_BOOLEAN, true, true)
|
||||
));
|
||||
$this->loginRequired = true;
|
||||
}
|
||||
|
||||
public function _execute(): bool {
|
||||
$sql = $this->user->getSQL();
|
||||
$query = $sql->select("uid", "api_key", "valid_until", "active")
|
||||
->from("ApiKey")
|
||||
->where(new Compare("user_id", $this->user->getId()));
|
||||
$sql = $this->context->getSQL();
|
||||
|
||||
$condition = new Compare("user_id", $this->context->getUser()->getId());
|
||||
if ($this->getParam("showActiveOnly")) {
|
||||
$query->where(new Compare("valid_until", $sql->currentTimestamp(), ">"))
|
||||
->where(new Compare("active", true));
|
||||
$condition = new CondAnd(
|
||||
$condition,
|
||||
new Compare("valid_until", $sql->currentTimestamp(), ">"),
|
||||
new Compare("active", true)
|
||||
);
|
||||
}
|
||||
|
||||
$res = $query->execute();
|
||||
|
||||
$this->success = ($res !== FALSE);
|
||||
$apiKeys = ApiKey::findAll($sql, $condition);
|
||||
$this->success = ($apiKeys !== FALSE);
|
||||
$this->lastError = $sql->getLastError();
|
||||
|
||||
if($this->success) {
|
||||
if ($this->success) {
|
||||
$this->result["api_keys"] = array();
|
||||
foreach($res as $row) {
|
||||
$apiKeyId = intval($row["uid"]);
|
||||
$this->result["api_keys"][$apiKeyId] = array(
|
||||
"id" => $apiKeyId,
|
||||
"api_key" => $row["api_key"],
|
||||
"valid_until" => $row["valid_until"],
|
||||
"revoked" => !$sql->parseBool($row["active"])
|
||||
);
|
||||
foreach($apiKeys as $apiKey) {
|
||||
$this->result["api_keys"][$apiKey->getId()] = $apiKey->jsonSerialize();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -113,8 +107,8 @@ namespace Api\ApiKey {
|
||||
|
||||
class Refresh extends ApiKeyAPI {
|
||||
|
||||
public function __construct($user, $externalCall = false) {
|
||||
parent::__construct($user, $externalCall, array(
|
||||
public function __construct(Context $context, $externalCall = false) {
|
||||
parent::__construct($context, $externalCall, array(
|
||||
"id" => new Parameter("id", Parameter::TYPE_INT),
|
||||
));
|
||||
$this->loginRequired = true;
|
||||
@@ -122,15 +116,16 @@ namespace Api\ApiKey {
|
||||
|
||||
public function _execute(): bool {
|
||||
$id = $this->getParam("id");
|
||||
if(!$this->apiKeyExists($id))
|
||||
if (!$this->apiKeyExists($id)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$validUntil = (new \DateTime)->modify("+30 DAY");
|
||||
$sql = $this->user->getSQL();
|
||||
$sql = $this->context->getSQL();
|
||||
$this->success = $sql->update("ApiKey")
|
||||
->set("valid_until", $validUntil)
|
||||
->where(new Compare("uid", $id))
|
||||
->where(new Compare("user_id", $this->user->getId()))
|
||||
->where(new Compare("id", $id))
|
||||
->where(new Compare("user_id", $this->context->getUser()->getId()))
|
||||
->execute();
|
||||
$this->lastError = $sql->getLastError();
|
||||
|
||||
@@ -153,20 +148,19 @@ namespace Api\ApiKey {
|
||||
|
||||
public function _execute(): bool {
|
||||
$id = $this->getParam("id");
|
||||
if (!$this->apiKeyExists($id))
|
||||
if (!$this->apiKeyExists($id)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$sql = $this->user->getSQL();
|
||||
$sql = $this->context->getSQL();
|
||||
$this->success = $sql->update("ApiKey")
|
||||
->set("active", false)
|
||||
->where(new Compare("uid", $id))
|
||||
->where(new Compare("user_id", $this->user->getId()))
|
||||
->where(new Compare("id", $id))
|
||||
->where(new Compare("user_id", $this->context->getUser()->getId()))
|
||||
->execute();
|
||||
$this->lastError = $sql->getLastError();
|
||||
|
||||
return $this->success;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -2,21 +2,20 @@
|
||||
|
||||
namespace Api {
|
||||
|
||||
use Objects\User;
|
||||
use Objects\Context;
|
||||
|
||||
abstract class ContactAPI extends Request {
|
||||
|
||||
protected ?string $messageId;
|
||||
|
||||
public function __construct(User $user, bool $externalCall, array $params) {
|
||||
parent::__construct($user, $externalCall, $params);
|
||||
public function __construct(Context $context, bool $externalCall, array $params) {
|
||||
parent::__construct($context, $externalCall, $params);
|
||||
$this->messageId = null;
|
||||
$this->csrfTokenRequired = false;
|
||||
|
||||
}
|
||||
|
||||
protected function sendMail(string $name, ?string $fromEmail, string $subject, string $message, ?string $to = null): bool {
|
||||
$request = new \Api\Mail\Send($this->user);
|
||||
$request = new \Api\Mail\Send($this->context);
|
||||
$this->success = $request->execute(array(
|
||||
"subject" => $subject,
|
||||
"body" => $message,
|
||||
@@ -45,30 +44,30 @@ namespace Api\Contact {
|
||||
use Driver\SQL\Condition\CondNot;
|
||||
use Driver\SQL\Expression\CaseWhen;
|
||||
use Driver\SQL\Expression\Sum;
|
||||
use Objects\User;
|
||||
use Objects\Context;
|
||||
|
||||
class Request extends ContactAPI {
|
||||
|
||||
public function __construct(User $user, bool $externalCall = false) {
|
||||
public function __construct(Context $context, bool $externalCall = false) {
|
||||
$parameters = array(
|
||||
'fromName' => new StringType('fromName', 32),
|
||||
'fromEmail' => new Parameter('fromEmail', Parameter::TYPE_EMAIL),
|
||||
'message' => new StringType('message', 512),
|
||||
);
|
||||
|
||||
$settings = $user->getConfiguration()->getSettings();
|
||||
$settings = $context->getSettings();
|
||||
if ($settings->isRecaptchaEnabled()) {
|
||||
$parameters["captcha"] = new StringType("captcha");
|
||||
}
|
||||
|
||||
parent::__construct($user, $externalCall, $parameters);
|
||||
parent::__construct($context, $externalCall, $parameters);
|
||||
}
|
||||
|
||||
public function _execute(): bool {
|
||||
$settings = $this->user->getConfiguration()->getSettings();
|
||||
$settings = $this->context->getSettings();
|
||||
if ($settings->isRecaptchaEnabled()) {
|
||||
$captcha = $this->getParam("captcha");
|
||||
$req = new VerifyCaptcha($this->user);
|
||||
$req = new VerifyCaptcha($this->context);
|
||||
if (!$req->execute(array("captcha" => $captcha, "action" => "contact"))) {
|
||||
return $this->createError($req->getLastError());
|
||||
}
|
||||
@@ -80,23 +79,7 @@ namespace Api\Contact {
|
||||
$email = $this->getParam("fromEmail");
|
||||
|
||||
$sendMail = $this->sendMail($name, $email, "Contact Request", $message);
|
||||
$mailError = $this->getLastError();
|
||||
|
||||
$insertDB = $this->insertContactRequest();
|
||||
$dbError = $this->getLastError();
|
||||
|
||||
// Create a log entry
|
||||
if (!$sendMail || $mailError) {
|
||||
$message = "Error processing contact request.";
|
||||
if (!$sendMail) {
|
||||
$message .= " Mail: $mailError";
|
||||
}
|
||||
|
||||
if (!$insertDB) {
|
||||
$message .= " Mail: $dbError";
|
||||
}
|
||||
}
|
||||
|
||||
if (!$sendMail && !$insertDB) {
|
||||
return $this->createError("The contact request could not be sent. The Administrator is already informed. Please try again later.");
|
||||
}
|
||||
@@ -105,7 +88,7 @@ namespace Api\Contact {
|
||||
}
|
||||
|
||||
private function insertContactRequest(): bool {
|
||||
$sql = $this->user->getSQL();
|
||||
$sql = $this->context->getSQL();
|
||||
$name = $this->getParam("fromName");
|
||||
$email = $this->getParam("fromEmail");
|
||||
$message = $this->getParam("message");
|
||||
@@ -113,7 +96,7 @@ namespace Api\Contact {
|
||||
|
||||
$res = $sql->insert("ContactRequest", array("from_name", "from_email", "message", "messageId"))
|
||||
->addRow($name, $email, $message, $messageId)
|
||||
->returning("uid")
|
||||
->returning("id")
|
||||
->execute();
|
||||
|
||||
$this->success = ($res !== FALSE);
|
||||
@@ -124,21 +107,20 @@ namespace Api\Contact {
|
||||
|
||||
class Respond extends ContactAPI {
|
||||
|
||||
public function __construct(User $user, bool $externalCall = false) {
|
||||
parent::__construct($user, $externalCall, array(
|
||||
public function __construct(Context $context, bool $externalCall = false) {
|
||||
parent::__construct($context, $externalCall, array(
|
||||
"requestId" => new Parameter("requestId", Parameter::TYPE_INT),
|
||||
'message' => new StringType('message', 512),
|
||||
));
|
||||
$this->loginRequired = true;
|
||||
$this->csrfTokenRequired = false;
|
||||
}
|
||||
|
||||
private function getSenderMail(): ?string {
|
||||
$requestId = $this->getParam("requestId");
|
||||
$sql = $this->user->getSQL();
|
||||
$sql = $this->context->getSQL();
|
||||
$res = $sql->select("from_email")
|
||||
->from("ContactRequest")
|
||||
->where(new Compare("uid", $requestId))
|
||||
->where(new Compare("id", $requestId))
|
||||
->execute();
|
||||
|
||||
$this->success = ($res !== false);
|
||||
@@ -156,12 +138,12 @@ namespace Api\Contact {
|
||||
}
|
||||
|
||||
private function insertResponseMessage(): bool {
|
||||
$sql = $this->user->getSQL();
|
||||
$sql = $this->context->getSQL();
|
||||
$message = $this->getParam("message");
|
||||
$requestId = $this->getParam("requestId");
|
||||
|
||||
$this->success = $sql->insert("ContactMessage", ["request_id", "user_id", "message", "messageId", "read"])
|
||||
->addRow($requestId, $this->user->getId(), $message, $this->messageId, true)
|
||||
->addRow($requestId, $this->context->getUser()->getId(), $message, $this->messageId, true)
|
||||
->execute();
|
||||
|
||||
$this->lastError = $sql->getLastError();
|
||||
@@ -169,7 +151,7 @@ namespace Api\Contact {
|
||||
}
|
||||
|
||||
private function updateEntity() {
|
||||
$sql = $this->user->getSQL();
|
||||
$sql = $this->context->getSQL();
|
||||
$requestId = $this->getParam("requestId");
|
||||
|
||||
$sql->update("EntityLog")
|
||||
@@ -185,8 +167,9 @@ namespace Api\Contact {
|
||||
return false;
|
||||
}
|
||||
|
||||
$fromName = $this->user->getUsername();
|
||||
$fromEmail = $this->user->getEmail();
|
||||
$user = $this->context->getUser();
|
||||
$fromName = $user->getUsername();
|
||||
$fromEmail = $user->getEmail();
|
||||
|
||||
if (!$this->sendMail($fromName, $fromEmail, "Re: Contact Request", $message, $senderMail)) {
|
||||
return false;
|
||||
@@ -203,19 +186,19 @@ namespace Api\Contact {
|
||||
|
||||
class Fetch extends ContactAPI {
|
||||
|
||||
public function __construct(User $user, bool $externalCall = false) {
|
||||
parent::__construct($user, $externalCall, array());
|
||||
public function __construct(Context $context, bool $externalCall = false) {
|
||||
parent::__construct($context, $externalCall, array());
|
||||
$this->loginRequired = true;
|
||||
$this->csrfTokenRequired = false;
|
||||
}
|
||||
|
||||
public function _execute(): bool {
|
||||
$sql = $this->user->getSQL();
|
||||
$res = $sql->select("ContactRequest.uid", "from_name", "from_email", "from_name",
|
||||
$sql = $this->context->getSQL();
|
||||
$res = $sql->select("ContactRequest.id", "from_name", "from_email", "from_name",
|
||||
new Sum(new CaseWhen(new CondNot("ContactMessage.read"), 1, 0), "unread"))
|
||||
->from("ContactRequest")
|
||||
->groupBy("ContactRequest.uid")
|
||||
->leftJoin("ContactMessage", "ContactRequest.uid", "ContactMessage.request_id")
|
||||
->groupBy("ContactRequest.id")
|
||||
->leftJoin("ContactMessage", "ContactRequest.id", "ContactMessage.request_id")
|
||||
->execute();
|
||||
|
||||
$this->success = ($res !== false);
|
||||
@@ -225,7 +208,7 @@ namespace Api\Contact {
|
||||
$this->result["contactRequests"] = [];
|
||||
foreach ($res as $row) {
|
||||
$this->result["contactRequests"][] = array(
|
||||
"uid" => intval($row["uid"]),
|
||||
"id" => intval($row["id"]),
|
||||
"from_name" => $row["from_name"],
|
||||
"from_email" => $row["from_email"],
|
||||
"unread" => intval($row["unread"]),
|
||||
@@ -239,8 +222,8 @@ namespace Api\Contact {
|
||||
|
||||
class Get extends ContactAPI {
|
||||
|
||||
public function __construct(User $user, bool $externalCall = false) {
|
||||
parent::__construct($user, $externalCall, array(
|
||||
public function __construct(Context $context, bool $externalCall = false) {
|
||||
parent::__construct($context, $externalCall, array(
|
||||
"requestId" => new Parameter("requestId", Parameter::TYPE_INT),
|
||||
));
|
||||
$this->loginRequired = true;
|
||||
@@ -249,7 +232,7 @@ namespace Api\Contact {
|
||||
|
||||
private function updateRead() {
|
||||
$requestId = $this->getParam("requestId");
|
||||
$sql = $this->user->getSQL();
|
||||
$sql = $this->context->getSQL();
|
||||
$sql->update("ContactMessage")
|
||||
->set("read", 1)
|
||||
->where(new Compare("request_id", $requestId))
|
||||
@@ -258,11 +241,11 @@ namespace Api\Contact {
|
||||
|
||||
public function _execute(): bool {
|
||||
$requestId = $this->getParam("requestId");
|
||||
$sql = $this->user->getSQL();
|
||||
$sql = $this->context->getSQL();
|
||||
|
||||
$res = $sql->select("from_name", "from_email", "message", "created_at")
|
||||
->from("ContactRequest")
|
||||
->where(new Compare("uid", $requestId))
|
||||
->where(new Compare("id", $requestId))
|
||||
->execute();
|
||||
|
||||
$this->success = ($res !== false);
|
||||
|
||||
@@ -3,11 +3,16 @@
|
||||
namespace Api {
|
||||
|
||||
use Driver\SQL\Condition\Compare;
|
||||
use Objects\Context;
|
||||
|
||||
abstract class GroupsAPI extends Request {
|
||||
|
||||
protected function groupExists($name) {
|
||||
$sql = $this->user->getSQL();
|
||||
public function __construct(Context $context, bool $externalCall = false, array $params = array()) {
|
||||
parent::__construct($context, $externalCall, $params);
|
||||
}
|
||||
|
||||
protected function groupExists($name): bool {
|
||||
$sql = $this->context->getSQL();
|
||||
$res = $sql->select($sql->count())
|
||||
->from("Group")
|
||||
->where(new Compare("name", $name))
|
||||
@@ -25,14 +30,15 @@ namespace Api\Groups {
|
||||
use Api\GroupsAPI;
|
||||
use Api\Parameter\Parameter;
|
||||
use Api\Parameter\StringType;
|
||||
use Driver\SQL\Condition\Compare;
|
||||
use Objects\Context;
|
||||
use Objects\DatabaseEntity\Group;
|
||||
|
||||
class Fetch extends GroupsAPI {
|
||||
|
||||
private int $groupCount;
|
||||
|
||||
public function __construct($user, $externalCall = false) {
|
||||
parent::__construct($user, $externalCall, array(
|
||||
public function __construct(Context $context, $externalCall = false) {
|
||||
parent::__construct($context, $externalCall, array(
|
||||
'page' => new Parameter('page', Parameter::TYPE_INT, true, 1),
|
||||
'count' => new Parameter('count', Parameter::TYPE_INT, true, 20)
|
||||
));
|
||||
@@ -40,9 +46,9 @@ namespace Api\Groups {
|
||||
$this->groupCount = 0;
|
||||
}
|
||||
|
||||
private function getGroupCount() {
|
||||
private function fetchGroupCount(): bool {
|
||||
|
||||
$sql = $this->user->getSQL();
|
||||
$sql = $this->context->getSQL();
|
||||
$res = $sql->select($sql->count())->from("Group")->execute();
|
||||
$this->success = ($res !== FALSE);
|
||||
$this->lastError = $sql->getLastError();
|
||||
@@ -65,16 +71,16 @@ namespace Api\Groups {
|
||||
return $this->createError("Invalid fetch count");
|
||||
}
|
||||
|
||||
if (!$this->getGroupCount()) {
|
||||
if (!$this->fetchGroupCount()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$sql = $this->user->getSQL();
|
||||
$res = $sql->select("Group.uid as groupId", "Group.name as groupName", "Group.color as groupColor", $sql->count("UserGroup.user_id"))
|
||||
$sql = $this->context->getSQL();
|
||||
$res = $sql->select("Group.id as groupId", "Group.name as groupName", "Group.color as groupColor", $sql->count("UserGroup.user_id"))
|
||||
->from("Group")
|
||||
->leftJoin("UserGroup", "UserGroup.group_id", "Group.uid")
|
||||
->groupBy("Group.uid")
|
||||
->orderBy("Group.uid")
|
||||
->leftJoin("UserGroup", "UserGroup.group_id", "Group.id")
|
||||
->groupBy("Group.id")
|
||||
->orderBy("Group.id")
|
||||
->ascending()
|
||||
->limit($count)
|
||||
->offset(($page - 1) * $count)
|
||||
@@ -105,8 +111,8 @@ namespace Api\Groups {
|
||||
}
|
||||
|
||||
class Create extends GroupsAPI {
|
||||
public function __construct($user, $externalCall = false) {
|
||||
parent::__construct($user, $externalCall, array(
|
||||
public function __construct(Context $context, $externalCall = false) {
|
||||
parent::__construct($context, $externalCall, array(
|
||||
'name' => new StringType('name', 32),
|
||||
'color' => new StringType('color', 10),
|
||||
));
|
||||
@@ -130,17 +136,17 @@ namespace Api\Groups {
|
||||
return $this->createError("A group with this name already exists");
|
||||
}
|
||||
|
||||
$sql = $this->user->getSQL();
|
||||
$res = $sql->insert("Group", array("name", "color"))
|
||||
->addRow($name, $color)
|
||||
->returning("uid")
|
||||
->execute();
|
||||
$sql = $this->context->getSQL();
|
||||
|
||||
$this->success = ($res !== FALSE);
|
||||
$group = new Group();
|
||||
$group->name = $name;
|
||||
$group->color = $color;
|
||||
|
||||
$this->success = ($group->save($sql) !== FALSE);
|
||||
$this->lastError = $sql->getLastError();
|
||||
|
||||
if ($this->success) {
|
||||
$this->result["uid"] = $sql->getLastInsertId();
|
||||
$this->result["id"] = $group->getId();
|
||||
}
|
||||
|
||||
return $this->success;
|
||||
@@ -148,33 +154,29 @@ namespace Api\Groups {
|
||||
}
|
||||
|
||||
class Delete extends GroupsAPI {
|
||||
public function __construct($user, $externalCall = false) {
|
||||
parent::__construct($user, $externalCall, array(
|
||||
'uid' => new Parameter('uid', Parameter::TYPE_INT)
|
||||
public function __construct(Context $context, $externalCall = false) {
|
||||
parent::__construct($context, $externalCall, array(
|
||||
'id' => new Parameter('id', Parameter::TYPE_INT)
|
||||
));
|
||||
}
|
||||
|
||||
public function _execute(): bool {
|
||||
$id = $this->getParam("uid");
|
||||
$id = $this->getParam("id");
|
||||
if (in_array($id, DEFAULT_GROUPS)) {
|
||||
return $this->createError("You cannot delete a default group.");
|
||||
}
|
||||
|
||||
$sql = $this->user->getSQL();
|
||||
$res = $sql->select($sql->count())
|
||||
->from("Group")
|
||||
->where(new Compare("uid", $id))
|
||||
->execute();
|
||||
$sql = $this->context->getSQL();
|
||||
$group = Group::find($sql, $id);
|
||||
|
||||
$this->success = ($res !== FALSE);
|
||||
$this->success = ($group !== FALSE);
|
||||
$this->lastError = $sql->getLastError();
|
||||
|
||||
if ($this->success && $res[0]["count"] === 0) {
|
||||
if ($this->success && $group === null) {
|
||||
return $this->createError("This group does not exist.");
|
||||
}
|
||||
|
||||
$res = $sql->delete("Group")->where(new Compare("uid", $id))->execute();
|
||||
$this->success = ($res !== FALSE);
|
||||
$this->success = ($group->delete($sql) !== FALSE);
|
||||
$this->lastError = $sql->getLastError();
|
||||
return $this->success;
|
||||
}
|
||||
|
||||
@@ -2,10 +2,13 @@
|
||||
|
||||
namespace Api {
|
||||
|
||||
use Objects\Context;
|
||||
|
||||
abstract class LanguageAPI extends Request {
|
||||
|
||||
public function __construct(Context $context, bool $externalCall = false, array $params = array()) {
|
||||
parent::__construct($context, $externalCall, $params);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
namespace Api\Language {
|
||||
@@ -15,30 +18,28 @@ namespace Api\Language {
|
||||
use Api\Parameter\StringType;
|
||||
use Driver\SQL\Condition\Compare;
|
||||
use Driver\SQL\Condition\CondOr;
|
||||
use Objects\Language;
|
||||
use Objects\Context;
|
||||
use Objects\DatabaseEntity\Language;
|
||||
|
||||
class Get extends LanguageAPI {
|
||||
|
||||
public function __construct($user, $externalCall = false) {
|
||||
parent::__construct($user, $externalCall, array());
|
||||
public function __construct(Context $context, $externalCall = false) {
|
||||
parent::__construct($context, $externalCall, array());
|
||||
}
|
||||
|
||||
public function _execute(): bool {
|
||||
$sql = $this->user->getSQL();
|
||||
$res = $sql->select("uid", "code", "name")
|
||||
->from("Language")
|
||||
->execute();
|
||||
|
||||
$this->success = ($res !== FALSE);
|
||||
$sql = $this->context->getSQL();
|
||||
$languages = Language::findAll($sql);
|
||||
$this->success = ($languages !== null);
|
||||
$this->lastError = $sql->getLastError();
|
||||
|
||||
if($this->success) {
|
||||
$this->result['languages'] = array();
|
||||
if(empty($res) === 0) {
|
||||
if ($this->success) {
|
||||
$this->result['languages'] = [];
|
||||
if (count($languages) === 0) {
|
||||
$this->lastError = L("No languages found");
|
||||
} else {
|
||||
foreach($res as $row) {
|
||||
$this->result['languages'][$row['uid']] = $row;
|
||||
foreach ($languages as $language) {
|
||||
$this->result['languages'][$language->getId()] = $language->jsonSerialize();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -51,70 +52,65 @@ namespace Api\Language {
|
||||
|
||||
private Language $language;
|
||||
|
||||
public function __construct($user, $externalCall = false) {
|
||||
parent::__construct($user, $externalCall, array(
|
||||
public function __construct(Context $context, $externalCall = false) {
|
||||
parent::__construct($context, $externalCall, array(
|
||||
'langId' => new Parameter('langId', Parameter::TYPE_INT, true, NULL),
|
||||
'langCode' => new StringType('langCode', 5, true, NULL),
|
||||
));
|
||||
|
||||
}
|
||||
|
||||
private function checkLanguage() {
|
||||
private function checkLanguage(): bool {
|
||||
$langId = $this->getParam("langId");
|
||||
$langCode = $this->getParam("langCode");
|
||||
|
||||
if(is_null($langId) && is_null($langCode)) {
|
||||
if (is_null($langId) && is_null($langCode)) {
|
||||
return $this->createError(L("Either langId or langCode must be given"));
|
||||
}
|
||||
|
||||
$res = $this->user->getSQL()
|
||||
->select("uid", "code", "name")
|
||||
->from("Language")
|
||||
->where(new CondOr(new Compare("uid", $langId), new Compare("code", $langCode)))
|
||||
->execute();
|
||||
$sql = $this->context->getSQL();
|
||||
$languages = Language::findAll($sql,
|
||||
new CondOr(new Compare("id", $langId), new Compare("code", $langCode))
|
||||
);
|
||||
|
||||
$this->success = ($res !== FALSE);
|
||||
$this->lastError = $this->user->getSQL()->getLastError();
|
||||
$this->success = ($languages !== null);
|
||||
$this->lastError = $sql->getLastError();
|
||||
|
||||
if ($this->success) {
|
||||
if(count($res) == 0) {
|
||||
if (count($languages) === 0) {
|
||||
return $this->createError(L("This Language does not exist"));
|
||||
} else {
|
||||
$row = $res[0];
|
||||
$this->language = Language::newInstance($row['uid'], $row['code'], $row['name']);
|
||||
if(!$this->language) {
|
||||
return $this->createError(L("Error while loading language"));
|
||||
}
|
||||
$this->language = array_shift($languages);
|
||||
}
|
||||
}
|
||||
|
||||
return $this->success;
|
||||
}
|
||||
|
||||
private function updateLanguage() {
|
||||
private function updateLanguage(): bool {
|
||||
$languageId = $this->language->getId();
|
||||
$userId = $this->user->getId();
|
||||
$sql = $this->user->getSQL();
|
||||
$userId = $this->context->getUser()->getId();
|
||||
$sql = $this->context->getSQL();
|
||||
|
||||
$this->success = $sql->update("User")
|
||||
->set("language_id", $languageId)
|
||||
->where(new Compare("uid", $userId))
|
||||
->where(new Compare("id", $userId))
|
||||
->execute();
|
||||
|
||||
$this->lastError = $sql->getLastError();
|
||||
return $this->success;
|
||||
}
|
||||
|
||||
public function _execute(): bool {
|
||||
if(!$this->checkLanguage())
|
||||
if (!$this->checkLanguage())
|
||||
return false;
|
||||
|
||||
if($this->user->isLoggedIn()) {
|
||||
if ($this->context->getSession()) {
|
||||
$this->updateLanguage();
|
||||
}
|
||||
|
||||
$this->user->setLanguage($this->language);
|
||||
$this->context->setLanguage($this->language);
|
||||
return $this->success;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -2,11 +2,11 @@
|
||||
|
||||
namespace Api {
|
||||
|
||||
use Objects\User;
|
||||
use Objects\Context;
|
||||
|
||||
abstract class LogsAPI extends Request {
|
||||
public function __construct(User $user, bool $externalCall = false, array $params = array()) {
|
||||
parent::__construct($user, $externalCall, $params);
|
||||
public function __construct(Context $context, bool $externalCall = false, array $params = array()) {
|
||||
parent::__construct($context, $externalCall, $params);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,20 +21,22 @@ namespace Api\Logs {
|
||||
use Driver\SQL\Column\Column;
|
||||
use Driver\SQL\Condition\Compare;
|
||||
use Driver\SQL\Condition\CondIn;
|
||||
use Objects\User;
|
||||
use Objects\Context;
|
||||
use Objects\DatabaseEntity\SystemLog;
|
||||
|
||||
class Get extends LogsAPI {
|
||||
|
||||
public function __construct(User $user, bool $externalCall = false) {
|
||||
parent::__construct($user, $externalCall, [
|
||||
public function __construct(Context $context, bool $externalCall = false) {
|
||||
parent::__construct($context, $externalCall, [
|
||||
"since" => new Parameter("since", Parameter::TYPE_DATE_TIME, true),
|
||||
"severity" => new StringType("severity", 32, true, "debug")
|
||||
]);
|
||||
$this->csrfTokenRequired = false;
|
||||
}
|
||||
|
||||
protected function _execute(): bool {
|
||||
$since = $this->getParam("since");
|
||||
$sql = $this->user->getSQL();
|
||||
$sql = $this->context->getSQL();
|
||||
$severity = strtolower(trim($this->getParam("severity")));
|
||||
$shownLogLevels = Logger::LOG_LEVELS;
|
||||
|
||||
@@ -45,8 +47,7 @@ namespace Api\Logs {
|
||||
$shownLogLevels = array_slice(Logger::LOG_LEVELS, $logLevel);
|
||||
}
|
||||
|
||||
$query = $sql->select("id", "module", "message", "severity", "timestamp")
|
||||
->from("SystemLog")
|
||||
$query = SystemLog::findAllBuilder($sql)
|
||||
->orderBy("timestamp")
|
||||
->descending();
|
||||
|
||||
@@ -58,12 +59,15 @@ namespace Api\Logs {
|
||||
$query->where(new CondIn(new Column("severity"), $shownLogLevels));
|
||||
}
|
||||
|
||||
$res = $query->execute();
|
||||
$this->success = $res !== false;
|
||||
$logEntries = $query->execute();
|
||||
$this->success = $logEntries !== false;
|
||||
$this->lastError = $sql->getLastError();
|
||||
|
||||
if ($this->success) {
|
||||
$this->result["logs"] = $res;
|
||||
$this->result["logs"] = [];
|
||||
foreach ($logEntries as $logEntry) {
|
||||
$this->result["logs"][] = $logEntry->jsonSerialize();
|
||||
}
|
||||
} else {
|
||||
// we couldn't fetch logs from database, return a message and proceed to log files
|
||||
$this->result["logs"] = [
|
||||
|
||||
@@ -3,10 +3,16 @@
|
||||
namespace Api {
|
||||
|
||||
use Objects\ConnectionData;
|
||||
use Objects\Context;
|
||||
|
||||
abstract class MailAPI extends Request {
|
||||
|
||||
public function __construct(Context $context, bool $externalCall = false, array $params = array()) {
|
||||
parent::__construct($context, $externalCall, $params);
|
||||
}
|
||||
|
||||
protected function getMailConfig(): ?ConnectionData {
|
||||
$req = new \Api\Settings\Get($this->user);
|
||||
$req = new \Api\Settings\Get($this->context);
|
||||
$this->success = $req->execute(array("key" => "^mail_"));
|
||||
$this->lastError = $req->getLastError();
|
||||
|
||||
@@ -47,13 +53,13 @@ namespace Api\Mail {
|
||||
use External\PHPMailer\Exception;
|
||||
use External\PHPMailer\PHPMailer;
|
||||
use Objects\ConnectionData;
|
||||
use Objects\GpgKey;
|
||||
use Objects\User;
|
||||
use Objects\Context;
|
||||
use Objects\DatabaseEntity\GpgKey;
|
||||
|
||||
class Test extends MailAPI {
|
||||
|
||||
public function __construct(User $user, bool $externalCall = false) {
|
||||
parent::__construct($user, $externalCall, array(
|
||||
public function __construct(Context $context, bool $externalCall = false) {
|
||||
parent::__construct($context, $externalCall, array(
|
||||
"receiver" => new Parameter("receiver", Parameter::TYPE_EMAIL),
|
||||
"gpgFingerprint" => new StringType("gpgFingerprint", 64, true, null)
|
||||
));
|
||||
@@ -62,7 +68,7 @@ namespace Api\Mail {
|
||||
public function _execute(): bool {
|
||||
|
||||
$receiver = $this->getParam("receiver");
|
||||
$req = new \Api\Mail\Send($this->user);
|
||||
$req = new \Api\Mail\Send($this->context);
|
||||
$this->success = $req->execute(array(
|
||||
"to" => $receiver,
|
||||
"subject" => "Test E-Mail",
|
||||
@@ -76,16 +82,15 @@ namespace Api\Mail {
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: expired gpg keys?
|
||||
class Send extends MailAPI {
|
||||
public function __construct($user, $externalCall = false) {
|
||||
parent::__construct($user, $externalCall, array(
|
||||
public function __construct(Context $context, $externalCall = false) {
|
||||
parent::__construct($context, $externalCall, array(
|
||||
'to' => new Parameter('to', Parameter::TYPE_EMAIL, true, null),
|
||||
'subject' => new StringType('subject', -1),
|
||||
'body' => new StringType('body', -1),
|
||||
'replyTo' => new Parameter('replyTo', Parameter::TYPE_EMAIL, true, null),
|
||||
'replyName' => new StringType('replyName', 32, true, ""),
|
||||
"gpgFingerprint" => new StringType("gpgFingerprint", 64, true, null),
|
||||
'gpgFingerprint' => new StringType("gpgFingerprint", 64, true, null),
|
||||
'async' => new Parameter("async", Parameter::TYPE_BOOLEAN, true, true)
|
||||
));
|
||||
$this->isPublic = false;
|
||||
@@ -108,7 +113,7 @@ namespace Api\Mail {
|
||||
$gpgFingerprint = $this->getParam("gpgFingerprint");
|
||||
|
||||
if ($this->getParam("async")) {
|
||||
$sql = $this->user->getSQL();
|
||||
$sql = $this->context->getSQL();
|
||||
$this->success = $sql->insert("MailQueue", ["from", "to", "subject", "body",
|
||||
"replyTo", "replyName", "gpgFingerprint"])
|
||||
->addRow($fromMail, $toMail, $subject, $body, $replyTo, $replyName, $gpgFingerprint)
|
||||
@@ -200,14 +205,14 @@ namespace Api\Mail {
|
||||
// TODO: attachments
|
||||
class Sync extends MailAPI {
|
||||
|
||||
public function __construct(User $user, bool $externalCall = false) {
|
||||
parent::__construct($user, $externalCall, array());
|
||||
public function __construct(Context $context, bool $externalCall = false) {
|
||||
parent::__construct($context, $externalCall, array());
|
||||
$this->loginRequired = true;
|
||||
}
|
||||
|
||||
private function fetchMessageIds() {
|
||||
$sql = $this->user->getSQL();
|
||||
$res = $sql->select("uid", "messageId")
|
||||
$sql = $this->context->getSQL();
|
||||
$res = $sql->select("id", "messageId")
|
||||
->from("ContactRequest")
|
||||
->where(new Compare("messageId", NULL, "!="))
|
||||
->execute();
|
||||
@@ -220,7 +225,7 @@ namespace Api\Mail {
|
||||
|
||||
$messageIds = [];
|
||||
foreach ($res as $row) {
|
||||
$messageIds[$row["messageId"]] = $row["uid"];
|
||||
$messageIds[$row["messageId"]] = $row["id"];
|
||||
}
|
||||
return $messageIds;
|
||||
}
|
||||
@@ -241,7 +246,7 @@ namespace Api\Mail {
|
||||
}
|
||||
|
||||
private function insertMessages($messages): bool {
|
||||
$sql = $this->user->getSQL();
|
||||
$sql = $this->context->getSQL();
|
||||
|
||||
$query = $sql->insert("ContactMessage", ["request_id", "user_id", "message", "messageId", "created_at"])
|
||||
->onDuplicateKeyStrategy(new UpdateStrategy(["messageId"], ["message" => new Column("message")]));
|
||||
@@ -251,7 +256,7 @@ namespace Api\Mail {
|
||||
$requestId = $message["requestId"];
|
||||
$query->addRow(
|
||||
$requestId,
|
||||
$sql->select("uid")->from("User")->where(new Compare("email", $message["from"]))->limit(1),
|
||||
$sql->select("id")->from("User")->where(new Compare("email", $message["from"]))->limit(1),
|
||||
$message["body"],
|
||||
$message["messageId"],
|
||||
(new \DateTime())->setTimeStamp($message["timestamp"]),
|
||||
@@ -450,7 +455,7 @@ namespace Api\Mail {
|
||||
return false;
|
||||
}
|
||||
|
||||
$req = new \Api\Settings\Set($this->user);
|
||||
$req = new \Api\Settings\Set($this->context);
|
||||
$this->success = $req->execute(array("settings" => array("mail_last_sync" => "$now")));
|
||||
$this->lastError = $req->getLastError();
|
||||
return $this->success;
|
||||
@@ -458,8 +463,8 @@ namespace Api\Mail {
|
||||
}
|
||||
|
||||
class SendQueue extends MailAPI {
|
||||
public function __construct(User $user, bool $externalCall = false) {
|
||||
parent::__construct($user, $externalCall, [
|
||||
public function __construct(Context $context, bool $externalCall = false) {
|
||||
parent::__construct($context, $externalCall, [
|
||||
"debug" => new Parameter("debug", Parameter::TYPE_BOOLEAN, true, false)
|
||||
]);
|
||||
$this->isPublic = false;
|
||||
@@ -473,8 +478,8 @@ namespace Api\Mail {
|
||||
echo "Start of processing mail queue at $startTime" . PHP_EOL;
|
||||
}
|
||||
|
||||
$sql = $this->user->getSQL();
|
||||
$res = $sql->select("uid", "from", "to", "subject", "body",
|
||||
$sql = $this->context->getSQL();
|
||||
$res = $sql->select("id", "from", "to", "subject", "body",
|
||||
"replyTo", "replyName", "gpgFingerprint", "retryCount")
|
||||
->from("MailQueue")
|
||||
->where(new Compare("retryCount", 0, ">"))
|
||||
@@ -505,9 +510,9 @@ namespace Api\Mail {
|
||||
echo "Sending subject=$subject to=$to" . PHP_EOL;
|
||||
}
|
||||
|
||||
$mailId = intval($row["uid"]);
|
||||
$mailId = intval($row["id"]);
|
||||
$retryCount = intval($row["retryCount"]);
|
||||
$req = new Send($this->user);
|
||||
$req = new Send($this->context);
|
||||
$args = [
|
||||
"to" => $to,
|
||||
"subject" => $subject,
|
||||
@@ -529,7 +534,7 @@ namespace Api\Mail {
|
||||
->set("status", "error")
|
||||
->set("errorMessage", $error)
|
||||
->set("nextTry", $nextTry)
|
||||
->where(new Compare("uid", $mailId))
|
||||
->where(new Compare("id", $mailId))
|
||||
->execute();
|
||||
} else {
|
||||
$successfulMails[] = $mailId;
|
||||
@@ -540,7 +545,7 @@ namespace Api\Mail {
|
||||
if (!empty($successfulMails)) {
|
||||
$res = $sql->update("MailQueue")
|
||||
->set("status", "success")
|
||||
->where(new CondIn(new Column("uid"), $successfulMails))
|
||||
->where(new CondIn(new Column("id"), $successfulMails))
|
||||
->execute();
|
||||
$this->success = $res !== false;
|
||||
$this->lastError = $sql->getLastError();
|
||||
|
||||
@@ -2,11 +2,11 @@
|
||||
|
||||
namespace Api {
|
||||
|
||||
use Objects\User;
|
||||
use Objects\Context;
|
||||
|
||||
abstract class NewsAPI extends Request {
|
||||
public function __construct(User $user, bool $externalCall = false, array $params = array()) {
|
||||
parent::__construct($user, $externalCall, $params);
|
||||
public function __construct(Context $context, bool $externalCall = false, array $params = array()) {
|
||||
parent::__construct($context, $externalCall, $params);
|
||||
$this->loginRequired = true;
|
||||
}
|
||||
}
|
||||
@@ -18,57 +18,47 @@ namespace Api\News {
|
||||
use Api\Parameter\Parameter;
|
||||
use Api\Parameter\StringType;
|
||||
use Driver\SQL\Condition\Compare;
|
||||
use Objects\User;
|
||||
use Objects\Context;
|
||||
use Objects\DatabaseEntity\News;
|
||||
|
||||
class Get extends NewsAPI {
|
||||
|
||||
public function __construct(User $user, bool $externalCall = false) {
|
||||
parent::__construct($user, $externalCall, [
|
||||
public function __construct(Context $context, bool $externalCall = false) {
|
||||
parent::__construct($context, $externalCall, [
|
||||
"since" => new Parameter("since", Parameter::TYPE_DATE_TIME, true, null),
|
||||
"limit" => new Parameter("limit", Parameter::TYPE_INT, true, 10)
|
||||
]);
|
||||
|
||||
$this->loginRequired = false;
|
||||
}
|
||||
|
||||
public function _execute(): bool {
|
||||
$sql = $this->user->getSQL();
|
||||
$query = $sql->select("News.uid", "title", "text", "publishedAt",
|
||||
"User.uid as publisherId", "User.name as publisherName", "User.fullName as publisherFullName")
|
||||
->from("News")
|
||||
->innerJoin("User", "User.uid", "News.publishedBy")
|
||||
->orderBy("publishedAt")
|
||||
->descending();
|
||||
|
||||
$since = $this->getParam("since");
|
||||
if ($since) {
|
||||
$query->where(new Compare("publishedAt", $since, ">="));
|
||||
}
|
||||
|
||||
$limit = $this->getParam("limit");
|
||||
if ($limit < 1 || $limit > 30) {
|
||||
return $this->createError("Limit must be in range 1-30");
|
||||
} else {
|
||||
$query->limit($limit);
|
||||
}
|
||||
|
||||
$res = $query->execute();
|
||||
$this->success = $res !== false;
|
||||
$sql = $this->context->getSQL();
|
||||
$newsQuery = News::findAllBuilder($sql)
|
||||
->limit($limit)
|
||||
->orderBy("published_at")
|
||||
->descending()
|
||||
->fetchEntities();
|
||||
|
||||
if ($since) {
|
||||
$newsQuery->where(new Compare("published_at", $since, ">="));
|
||||
}
|
||||
|
||||
$newsArray = $newsQuery->execute();
|
||||
$this->success = $newsArray !== null;
|
||||
$this->lastError = $sql->getLastError();
|
||||
|
||||
if ($this->success) {
|
||||
$this->result["news"] = [];
|
||||
foreach ($res as $row) {
|
||||
$newsId = intval($row["uid"]);
|
||||
$this->result["news"][$newsId] = [
|
||||
"id" => $newsId,
|
||||
"title" => $row["title"],
|
||||
"text" => $row["text"],
|
||||
"publishedAt" => $row["publishedAt"],
|
||||
"publisher" => [
|
||||
"id" => intval($row["publisherId"]),
|
||||
"name" => $row["publisherName"],
|
||||
"fullName" => $row["publisherFullName"]
|
||||
]
|
||||
];
|
||||
foreach ($newsArray as $news) {
|
||||
$newsId = $news->getId();
|
||||
$this->result["news"][$newsId] = $news->jsonSerialize();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -77,28 +67,27 @@ namespace Api\News {
|
||||
}
|
||||
|
||||
class Publish extends NewsAPI {
|
||||
public function __construct(User $user, bool $externalCall = false) {
|
||||
parent::__construct($user, $externalCall, [
|
||||
public function __construct(Context $context, bool $externalCall = false) {
|
||||
parent::__construct($context, $externalCall, [
|
||||
"title" => new StringType("title", 128),
|
||||
"text" => new StringType("text", 1024)
|
||||
]);
|
||||
$this->loginRequired = true;
|
||||
}
|
||||
|
||||
public function _execute(): bool {
|
||||
$sql = $this->user->getSQL();
|
||||
$title = $this->getParam("title");
|
||||
$text = $this->getParam("text");
|
||||
|
||||
$res = $sql->insert("News", ["title", "text"])
|
||||
->addRow($title, $text)
|
||||
->returning("uid")
|
||||
->execute();
|
||||
$news = new News();
|
||||
$news->text = $this->getParam("text");
|
||||
$news->title = $this->getParam("title");
|
||||
$news->publishedBy = $this->context->getUser();
|
||||
|
||||
$this->success = $res !== false;
|
||||
$sql = $this->context->getSQL();
|
||||
$this->success = $news->save($sql);
|
||||
$this->lastError = $sql->getLastError();
|
||||
|
||||
if ($this->success) {
|
||||
$this->result["newsId"] = $sql->getLastInsertId();
|
||||
$this->result["newsId"] = $news->getId();
|
||||
}
|
||||
|
||||
return $this->success;
|
||||
@@ -106,77 +95,62 @@ namespace Api\News {
|
||||
}
|
||||
|
||||
class Delete extends NewsAPI {
|
||||
public function __construct(User $user, bool $externalCall = false) {
|
||||
parent::__construct($user, $externalCall, [
|
||||
public function __construct(Context $context, bool $externalCall = false) {
|
||||
parent::__construct($context, $externalCall, [
|
||||
"id" => new Parameter("id", Parameter::TYPE_INT)
|
||||
]);
|
||||
$this->loginRequired = true;
|
||||
}
|
||||
|
||||
public function _execute(): bool {
|
||||
$sql = $this->user->getSQL();
|
||||
$id = $this->getParam("id");
|
||||
$res = $sql->select("publishedBy")
|
||||
->from("News")
|
||||
->where(new Compare("uid", $id))
|
||||
->execute();
|
||||
$sql = $this->context->getSQL();
|
||||
$currentUser = $this->context->getUser();
|
||||
|
||||
$this->success = ($res !== false);
|
||||
$news = News::find($sql, $this->getParam("id"));
|
||||
$this->success = ($news !== false);
|
||||
$this->lastError = $sql->getLastError();
|
||||
if (!$this->success) {
|
||||
return false;
|
||||
} else if (empty($res) || !is_array($res)) {
|
||||
} else if ($news === null) {
|
||||
return $this->createError("News Post not found");
|
||||
} else if (intval($res[0]["publishedBy"]) !== $this->user->getId() && !$this->user->hasGroup(USER_GROUP_ADMIN)) {
|
||||
} else if ($news->publishedBy->getId() !== $currentUser->getId() && !$currentUser->hasGroup(USER_GROUP_ADMIN)) {
|
||||
return $this->createError("You do not have permissions to delete news post of other users.");
|
||||
}
|
||||
|
||||
$res = $sql->delete("News")
|
||||
->where(new Compare("uid", $id))
|
||||
->execute();
|
||||
|
||||
$this->success = $res !== false;
|
||||
$this->success = $news->delete($sql);
|
||||
$this->lastError = $sql->getLastError();
|
||||
return $this->success;
|
||||
}
|
||||
}
|
||||
|
||||
class Edit extends NewsAPI {
|
||||
public function __construct(User $user, bool $externalCall = false) {
|
||||
parent::__construct($user, $externalCall, [
|
||||
public function __construct(Context $context, bool $externalCall = false) {
|
||||
parent::__construct($context, $externalCall, [
|
||||
"id" => new Parameter("id", Parameter::TYPE_INT),
|
||||
"title" => new StringType("title", 128),
|
||||
"text" => new StringType("text", 1024)
|
||||
]);
|
||||
$this->loginRequired = true;
|
||||
}
|
||||
|
||||
public function _execute(): bool {
|
||||
$sql = $this->context->getSQL();
|
||||
$currentUser = $this->context->getUser();
|
||||
|
||||
$sql = $this->user->getSQL();
|
||||
$id = $this->getParam("id");
|
||||
$text = $this->getParam("text");
|
||||
$title = $this->getParam("title");
|
||||
$res = $sql->select("publishedBy")
|
||||
->from("News")
|
||||
->where(new Compare("uid", $id))
|
||||
->execute();
|
||||
|
||||
$this->success = ($res !== false);
|
||||
$news = News::find($sql, $this->getParam("id"));
|
||||
$this->success = ($news !== false);
|
||||
$this->lastError = $sql->getLastError();
|
||||
if (!$this->success) {
|
||||
return false;
|
||||
} else if (empty($res) || !is_array($res)) {
|
||||
} else if ($news === null) {
|
||||
return $this->createError("News Post not found");
|
||||
} else if (intval($res[0]["publishedBy"]) !== $this->user->getId() && !$this->user->hasGroup(USER_GROUP_ADMIN)) {
|
||||
} else if ($news->publishedBy->getId() !== $currentUser->getId() && !$currentUser->hasGroup(USER_GROUP_ADMIN)) {
|
||||
return $this->createError("You do not have permissions to edit news post of other users.");
|
||||
}
|
||||
|
||||
$res = $sql->update("News")
|
||||
->set("title", $title)
|
||||
->set("text", $text)
|
||||
->where(new Compare("uid", $id))
|
||||
->execute();
|
||||
|
||||
$this->success = $res !== false;
|
||||
$news->text = $this->getParam("text");
|
||||
$news->title = $this->getParam("title");
|
||||
$this->success = $news->save($sql);
|
||||
$this->lastError = $sql->getLastError();
|
||||
return $this->success;
|
||||
}
|
||||
|
||||
@@ -1,8 +1,13 @@
|
||||
<?php
|
||||
|
||||
namespace Api {
|
||||
abstract class NotificationsAPI extends Request {
|
||||
|
||||
use Objects\Context;
|
||||
|
||||
abstract class NotificationsAPI extends Request {
|
||||
public function __construct(Context $context, bool $externalCall = false, array $params = array()) {
|
||||
parent::__construct($context, $externalCall, $params);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,12 +20,15 @@ namespace Api\Notifications {
|
||||
use Driver\SQL\Condition\Compare;
|
||||
use Driver\SQL\Condition\CondIn;
|
||||
use Driver\SQL\Query\Select;
|
||||
use Objects\User;
|
||||
use Objects\Context;
|
||||
use Objects\DatabaseEntity\Group;
|
||||
use Objects\DatabaseEntity\Notification;
|
||||
use Objects\DatabaseEntity\User;
|
||||
|
||||
class Create extends NotificationsAPI {
|
||||
|
||||
public function __construct($user, $externalCall = false) {
|
||||
parent::__construct($user, $externalCall, array(
|
||||
public function __construct(Context $context, $externalCall = false) {
|
||||
parent::__construct($context, $externalCall, array(
|
||||
'groupId' => new Parameter('groupId', Parameter::TYPE_INT, true),
|
||||
'userId' => new Parameter('userId', Parameter::TYPE_INT, true),
|
||||
'title' => new StringType('title', 32),
|
||||
@@ -29,28 +37,8 @@ namespace Api\Notifications {
|
||||
$this->isPublic = false;
|
||||
}
|
||||
|
||||
private function checkUser($userId) {
|
||||
$sql = $this->user->getSQL();
|
||||
$res = $sql->select($sql->count())
|
||||
->from("User")
|
||||
->where(new Compare("uid", $userId))
|
||||
->execute();
|
||||
|
||||
$this->success = ($res !== FALSE);
|
||||
$this->lastError = $sql->getLastError();
|
||||
|
||||
if ($this->success) {
|
||||
if ($res[0]["count"] == 0) {
|
||||
$this->success = false;
|
||||
$this->lastError = "User not found";
|
||||
}
|
||||
}
|
||||
|
||||
return $this->success;
|
||||
}
|
||||
|
||||
private function insertUserNotification($userId, $notificationId) {
|
||||
$sql = $this->user->getSQL();
|
||||
private function insertUserNotification($userId, $notificationId): bool {
|
||||
$sql = $this->context->getSQL();
|
||||
$res = $sql->insert("UserNotification", array("user_id", "notification_id"))
|
||||
->addRow($userId, $notificationId)
|
||||
->execute();
|
||||
@@ -60,28 +48,8 @@ namespace Api\Notifications {
|
||||
return $this->success;
|
||||
}
|
||||
|
||||
private function checkGroup($groupId) {
|
||||
$sql = $this->user->getSQL();
|
||||
$res = $sql->select($sql->count())
|
||||
->from("Group")
|
||||
->where(new Compare("uid", $groupId))
|
||||
->execute();
|
||||
|
||||
$this->success = ($res !== FALSE);
|
||||
$this->lastError = $sql->getLastError();
|
||||
|
||||
if ($this->success) {
|
||||
if ($res[0]["count"] == 0) {
|
||||
$this->success = false;
|
||||
$this->lastError = "Group not found";
|
||||
}
|
||||
}
|
||||
|
||||
return $this->success;
|
||||
}
|
||||
|
||||
private function insertGroupNotification($groupId, $notificationId) {
|
||||
$sql = $this->user->getSQL();
|
||||
private function insertGroupNotification($groupId, $notificationId): bool {
|
||||
$sql = $this->context->getSQL();
|
||||
$res = $sql->insert("GroupNotification", array("group_id", "notification_id"))
|
||||
->addRow($groupId, $notificationId)
|
||||
->execute();
|
||||
@@ -91,24 +59,24 @@ namespace Api\Notifications {
|
||||
return $this->success;
|
||||
}
|
||||
|
||||
private function createNotification($title, $message) {
|
||||
$sql = $this->user->getSQL();
|
||||
$res = $sql->insert("Notification", array("title", "message"))
|
||||
->addRow($title, $message)
|
||||
->returning("uid")
|
||||
->execute();
|
||||
private function createNotification($title, $message): bool|int {
|
||||
$sql = $this->context->getSQL();
|
||||
$notification = new Notification();
|
||||
$notification->title = $title;
|
||||
$notification->message = $message;
|
||||
|
||||
$this->success = ($res !== FALSE);
|
||||
$this->success = ($notification->save($sql) !== FALSE);
|
||||
$this->lastError = $sql->getLastError();
|
||||
|
||||
if ($this->success) {
|
||||
return $sql->getLastInsertId();
|
||||
return $notification->getId();
|
||||
}
|
||||
|
||||
return $this->success;
|
||||
}
|
||||
|
||||
public function _execute(): bool {
|
||||
$sql = $this->context->getSQL();
|
||||
$userId = $this->getParam("userId");
|
||||
$groupId = $this->getParam("groupId");
|
||||
$title = $this->getParam("title");
|
||||
@@ -119,18 +87,22 @@ namespace Api\Notifications {
|
||||
} else if(!is_null($userId) && !is_null($groupId)) {
|
||||
return $this->createError("Only one of userId and groupId must be specified.");
|
||||
} else if(!is_null($userId)) {
|
||||
if ($this->checkUser($userId)) {
|
||||
if (User::exists($sql, $userId)) {
|
||||
$id = $this->createNotification($title, $message);
|
||||
if ($this->success) {
|
||||
return $this->insertUserNotification($userId, $id);
|
||||
}
|
||||
} else {
|
||||
return $this->createError("User not found: $userId");
|
||||
}
|
||||
} else if(!is_null($groupId)) {
|
||||
if ($this->checkGroup($groupId)) {
|
||||
if (Group::exists($sql, $groupId)) {
|
||||
$id = $this->createNotification($title, $message);
|
||||
if ($this->success) {
|
||||
return $this->insertGroupNotification($groupId, $id);
|
||||
}
|
||||
} else {
|
||||
return $this->createError("Group not found: $groupId");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -141,22 +113,22 @@ namespace Api\Notifications {
|
||||
class Fetch extends NotificationsAPI {
|
||||
|
||||
private array $notifications;
|
||||
private array $notificationids;
|
||||
private array $notificationIds;
|
||||
|
||||
public function __construct($user, $externalCall = false) {
|
||||
parent::__construct($user, $externalCall, array(
|
||||
public function __construct(Context $context, $externalCall = false) {
|
||||
parent::__construct($context, $externalCall, array(
|
||||
'new' => new Parameter('new', Parameter::TYPE_BOOLEAN, true, true)
|
||||
));
|
||||
$this->loginRequired = true;
|
||||
}
|
||||
|
||||
private function fetchUserNotifications() {
|
||||
private function fetchUserNotifications(): bool {
|
||||
$onlyNew = $this->getParam('new');
|
||||
$userId = $this->user->getId();
|
||||
$sql = $this->user->getSQL();
|
||||
$query = $sql->select($sql->distinct("Notification.uid"), "created_at", "title", "message", "type")
|
||||
$userId = $this->context->getUser()->getId();
|
||||
$sql = $this->context->getSQL();
|
||||
$query = $sql->select($sql->distinct("Notification.id"), "created_at", "title", "message", "type")
|
||||
->from("Notification")
|
||||
->innerJoin("UserNotification", "UserNotification.notification_id", "Notification.uid")
|
||||
->innerJoin("UserNotification", "UserNotification.notification_id", "Notification.id")
|
||||
->where(new Compare("UserNotification.user_id", $userId))
|
||||
->orderBy("created_at")->descending();
|
||||
|
||||
@@ -167,13 +139,13 @@ namespace Api\Notifications {
|
||||
return $this->fetchNotifications($query);
|
||||
}
|
||||
|
||||
private function fetchGroupNotifications() {
|
||||
private function fetchGroupNotifications(): bool {
|
||||
$onlyNew = $this->getParam('new');
|
||||
$userId = $this->user->getId();
|
||||
$sql = $this->user->getSQL();
|
||||
$query = $sql->select($sql->distinct("Notification.uid"), "created_at", "title", "message", "type")
|
||||
$userId = $this->context->getUser()->getId();
|
||||
$sql = $this->context->getSQL();
|
||||
$query = $sql->select($sql->distinct("Notification.id"), "created_at", "title", "message", "type")
|
||||
->from("Notification")
|
||||
->innerJoin("GroupNotification", "GroupNotification.notification_id", "Notification.uid")
|
||||
->innerJoin("GroupNotification", "GroupNotification.notification_id", "Notification.id")
|
||||
->innerJoin("UserGroup", "GroupNotification.group_id", "UserGroup.group_id")
|
||||
->where(new Compare("UserGroup.user_id", $userId))
|
||||
->orderBy("created_at")->descending();
|
||||
@@ -185,19 +157,19 @@ namespace Api\Notifications {
|
||||
return $this->fetchNotifications($query);
|
||||
}
|
||||
|
||||
private function fetchNotifications(Select $query) {
|
||||
$sql = $this->user->getSQL();
|
||||
private function fetchNotifications(Select $query): bool {
|
||||
$sql = $this->context->getSQL();
|
||||
$res = $query->execute();
|
||||
$this->success = ($res !== FALSE);
|
||||
$this->lastError = $sql->getLastError();
|
||||
|
||||
if ($this->success) {
|
||||
foreach($res as $row) {
|
||||
$id = $row["uid"];
|
||||
if (!in_array($id, $this->notificationids)) {
|
||||
$this->notificationids[] = $id;
|
||||
$id = $row["id"];
|
||||
if (!in_array($id, $this->notificationIds)) {
|
||||
$this->notificationIds[] = $id;
|
||||
$this->notifications[] = array(
|
||||
"uid" => $id,
|
||||
"id" => $id,
|
||||
"title" => $row["title"],
|
||||
"message" => $row["message"],
|
||||
"created_at" => $row["created_at"],
|
||||
@@ -212,7 +184,7 @@ namespace Api\Notifications {
|
||||
|
||||
public function _execute(): bool {
|
||||
$this->notifications = array();
|
||||
$this->notificationids = array();
|
||||
$this->notificationIds = array();
|
||||
if ($this->fetchUserNotifications() && $this->fetchGroupNotifications()) {
|
||||
$this->result["notifications"] = $this->notifications;
|
||||
}
|
||||
@@ -223,17 +195,18 @@ namespace Api\Notifications {
|
||||
|
||||
class Seen extends NotificationsAPI {
|
||||
|
||||
public function __construct(User $user, bool $externalCall = false) {
|
||||
parent::__construct($user, $externalCall, array());
|
||||
public function __construct(Context $context, bool $externalCall = false) {
|
||||
parent::__construct($context, $externalCall, array());
|
||||
$this->loginRequired = true;
|
||||
}
|
||||
|
||||
public function _execute(): bool {
|
||||
|
||||
$sql = $this->user->getSQL();
|
||||
$currentUser = $this->context->getUser();
|
||||
$sql = $this->context->getSQL();
|
||||
$res = $sql->update("UserNotification")
|
||||
->set("seen", true)
|
||||
->where(new Compare("user_id", $this->user->getId()))
|
||||
->where(new Compare("user_id", $currentUser->getId()))
|
||||
->execute();
|
||||
|
||||
$this->success = ($res !== FALSE);
|
||||
@@ -245,7 +218,7 @@ namespace Api\Notifications {
|
||||
->where(new CondIn(new Column("group_id"),
|
||||
$sql->select("group_id")
|
||||
->from("UserGroup")
|
||||
->where(new Compare("user_id", $this->user->getId()))))
|
||||
->where(new Compare("user_id", $currentUser->getId()))))
|
||||
->execute();
|
||||
|
||||
$this->success = ($res !== FALSE);
|
||||
|
||||
@@ -2,9 +2,17 @@
|
||||
|
||||
namespace Api {
|
||||
|
||||
use Objects\Context;
|
||||
|
||||
abstract class PermissionAPI extends Request {
|
||||
|
||||
public function __construct(Context $context, bool $externalCall = false, array $params = array()) {
|
||||
parent::__construct($context, $externalCall, $params);
|
||||
}
|
||||
|
||||
protected function checkStaticPermission(): bool {
|
||||
if (!$this->user->isLoggedIn() || !$this->user->hasGroup(USER_GROUP_ADMIN)) {
|
||||
$user = $this->context->getUser();
|
||||
if (!$user || !$user->hasGroup(USER_GROUP_ADMIN)) {
|
||||
return $this->createError("Permission denied.");
|
||||
}
|
||||
|
||||
@@ -24,12 +32,14 @@ namespace Api\Permission {
|
||||
use Driver\SQL\Condition\CondLike;
|
||||
use Driver\SQL\Condition\CondNot;
|
||||
use Driver\SQL\Strategy\UpdateStrategy;
|
||||
use Objects\User;
|
||||
use Objects\Context;
|
||||
use Objects\DatabaseEntity\Group;
|
||||
use Objects\DatabaseEntity\User;
|
||||
|
||||
class Check extends PermissionAPI {
|
||||
|
||||
public function __construct(User $user, bool $externalCall = false) {
|
||||
parent::__construct($user, $externalCall, array(
|
||||
public function __construct(Context $context, bool $externalCall = false) {
|
||||
parent::__construct($context, $externalCall, array(
|
||||
'method' => new StringType('method', 323)
|
||||
));
|
||||
|
||||
@@ -39,7 +49,7 @@ namespace Api\Permission {
|
||||
public function _execute(): bool {
|
||||
|
||||
$method = $this->getParam("method");
|
||||
$sql = $this->user->getSQL();
|
||||
$sql = $this->context->getSQL();
|
||||
$res = $sql->select("groups")
|
||||
->from("ApiPermission")
|
||||
->where(new CondLike($method, new Column("method")))
|
||||
@@ -58,8 +68,9 @@ namespace Api\Permission {
|
||||
return true;
|
||||
}
|
||||
|
||||
$userGroups = $this->user->getGroups();
|
||||
if (empty($userGroups) || empty(array_intersect($groups, array_keys($this->user->getGroups())))) {
|
||||
$currentUser = $this->context->getUser();
|
||||
$userGroups = $currentUser ? $currentUser->getGroups() : [];
|
||||
if (empty($userGroups) || empty(array_intersect($groups, array_keys($userGroups)))) {
|
||||
http_response_code(401);
|
||||
return $this->createError("Permission denied.");
|
||||
}
|
||||
@@ -71,33 +82,17 @@ namespace Api\Permission {
|
||||
|
||||
class Fetch extends PermissionAPI {
|
||||
|
||||
private array $groups;
|
||||
private ?array $groups;
|
||||
|
||||
public function __construct(User $user, bool $externalCall = false) {
|
||||
parent::__construct($user, $externalCall, array());
|
||||
public function __construct(Context $context, bool $externalCall = false) {
|
||||
parent::__construct($context, $externalCall, array());
|
||||
}
|
||||
|
||||
private function fetchGroups() {
|
||||
$sql = $this->user->getSQL();
|
||||
$res = $sql->select("uid", "name", "color")
|
||||
->from("Group")
|
||||
->orderBy("uid")
|
||||
->ascending()
|
||||
->execute();
|
||||
|
||||
$this->success = ($res !== FALSE);
|
||||
private function fetchGroups(): bool {
|
||||
$sql = $this->context->getSQL();
|
||||
$this->groups = Group::findAll($sql);
|
||||
$this->success = ($this->groups !== FALSE);
|
||||
$this->lastError = $sql->getLastError();
|
||||
|
||||
if ($this->success) {
|
||||
$this->groups = array();
|
||||
foreach($res as $row) {
|
||||
$groupId = $row["uid"];
|
||||
$groupName = $row["name"];
|
||||
$groupColor = $row["color"];
|
||||
$this->groups[$groupId] = array("name" => $groupName, "color" => $groupColor);
|
||||
}
|
||||
}
|
||||
|
||||
return $this->success;
|
||||
}
|
||||
|
||||
@@ -107,7 +102,7 @@ namespace Api\Permission {
|
||||
return false;
|
||||
}
|
||||
|
||||
$sql = $this->user->getSQL();
|
||||
$sql = $this->context->getSQL();
|
||||
$res = $sql->select("method", "groups", "description")
|
||||
->from("ApiPermission")
|
||||
->execute();
|
||||
@@ -137,8 +132,8 @@ namespace Api\Permission {
|
||||
|
||||
class Save extends PermissionAPI {
|
||||
|
||||
public function __construct(User $user, bool $externalCall = false) {
|
||||
parent::__construct($user, $externalCall, array(
|
||||
public function __construct(Context $context, bool $externalCall = false) {
|
||||
parent::__construct($context, $externalCall, array(
|
||||
'permissions' => new Parameter('permissions', Parameter::TYPE_ARRAY)
|
||||
));
|
||||
}
|
||||
@@ -150,27 +145,27 @@ namespace Api\Permission {
|
||||
}
|
||||
|
||||
$permissions = $this->getParam("permissions");
|
||||
$sql = $this->user->getSQL();
|
||||
$sql = $this->context->getSQL();
|
||||
$methodParam = new StringType('method', 32);
|
||||
$groupsParam = new Parameter('groups', Parameter::TYPE_ARRAY);
|
||||
|
||||
$updateQuery = $sql->insert("ApiPermission", array("method", "groups"))
|
||||
->onDuplicateKeyStrategy(new UpdateStrategy(array("method"), array( "groups" => new Column("groups") )));
|
||||
->onDuplicateKeyStrategy(new UpdateStrategy(array("method"), array("groups" => new Column("groups"))));
|
||||
|
||||
$insertedMethods = array();
|
||||
|
||||
foreach($permissions as $permission) {
|
||||
foreach ($permissions as $permission) {
|
||||
if (!is_array($permission)) {
|
||||
return $this->createError("Invalid data type found in parameter: permissions, expected: object");
|
||||
} else if(!isset($permission["method"]) || !array_key_exists("groups", $permission)) {
|
||||
} else if (!isset($permission["method"]) || !array_key_exists("groups", $permission)) {
|
||||
return $this->createError("Invalid object found in parameter: permissions, expected keys 'method' and 'groups'");
|
||||
} else if (!$methodParam->parseParam($permission["method"])) {
|
||||
$expectedType = $methodParam->getTypeName();
|
||||
return $this->createError("Invalid data type found for attribute 'method', expected: $expectedType");
|
||||
} else if(!$groupsParam->parseParam($permission["groups"])) {
|
||||
} else if (!$groupsParam->parseParam($permission["groups"])) {
|
||||
$expectedType = $groupsParam->getTypeName();
|
||||
return $this->createError("Invalid data type found for attribute 'groups', expected: $expectedType");
|
||||
} else if(empty(trim($methodParam->value))) {
|
||||
} else if (empty(trim($methodParam->value))) {
|
||||
return $this->createError("Method cannot be empty.");
|
||||
} else {
|
||||
$method = $methodParam->value;
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
namespace Api;
|
||||
|
||||
use Driver\Logger\Logger;
|
||||
use Objects\User;
|
||||
use Objects\Context;
|
||||
use PhpMqtt\Client\MqttClient;
|
||||
|
||||
/**
|
||||
@@ -14,7 +14,7 @@ use PhpMqtt\Client\MqttClient;
|
||||
|
||||
abstract class Request {
|
||||
|
||||
protected User $user;
|
||||
protected Context $context;
|
||||
protected Logger $logger;
|
||||
protected array $params;
|
||||
protected string $lastError;
|
||||
@@ -31,9 +31,9 @@ abstract class Request {
|
||||
private array $allowedMethods;
|
||||
private bool $externalCall;
|
||||
|
||||
public function __construct(User $user, bool $externalCall = false, array $params = array()) {
|
||||
$this->user = $user;
|
||||
$this->logger = new Logger($this->getAPIName(), $this->user->getSQL());
|
||||
public function __construct(Context $context, bool $externalCall = false, array $params = array()) {
|
||||
$this->context = $context;
|
||||
$this->logger = new Logger($this->getAPIName(), $this->context->getSQL());
|
||||
$this->defaultParams = $params;
|
||||
|
||||
$this->success = false;
|
||||
@@ -137,8 +137,9 @@ abstract class Request {
|
||||
$this->result = array();
|
||||
$this->lastError = '';
|
||||
|
||||
if ($this->user->isLoggedIn()) {
|
||||
$this->result['logoutIn'] = $this->user->getSession()->getExpiresSeconds();
|
||||
$session = $this->context->getSession();
|
||||
if ($session) {
|
||||
$this->result['logoutIn'] = $session->getExpiresSeconds();
|
||||
}
|
||||
|
||||
if ($this->externalCall) {
|
||||
@@ -183,25 +184,24 @@ abstract class Request {
|
||||
}
|
||||
|
||||
$apiKeyAuthorized = false;
|
||||
|
||||
if (!$this->user->isLoggedIn() && $this->apiKeyAllowed) {
|
||||
if (!$session && $this->apiKeyAllowed) {
|
||||
if (isset($_SERVER["HTTP_AUTHORIZATION"])) {
|
||||
$authHeader = $_SERVER["HTTP_AUTHORIZATION"];
|
||||
if (startsWith($authHeader, "Bearer ")) {
|
||||
$apiKey = substr($authHeader, strlen("Bearer "));
|
||||
$apiKeyAuthorized = $this->user->loadApiKey($apiKey);
|
||||
$apiKeyAuthorized = $this->context->loadApiKey($apiKey);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Logged in or api key authorized?
|
||||
if ($this->loginRequired) {
|
||||
if (!$this->user->isLoggedIn() && !$apiKeyAuthorized) {
|
||||
if (!$session && !$apiKeyAuthorized) {
|
||||
$this->lastError = 'You are not logged in.';
|
||||
http_response_code(401);
|
||||
return false;
|
||||
} else if ($this->user->isLoggedIn()) {
|
||||
$tfaToken = $this->user->getTwoFactorToken();
|
||||
} else if ($session) {
|
||||
$tfaToken = $session->getUser()->getTwoFactorToken();
|
||||
if ($tfaToken && $tfaToken->isConfirmed() && !$tfaToken->isAuthenticated()) {
|
||||
$this->lastError = '2FA-Authorization is required';
|
||||
http_response_code(401);
|
||||
@@ -211,11 +211,11 @@ abstract class Request {
|
||||
}
|
||||
|
||||
// CSRF Token
|
||||
if ($this->csrfTokenRequired && $this->user->isLoggedIn()) {
|
||||
if ($this->csrfTokenRequired && $session) {
|
||||
// csrf token required + external call
|
||||
// if it's not a call with API_KEY, check for csrf_token
|
||||
$csrfToken = $values["csrf_token"] ?? $_SERVER["HTTP_XSRF_TOKEN"] ?? null;
|
||||
if (!$csrfToken || strcmp($csrfToken, $this->user->getSession()->getCsrfToken()) !== 0) {
|
||||
if (!$csrfToken || strcmp($csrfToken, $session->getCsrfToken()) !== 0) {
|
||||
$this->lastError = "CSRF-Token mismatch";
|
||||
http_response_code(403);
|
||||
return false;
|
||||
@@ -224,7 +224,7 @@ abstract class Request {
|
||||
|
||||
// Check for permission
|
||||
if (!($this instanceof \Api\Permission\Save)) {
|
||||
$req = new \Api\Permission\Check($this->user);
|
||||
$req = new \Api\Permission\Check($this->context);
|
||||
$this->success = $req->execute(array("method" => $this->getMethod()));
|
||||
$this->lastError = $req->getLastError();
|
||||
if (!$this->success) {
|
||||
@@ -241,8 +241,9 @@ abstract class Request {
|
||||
$this->parseVariableParams($values);
|
||||
}
|
||||
|
||||
if (!$this->user->getSQL()->isConnected()) {
|
||||
$this->lastError = $this->user->getSQL()->getLastError();
|
||||
$sql = $this->context->getSQL();
|
||||
if (!$sql->isConnected()) {
|
||||
$this->lastError = $sql->getLastError();
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -254,7 +255,7 @@ abstract class Request {
|
||||
$this->success = $success;
|
||||
}
|
||||
|
||||
$this->user->getSQL()->setLastError('');
|
||||
$sql->setLastError('');
|
||||
return $this->success;
|
||||
}
|
||||
|
||||
@@ -331,8 +332,8 @@ abstract class Request {
|
||||
}
|
||||
|
||||
protected function setupSSE() {
|
||||
$this->user->getSQL()->close();
|
||||
$this->user->sendCookies();
|
||||
$this->context->sendCookies();
|
||||
$this->context->getSQL()?->close();
|
||||
set_time_limit(0);
|
||||
ignore_user_abort(true);
|
||||
header('Content-Type: text/event-stream');
|
||||
|
||||
@@ -4,7 +4,7 @@ namespace Api {
|
||||
|
||||
use Api\Routes\GenerateCache;
|
||||
use Driver\SQL\Condition\Compare;
|
||||
use Objects\User;
|
||||
use Objects\Context;
|
||||
|
||||
abstract class RoutesAPI extends Request {
|
||||
|
||||
@@ -13,16 +13,16 @@ namespace Api {
|
||||
|
||||
protected string $routerCachePath;
|
||||
|
||||
public function __construct(User $user, bool $externalCall, array $params) {
|
||||
parent::__construct($user, $externalCall, $params);
|
||||
public function __construct(Context $context, bool $externalCall, array $params) {
|
||||
parent::__construct($context, $externalCall, $params);
|
||||
$this->routerCachePath = getClassPath(self::ROUTER_CACHE_CLASS);
|
||||
}
|
||||
|
||||
protected function routeExists($uid): bool {
|
||||
$sql = $this->user->getSQL();
|
||||
$sql = $this->context->getSQL();
|
||||
$res = $sql->select($sql->count())
|
||||
->from("Route")
|
||||
->where(new Compare("uid", $uid))
|
||||
->where(new Compare("id", $uid))
|
||||
->execute();
|
||||
|
||||
$this->success = ($res !== false);
|
||||
@@ -41,10 +41,10 @@ namespace Api {
|
||||
return false;
|
||||
}
|
||||
|
||||
$sql = $this->user->getSQL();
|
||||
$sql = $this->context->getSQL();
|
||||
$this->success = $sql->update("Route")
|
||||
->set("active", $active)
|
||||
->where(new Compare("uid", $uid))
|
||||
->where(new Compare("id", $uid))
|
||||
->execute();
|
||||
|
||||
$this->lastError = $sql->getLastError();
|
||||
@@ -53,7 +53,7 @@ namespace Api {
|
||||
}
|
||||
|
||||
protected function regenerateCache(): bool {
|
||||
$req = new GenerateCache($this->user);
|
||||
$req = new GenerateCache($this->context);
|
||||
$this->success = $req->execute();
|
||||
$this->lastError = $req->getLastError();
|
||||
return $this->success;
|
||||
@@ -68,25 +68,25 @@ namespace Api\Routes {
|
||||
use Api\RoutesAPI;
|
||||
use Driver\SQL\Condition\Compare;
|
||||
use Driver\SQL\Condition\CondBool;
|
||||
use Objects\Context;
|
||||
use Objects\Router\DocumentRoute;
|
||||
use Objects\Router\RedirectRoute;
|
||||
use Objects\Router\Router;
|
||||
use Objects\Router\StaticFileRoute;
|
||||
use Objects\User;
|
||||
|
||||
class Fetch extends RoutesAPI {
|
||||
|
||||
public function __construct($user, $externalCall = false) {
|
||||
parent::__construct($user, $externalCall, array());
|
||||
public function __construct(Context $context, $externalCall = false) {
|
||||
parent::__construct($context, $externalCall, array());
|
||||
}
|
||||
|
||||
public function _execute(): bool {
|
||||
$sql = $this->user->getSQL();
|
||||
$sql = $this->context->getSQL();
|
||||
|
||||
$res = $sql
|
||||
->select("uid", "request", "action", "target", "extra", "active", "exact")
|
||||
->select("id", "request", "action", "target", "extra", "active", "exact")
|
||||
->from("Route")
|
||||
->orderBy("uid")
|
||||
->orderBy("id")
|
||||
->ascending()
|
||||
->execute();
|
||||
|
||||
@@ -97,7 +97,7 @@ namespace Api\Routes {
|
||||
$routes = array();
|
||||
foreach ($res as $row) {
|
||||
$routes[] = array(
|
||||
"uid" => intval($row["uid"]),
|
||||
"id" => intval($row["id"]),
|
||||
"request" => $row["request"],
|
||||
"action" => $row["action"],
|
||||
"target" => $row["target"],
|
||||
@@ -118,8 +118,8 @@ namespace Api\Routes {
|
||||
|
||||
private array $routes;
|
||||
|
||||
public function __construct($user, $externalCall = false) {
|
||||
parent::__construct($user, $externalCall, array(
|
||||
public function __construct(Context $context, $externalCall = false) {
|
||||
parent::__construct($context, $externalCall, array(
|
||||
'routes' => new Parameter('routes', Parameter::TYPE_ARRAY, false)
|
||||
));
|
||||
}
|
||||
@@ -129,7 +129,7 @@ namespace Api\Routes {
|
||||
return false;
|
||||
}
|
||||
|
||||
$sql = $this->user->getSQL();
|
||||
$sql = $this->context->getSQL();
|
||||
|
||||
// DELETE old rules
|
||||
$this->success = ($sql->truncate("Route")->execute() !== FALSE);
|
||||
@@ -210,8 +210,8 @@ namespace Api\Routes {
|
||||
|
||||
class Add extends RoutesAPI {
|
||||
|
||||
public function __construct(User $user, bool $externalCall = false) {
|
||||
parent::__construct($user, $externalCall, array(
|
||||
public function __construct(Context $context, bool $externalCall = false) {
|
||||
parent::__construct($context, $externalCall, array(
|
||||
"request" => new StringType("request", 128),
|
||||
"action" => new StringType("action"),
|
||||
"target" => new StringType("target", 128),
|
||||
@@ -231,7 +231,7 @@ namespace Api\Routes {
|
||||
return $this->createError("Invalid action: $action");
|
||||
}
|
||||
|
||||
$sql = $this->user->getSQL();
|
||||
$sql = $this->context->getSQL();
|
||||
$this->success = $sql->insert("Route", ["request", "action", "target", "extra"])
|
||||
->addRow($request, $action, $target, $extra)
|
||||
->execute();
|
||||
@@ -243,9 +243,9 @@ namespace Api\Routes {
|
||||
}
|
||||
|
||||
class Update extends RoutesAPI {
|
||||
public function __construct(User $user, bool $externalCall = false) {
|
||||
parent::__construct($user, $externalCall, array(
|
||||
"uid" => new Parameter("uid", Parameter::TYPE_INT),
|
||||
public function __construct(Context $context, bool $externalCall = false) {
|
||||
parent::__construct($context, $externalCall, array(
|
||||
"id" => new Parameter("id", Parameter::TYPE_INT),
|
||||
"request" => new StringType("request", 128),
|
||||
"action" => new StringType("action"),
|
||||
"target" => new StringType("target", 128),
|
||||
@@ -256,8 +256,8 @@ namespace Api\Routes {
|
||||
|
||||
public function _execute(): bool {
|
||||
|
||||
$uid = $this->getParam("uid");
|
||||
if (!$this->routeExists($uid)) {
|
||||
$id = $this->getParam("id");
|
||||
if (!$this->routeExists($id)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -269,13 +269,13 @@ namespace Api\Routes {
|
||||
return $this->createError("Invalid action: $action");
|
||||
}
|
||||
|
||||
$sql = $this->user->getSQL();
|
||||
$sql = $this->context->getSQL();
|
||||
$this->success = $sql->update("Route")
|
||||
->set("request", $request)
|
||||
->set("action", $action)
|
||||
->set("target", $target)
|
||||
->set("extra", $extra)
|
||||
->where(new Compare("uid", $uid))
|
||||
->where(new Compare("id", $id))
|
||||
->execute();
|
||||
|
||||
$this->lastError = $sql->getLastError();
|
||||
@@ -285,23 +285,23 @@ namespace Api\Routes {
|
||||
}
|
||||
|
||||
class Remove extends RoutesAPI {
|
||||
public function __construct(User $user, bool $externalCall = false) {
|
||||
parent::__construct($user, $externalCall, array(
|
||||
"uid" => new Parameter("uid", Parameter::TYPE_INT)
|
||||
public function __construct(Context $context, bool $externalCall = false) {
|
||||
parent::__construct($context, $externalCall, array(
|
||||
"id" => new Parameter("id", Parameter::TYPE_INT)
|
||||
));
|
||||
$this->isPublic = false;
|
||||
}
|
||||
|
||||
public function _execute(): bool {
|
||||
|
||||
$uid = $this->getParam("uid");
|
||||
$uid = $this->getParam("id");
|
||||
if (!$this->routeExists($uid)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$sql = $this->user->getSQL();
|
||||
$sql = $this->context->getSQL();
|
||||
$this->success = $sql->delete("Route")
|
||||
->where(new Compare("uid", $uid))
|
||||
->where(new Compare("id", $uid))
|
||||
->execute();
|
||||
|
||||
$this->lastError = $sql->getLastError();
|
||||
@@ -311,29 +311,29 @@ namespace Api\Routes {
|
||||
}
|
||||
|
||||
class Enable extends RoutesAPI {
|
||||
public function __construct(User $user, bool $externalCall = false) {
|
||||
parent::__construct($user, $externalCall, array(
|
||||
"uid" => new Parameter("uid", Parameter::TYPE_INT)
|
||||
public function __construct(Context $context, bool $externalCall = false) {
|
||||
parent::__construct($context, $externalCall, array(
|
||||
"id" => new Parameter("id", Parameter::TYPE_INT)
|
||||
));
|
||||
$this->isPublic = false;
|
||||
}
|
||||
|
||||
public function _execute(): bool {
|
||||
$uid = $this->getParam("uid");
|
||||
$uid = $this->getParam("id");
|
||||
return $this->toggleRoute($uid, true);
|
||||
}
|
||||
}
|
||||
|
||||
class Disable extends RoutesAPI {
|
||||
public function __construct(User $user, bool $externalCall = false) {
|
||||
parent::__construct($user, $externalCall, array(
|
||||
"uid" => new Parameter("uid", Parameter::TYPE_INT)
|
||||
public function __construct(Context $context, bool $externalCall = false) {
|
||||
parent::__construct($context, $externalCall, array(
|
||||
"id" => new Parameter("id", Parameter::TYPE_INT)
|
||||
));
|
||||
$this->isPublic = false;
|
||||
}
|
||||
|
||||
public function _execute(): bool {
|
||||
$uid = $this->getParam("uid");
|
||||
$uid = $this->getParam("id");
|
||||
return $this->toggleRoute($uid, false);
|
||||
}
|
||||
}
|
||||
@@ -342,19 +342,19 @@ namespace Api\Routes {
|
||||
|
||||
private ?Router $router;
|
||||
|
||||
public function __construct(User $user, bool $externalCall = false) {
|
||||
parent::__construct($user, $externalCall, []);
|
||||
public function __construct(Context $context, bool $externalCall = false) {
|
||||
parent::__construct($context, $externalCall, []);
|
||||
$this->isPublic = false;
|
||||
$this->router = null;
|
||||
}
|
||||
|
||||
protected function _execute(): bool {
|
||||
$sql = $this->user->getSQL();
|
||||
$sql = $this->context->getSQL();
|
||||
$res = $sql
|
||||
->select("uid", "request", "action", "target", "extra", "exact")
|
||||
->select("id", "request", "action", "target", "extra", "exact")
|
||||
->from("Route")
|
||||
->where(new CondBool("active"))
|
||||
->orderBy("uid")->ascending()
|
||||
->orderBy("id")->ascending()
|
||||
->execute();
|
||||
|
||||
$this->success = $res !== false;
|
||||
@@ -363,7 +363,7 @@ namespace Api\Routes {
|
||||
return false;
|
||||
}
|
||||
|
||||
$this->router = new Router($this->user);
|
||||
$this->router = new Router($this->context);
|
||||
foreach ($res as $row) {
|
||||
$request = $row["request"];
|
||||
$target = $row["target"];
|
||||
|
||||
@@ -2,10 +2,13 @@
|
||||
|
||||
namespace Api {
|
||||
|
||||
use Objects\Context;
|
||||
|
||||
abstract class SettingsAPI extends Request {
|
||||
|
||||
public function __construct(Context $context, bool $externalCall = false, array $params = array()) {
|
||||
parent::__construct($context, $externalCall, $params);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
namespace Api\Settings {
|
||||
@@ -19,19 +22,19 @@ namespace Api\Settings {
|
||||
use Driver\SQL\Condition\CondNot;
|
||||
use Driver\SQL\Condition\CondRegex;
|
||||
use Driver\SQL\Strategy\UpdateStrategy;
|
||||
use Objects\User;
|
||||
use Objects\Context;
|
||||
|
||||
class Get extends SettingsAPI {
|
||||
|
||||
public function __construct(User $user, bool $externalCall = false) {
|
||||
parent::__construct($user, $externalCall, array(
|
||||
public function __construct(Context $context, bool $externalCall = false) {
|
||||
parent::__construct($context, $externalCall, array(
|
||||
'key' => new StringType('key', -1, true, NULL)
|
||||
));
|
||||
}
|
||||
|
||||
public function _execute(): bool {
|
||||
$key = $this->getParam("key");
|
||||
$sql = $this->user->getSQL();
|
||||
$sql = $this->context->getSQL();
|
||||
|
||||
$query = $sql->select("name", "value") ->from("Settings");
|
||||
|
||||
@@ -62,8 +65,8 @@ namespace Api\Settings {
|
||||
}
|
||||
|
||||
class Set extends SettingsAPI {
|
||||
public function __construct(User $user, bool $externalCall = false) {
|
||||
parent::__construct($user, $externalCall, array(
|
||||
public function __construct(Context $context, bool $externalCall = false) {
|
||||
parent::__construct($context, $externalCall, array(
|
||||
'settings' => new Parameter('settings', Parameter::TYPE_ARRAY)
|
||||
));
|
||||
}
|
||||
@@ -77,7 +80,7 @@ namespace Api\Settings {
|
||||
$paramKey = new StringType('key', 32);
|
||||
$paramValue = new StringType('value', 1024, true, NULL);
|
||||
|
||||
$sql = $this->user->getSQL();
|
||||
$sql = $this->context->getSQL();
|
||||
$query = $sql->insert("Settings", array("name", "value"));
|
||||
$keys = array();
|
||||
$deleteKeys = array();
|
||||
@@ -129,7 +132,7 @@ namespace Api\Settings {
|
||||
}
|
||||
|
||||
private function checkReadonly(array $keys) {
|
||||
$sql = $this->user->getSQL();
|
||||
$sql = $this->context->getSQL();
|
||||
$res = $sql->select("name")
|
||||
->from("Settings")
|
||||
->where(new CondBool("readonly"))
|
||||
@@ -148,7 +151,7 @@ namespace Api\Settings {
|
||||
}
|
||||
|
||||
private function deleteKeys(array $keys) {
|
||||
$sql = $this->user->getSQL();
|
||||
$sql = $this->context->getSQL();
|
||||
$res = $sql->delete("Settings")
|
||||
->where(new CondIn(new Column("name"), $keys))
|
||||
->execute();
|
||||
|
||||
@@ -5,18 +5,20 @@ namespace Api;
|
||||
use DateTime;
|
||||
use Driver\SQL\Condition\Compare;
|
||||
use Driver\SQL\Condition\CondBool;
|
||||
use Objects\Context;
|
||||
use Objects\DatabaseEntity\User;
|
||||
|
||||
class Stats extends Request {
|
||||
|
||||
private bool $mailConfigured;
|
||||
private bool $recaptchaConfigured;
|
||||
|
||||
public function __construct($user, $externalCall = false) {
|
||||
parent::__construct($user, $externalCall, array());
|
||||
public function __construct(Context $context, $externalCall = false) {
|
||||
parent::__construct($context, $externalCall, array());
|
||||
}
|
||||
|
||||
private function getUserCount() {
|
||||
$sql = $this->user->getSQL();
|
||||
$sql = $this->context->getSQL();
|
||||
$res = $sql->select($sql->count())->from("User")->execute();
|
||||
$this->success = $this->success && ($res !== FALSE);
|
||||
$this->lastError = $sql->getLastError();
|
||||
@@ -25,7 +27,7 @@ class Stats extends Request {
|
||||
}
|
||||
|
||||
private function getPageCount() {
|
||||
$sql = $this->user->getSQL();
|
||||
$sql = $this->context->getSQL();
|
||||
$res = $sql->select($sql->count())->from("Route")
|
||||
->where(new CondBool("active"))
|
||||
->execute();
|
||||
@@ -36,7 +38,7 @@ class Stats extends Request {
|
||||
}
|
||||
|
||||
private function checkSettings(): bool {
|
||||
$req = new \Api\Settings\Get($this->user);
|
||||
$req = new \Api\Settings\Get($this->context);
|
||||
$this->success = $req->execute(array("key" => "^(mail_enabled|recaptcha_enabled)$"));
|
||||
$this->lastError = $req->getLastError();
|
||||
|
||||
@@ -50,7 +52,7 @@ class Stats extends Request {
|
||||
}
|
||||
|
||||
private function getVisitorCount() {
|
||||
$sql = $this->user->getSQL();
|
||||
$sql = $this->context->getSQL();
|
||||
$date = new DateTime();
|
||||
$monthStart = $date->format("Ym00");
|
||||
$monthEnd = $date->modify("+1 month")->format("Ym00");
|
||||
@@ -69,7 +71,7 @@ class Stats extends Request {
|
||||
public function _execute(): bool {
|
||||
$userCount = $this->getUserCount();
|
||||
$pageCount = $this->getPageCount();
|
||||
$req = new \Api\Visitors\Stats($this->user);
|
||||
$req = new \Api\Visitors\Stats($this->context);
|
||||
$this->success = $req->execute(array("type"=>"monthly"));
|
||||
$this->lastError = $req->getLastError();
|
||||
if (!$this->success) {
|
||||
@@ -100,7 +102,7 @@ class Stats extends Request {
|
||||
"server" => $_SERVER["SERVER_SOFTWARE"] ?? "Unknown",
|
||||
"memory_usage" => memory_get_usage(),
|
||||
"load_avg" => $loadAvg,
|
||||
"database" => $this->user->getSQL()->getStatus(),
|
||||
"database" => $this->context->getSQL()->getStatus(),
|
||||
"mail" => $this->mailConfigured,
|
||||
"reCaptcha" => $this->recaptchaConfigured
|
||||
);
|
||||
|
||||
@@ -3,12 +3,13 @@
|
||||
namespace Api;
|
||||
|
||||
use Api\Parameter\StringType;
|
||||
use Objects\User;
|
||||
use Objects\Context;
|
||||
use Objects\DatabaseEntity\User;
|
||||
|
||||
class Swagger extends Request {
|
||||
|
||||
public function __construct(User $user, bool $externalCall = false) {
|
||||
parent::__construct($user, $externalCall, []);
|
||||
public function __construct(Context $context, bool $externalCall = false) {
|
||||
parent::__construct($context, $externalCall, []);
|
||||
$this->csrfTokenRequired = false;
|
||||
}
|
||||
|
||||
@@ -61,7 +62,7 @@ class Swagger extends Request {
|
||||
}
|
||||
|
||||
private function fetchPermissions(): array {
|
||||
$req = new Permission\Fetch($this->user);
|
||||
$req = new Permission\Fetch($this->context);
|
||||
$this->success = $req->execute();
|
||||
$permissions = [];
|
||||
foreach( $req->getResult()["permissions"] as $permission) {
|
||||
@@ -76,17 +77,19 @@ class Swagger extends Request {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (($request->loginRequired() || !empty($requiredGroups)) && !$this->user->isLoggedIn()) {
|
||||
$currentUser = $this->context->getUser();
|
||||
if (($request->loginRequired() || !empty($requiredGroups)) && !$currentUser) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// special case: hardcoded permission
|
||||
if ($request instanceof Permission\Save && (!$this->user->isLoggedIn() || !$this->user->hasGroup(USER_GROUP_ADMIN))) {
|
||||
if ($request instanceof Permission\Save && (!$currentUser || !$currentUser->hasGroup(USER_GROUP_ADMIN))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!empty($requiredGroups)) {
|
||||
return !empty(array_intersect($requiredGroups, $this->user->getGroups()));
|
||||
$userGroups = array_keys($currentUser?->getGroups() ?? []);
|
||||
return !empty(array_intersect($requiredGroups, $userGroups));
|
||||
}
|
||||
|
||||
return true;
|
||||
@@ -94,7 +97,7 @@ class Swagger extends Request {
|
||||
|
||||
private function getDocumentation(): string {
|
||||
|
||||
$settings = $this->user->getConfiguration()->getSettings();
|
||||
$settings = $this->context->getSettings();
|
||||
$siteName = $settings->getSiteName();
|
||||
$domain = parse_url($settings->getBaseUrl(), PHP_URL_HOST);
|
||||
|
||||
@@ -105,7 +108,7 @@ class Swagger extends Request {
|
||||
foreach (self::getApiEndpoints() as $endpoint => $apiClass) {
|
||||
$body = null;
|
||||
$requiredProperties = [];
|
||||
$apiObject = $apiClass->newInstance($this->user, false);
|
||||
$apiObject = $apiClass->newInstance($this->context, false);
|
||||
if (!$this->canView($permissions[strtolower($endpoint)] ?? [], $apiObject)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -2,11 +2,11 @@
|
||||
|
||||
namespace Api {
|
||||
|
||||
use Objects\User;
|
||||
use Objects\Context;
|
||||
|
||||
abstract class TemplateAPI extends Request {
|
||||
function __construct(User $user, bool $externalCall = false, array $params = array()) {
|
||||
parent::__construct($user, $externalCall, $params);
|
||||
function __construct(Context $context, bool $externalCall = false, array $params = array()) {
|
||||
parent::__construct($context, $externalCall, $params);
|
||||
$this->isPublic = false; // internal API
|
||||
}
|
||||
}
|
||||
@@ -19,7 +19,7 @@ namespace Api\Template {
|
||||
use Api\Parameter\Parameter;
|
||||
use Api\Parameter\StringType;
|
||||
use Api\TemplateAPI;
|
||||
use Objects\User;
|
||||
use Objects\Context;
|
||||
use Twig\Environment;
|
||||
use Twig\Error\LoaderError;
|
||||
use Twig\Error\RuntimeError;
|
||||
@@ -28,8 +28,8 @@ namespace Api\Template {
|
||||
|
||||
class Render extends TemplateAPI {
|
||||
|
||||
public function __construct(User $user, bool $externalCall = false) {
|
||||
parent::__construct($user, $externalCall, [
|
||||
public function __construct(Context $context, bool $externalCall = false) {
|
||||
parent::__construct($context, $externalCall, [
|
||||
"file" => new StringType("file"),
|
||||
"parameters" => new ArrayType("parameters", Parameter::TYPE_MIXED, false, true, [])
|
||||
]);
|
||||
|
||||
@@ -2,22 +2,23 @@
|
||||
|
||||
namespace Api {
|
||||
|
||||
use Objects\Context;
|
||||
use Objects\TwoFactor\AuthenticationData;
|
||||
use Objects\TwoFactor\KeyBasedTwoFactorToken;
|
||||
use Objects\User;
|
||||
|
||||
abstract class TfaAPI extends Request {
|
||||
|
||||
private bool $userVerficiationRequired;
|
||||
private bool $userVerificationRequired;
|
||||
|
||||
public function __construct(User $user, bool $externalCall = false, array $params = array()) {
|
||||
parent::__construct($user, $externalCall, $params);
|
||||
public function __construct(Context $context, bool $externalCall = false, array $params = array()) {
|
||||
parent::__construct($context, $externalCall, $params);
|
||||
$this->loginRequired = true;
|
||||
$this->userVerficiationRequired = false;
|
||||
$this->apiKeyAllowed = false;
|
||||
$this->userVerificationRequired = false;
|
||||
}
|
||||
|
||||
protected function verifyAuthData(AuthenticationData $authData): bool {
|
||||
$settings = $this->user->getConfiguration()->getSettings();
|
||||
$settings = $this->context->getSettings();
|
||||
// $relyingParty = $settings->getSiteName();
|
||||
$domain = parse_url($settings->getBaseUrl(), PHP_URL_HOST);
|
||||
// $domain = "localhost";
|
||||
@@ -26,7 +27,7 @@ namespace Api {
|
||||
return $this->createError("mismatched rpIDHash. expected: " . hash("sha256", $domain) . " got: " . bin2hex($authData->getHash()));
|
||||
} else if (!$authData->isUserPresent()) {
|
||||
return $this->createError("No user present");
|
||||
} else if ($this->userVerficiationRequired && !$authData->isUserVerified()) {
|
||||
} else if ($this->userVerificationRequired && !$authData->isUserVerified()) {
|
||||
return $this->createError("user was not verified on device (PIN/Biometric/...)");
|
||||
} else if ($authData->hasExtensionData()) {
|
||||
return $this->createError("No extensions supported");
|
||||
@@ -36,7 +37,7 @@ namespace Api {
|
||||
}
|
||||
|
||||
protected function verifyClientDataJSON($jsonData, KeyBasedTwoFactorToken $token): bool {
|
||||
$settings = $this->user->getConfiguration()->getSettings();
|
||||
$settings = $this->context->getSettings();
|
||||
$expectedType = $token->isConfirmed() ? "webauthn.get" : "webauthn.create";
|
||||
$type = $jsonData["type"] ?? "null";
|
||||
if ($type !== $expectedType) {
|
||||
@@ -58,33 +59,34 @@ namespace Api\TFA {
|
||||
use Api\Parameter\StringType;
|
||||
use Api\TfaAPI;
|
||||
use Driver\SQL\Condition\Compare;
|
||||
use Objects\Context;
|
||||
use Objects\TwoFactor\AttestationObject;
|
||||
use Objects\TwoFactor\AuthenticationData;
|
||||
use Objects\TwoFactor\KeyBasedTwoFactorToken;
|
||||
use Objects\TwoFactor\TimeBasedTwoFactorToken;
|
||||
use Objects\User;
|
||||
|
||||
// General
|
||||
class Remove extends TfaAPI {
|
||||
public function __construct(User $user, bool $externalCall = false) {
|
||||
parent::__construct($user, $externalCall, [
|
||||
public function __construct(Context $context, bool $externalCall = false) {
|
||||
parent::__construct($context, $externalCall, [
|
||||
"password" => new StringType("password", 0, true)
|
||||
]);
|
||||
}
|
||||
|
||||
public function _execute(): bool {
|
||||
|
||||
$token = $this->user->getTwoFactorToken();
|
||||
$currentUser = $this->context->getUser();
|
||||
$token = $currentUser->getTwoFactorToken();
|
||||
if (!$token) {
|
||||
return $this->createError("You do not have an active 2FA-Token");
|
||||
}
|
||||
|
||||
$sql = $this->user->getSQL();
|
||||
$sql = $this->context->getSQL();
|
||||
$password = $this->getParam("password");
|
||||
if ($password) {
|
||||
$res = $sql->select("password")
|
||||
->from("User")
|
||||
->where(new Compare("uid", $this->user->getId()))
|
||||
->where(new Compare("id", $currentUser->getId()))
|
||||
->execute();
|
||||
$this->success = !empty($res);
|
||||
$this->lastError = $sql->getLastError();
|
||||
@@ -99,7 +101,7 @@ namespace Api\TFA {
|
||||
}
|
||||
|
||||
$res = $sql->delete("2FA")
|
||||
->where(new Compare("uid", $token->getId()))
|
||||
->where(new Compare("id", $token->getId()))
|
||||
->execute();
|
||||
|
||||
$this->success = $res !== false;
|
||||
@@ -107,12 +109,12 @@ namespace Api\TFA {
|
||||
|
||||
if ($this->success && $token->isConfirmed()) {
|
||||
// send an email
|
||||
$settings = $this->user->getConfiguration()->getSettings();
|
||||
$req = new \Api\Template\Render($this->user);
|
||||
$settings = $this->context->getSettings();
|
||||
$req = new \Api\Template\Render($this->context);
|
||||
$this->success = $req->execute([
|
||||
"file" => "mail/2fa_remove.twig",
|
||||
"parameters" => [
|
||||
"username" => $this->user->getFullName() ?? $this->user->getUsername(),
|
||||
"username" => $currentUser->getFullName() ?? $currentUser->getUsername(),
|
||||
"site_name" => $settings->getSiteName(),
|
||||
"sender_mail" => $settings->getMailSender()
|
||||
]
|
||||
@@ -120,13 +122,13 @@ namespace Api\TFA {
|
||||
|
||||
if ($this->success) {
|
||||
$body = $req->getResult()["html"];
|
||||
$gpg = $this->user->getGPG();
|
||||
$req = new \Api\Mail\Send($this->user);
|
||||
$gpg = $currentUser->getGPG();
|
||||
$req = new \Api\Mail\Send($this->context);
|
||||
$this->success = $req->execute([
|
||||
"to" => $this->user->getEmail(),
|
||||
"to" => $currentUser->getEmail(),
|
||||
"subject" => "[Security Lab] 2FA-Authentication removed",
|
||||
"body" => $body,
|
||||
"gpgFingerprint" => $gpg ? $gpg->getFingerprint() : null
|
||||
"gpgFingerprint" => $gpg?->getFingerprint()
|
||||
]);
|
||||
}
|
||||
|
||||
@@ -140,27 +142,28 @@ namespace Api\TFA {
|
||||
// TOTP
|
||||
class GenerateQR extends TfaAPI {
|
||||
|
||||
public function __construct(User $user, bool $externalCall = false) {
|
||||
parent::__construct($user, $externalCall);
|
||||
public function __construct(Context $context, bool $externalCall = false) {
|
||||
parent::__construct($context, $externalCall);
|
||||
$this->csrfTokenRequired = false;
|
||||
}
|
||||
|
||||
public function _execute(): bool {
|
||||
|
||||
$twoFactorToken = $this->user->getTwoFactorToken();
|
||||
$currentUser = $this->context->getUser();
|
||||
$twoFactorToken = $currentUser->getTwoFactorToken();
|
||||
if ($twoFactorToken && $twoFactorToken->isConfirmed()) {
|
||||
return $this->createError("You already added a two factor token");
|
||||
} else if (!($twoFactorToken instanceof TimeBasedTwoFactorToken)) {
|
||||
$twoFactorToken = new TimeBasedTwoFactorToken(generateRandomString(32, "base32"));
|
||||
$sql = $this->user->getSQL();
|
||||
$sql = $this->context->getSQL();
|
||||
$this->success = $sql->insert("2FA", ["type", "data"])
|
||||
->addRow("totp", $twoFactorToken->getData())
|
||||
->returning("uid")
|
||||
->returning("id")
|
||||
->execute() !== false;
|
||||
$this->lastError = $sql->getLastError();
|
||||
if ($this->success) {
|
||||
$this->success = $sql->update("User")
|
||||
->set("2fa_id", $sql->getLastInsertId())->where(new Compare("uid", $this->user->getId()))
|
||||
->set("2fa_id", $sql->getLastInsertId())->where(new Compare("id", $currentUser->getId()))
|
||||
->execute() !== false;
|
||||
$this->lastError = $sql->getLastError();
|
||||
}
|
||||
@@ -172,27 +175,27 @@ namespace Api\TFA {
|
||||
|
||||
header("Content-Type: image/png");
|
||||
$this->disableCache();
|
||||
die($twoFactorToken->generateQRCode($this->user));
|
||||
die($twoFactorToken->generateQRCode($this->context));
|
||||
}
|
||||
}
|
||||
|
||||
class ConfirmTotp extends VerifyTotp {
|
||||
public function __construct(User $user, bool $externalCall = false) {
|
||||
parent::__construct($user, $externalCall);
|
||||
$this->loginRequired = true;
|
||||
public function __construct(Context $context, bool $externalCall = false) {
|
||||
parent::__construct($context, $externalCall);
|
||||
}
|
||||
|
||||
public function _execute(): bool {
|
||||
|
||||
$twoFactorToken = $this->user->getTwoFactorToken();
|
||||
$currentUser = $this->context->getUser();
|
||||
$twoFactorToken = $currentUser->getTwoFactorToken();
|
||||
if ($twoFactorToken->isConfirmed()) {
|
||||
return $this->createError("Your two factor token is already confirmed.");
|
||||
}
|
||||
|
||||
$sql = $this->user->getSQL();
|
||||
$sql = $this->context->getSQL();
|
||||
$this->success = $sql->update("2FA")
|
||||
->set("confirmed", true)
|
||||
->where(new Compare("uid", $twoFactorToken->getId()))
|
||||
->where(new Compare("id", $twoFactorToken->getId()))
|
||||
->execute() !== false;
|
||||
$this->lastError = $sql->getLastError();
|
||||
return $this->success;
|
||||
@@ -201,22 +204,22 @@ namespace Api\TFA {
|
||||
|
||||
class VerifyTotp extends TfaAPI {
|
||||
|
||||
public function __construct(User $user, bool $externalCall = false) {
|
||||
parent::__construct($user, $externalCall, [
|
||||
public function __construct(Context $context, bool $externalCall = false) {
|
||||
parent::__construct($context, $externalCall, [
|
||||
"code" => new StringType("code", 6)
|
||||
]);
|
||||
$this->loginRequired = false;
|
||||
$this->loginRequired = true;
|
||||
$this->csrfTokenRequired = false;
|
||||
}
|
||||
|
||||
public function _execute(): bool {
|
||||
|
||||
$session = $this->user->getSession();
|
||||
if (!$session) {
|
||||
$currentUser = $this->context->getUser();
|
||||
if (!$currentUser) {
|
||||
return $this->createError("You are not logged in.");
|
||||
}
|
||||
|
||||
$twoFactorToken = $this->user->getTwoFactorToken();
|
||||
$twoFactorToken = $currentUser->getTwoFactorToken();
|
||||
if (!$twoFactorToken) {
|
||||
return $this->createError("You did not add a two factor token yet.");
|
||||
} else if (!($twoFactorToken instanceof TimeBasedTwoFactorToken)) {
|
||||
@@ -235,21 +238,23 @@ namespace Api\TFA {
|
||||
|
||||
// Key
|
||||
class RegisterKey extends TfaAPI {
|
||||
public function __construct(User $user, bool $externalCall = false) {
|
||||
parent::__construct($user, $externalCall, [
|
||||
public function __construct(Context $context, bool $externalCall = false) {
|
||||
parent::__construct($context, $externalCall, [
|
||||
"clientDataJSON" => new StringType("clientDataJSON", 0, true, "{}"),
|
||||
"attestationObject" => new StringType("attestationObject", 0, true, "")
|
||||
]);
|
||||
$this->loginRequired = true;
|
||||
}
|
||||
|
||||
public function _execute(): bool {
|
||||
|
||||
$currentUser = $this->context->getUser();
|
||||
$clientDataJSON = json_decode($this->getParam("clientDataJSON"), true);
|
||||
$attestationObjectRaw = base64_decode($this->getParam("attestationObject"));
|
||||
$twoFactorToken = $this->user->getTwoFactorToken();
|
||||
$settings = $this->user->getConfiguration()->getSettings();
|
||||
$twoFactorToken = $currentUser->getTwoFactorToken();
|
||||
$settings = $this->context->getSettings();
|
||||
$relyingParty = $settings->getSiteName();
|
||||
$sql = $this->user->getSQL();
|
||||
$sql = $this->context->getSQL();
|
||||
|
||||
// TODO: for react development, localhost / HTTP_HOST is required, otherwise a DOMException is thrown
|
||||
$domain = parse_url($settings->getBaseUrl(), PHP_URL_HOST);
|
||||
@@ -266,7 +271,7 @@ namespace Api\TFA {
|
||||
$challenge = base64_encode(generateRandomString(32, "raw"));
|
||||
$res = $sql->insert("2FA", ["type", "data"])
|
||||
->addRow("fido", $challenge)
|
||||
->returning("uid")
|
||||
->returning("id")
|
||||
->execute();
|
||||
$this->success = ($res !== false);
|
||||
$this->lastError = $sql->getLastError();
|
||||
@@ -276,7 +281,7 @@ namespace Api\TFA {
|
||||
|
||||
$this->success = $sql->update("User")
|
||||
->set("2fa_id", $sql->getLastInsertId())
|
||||
->where(new Compare("uid", $this->user->getId()))
|
||||
->where(new Compare("id", $currentUser->getId()))
|
||||
->execute() !== false;
|
||||
$this->lastError = $sql->getLastError();
|
||||
if (!$this->success) {
|
||||
@@ -286,7 +291,7 @@ namespace Api\TFA {
|
||||
|
||||
$this->result["data"] = [
|
||||
"challenge" => $challenge,
|
||||
"id" => $this->user->getId() . "@" . $domain, // <userId>@<domain>
|
||||
"id" => $currentUser->getId() . "@" . $domain, // <userId>@<domain>
|
||||
"relyingParty" => [
|
||||
"name" => $relyingParty,
|
||||
"id" => $domain
|
||||
@@ -322,7 +327,7 @@ namespace Api\TFA {
|
||||
$this->success = $sql->update("2FA")
|
||||
->set("data", json_encode($data))
|
||||
->set("confirmed", true)
|
||||
->where(new Compare("uid", $twoFactorToken->getId()))
|
||||
->where(new Compare("id", $twoFactorToken->getId()))
|
||||
->execute() !== false;
|
||||
$this->lastError = $sql->getLastError();
|
||||
}
|
||||
@@ -332,25 +337,25 @@ namespace Api\TFA {
|
||||
}
|
||||
|
||||
class VerifyKey extends TfaAPI {
|
||||
public function __construct(User $user, bool $externalCall = false) {
|
||||
parent::__construct($user, $externalCall, [
|
||||
public function __construct(Context $context, bool $externalCall = false) {
|
||||
parent::__construct($context, $externalCall, [
|
||||
"credentialID" => new StringType("credentialID"),
|
||||
"clientDataJSON" => new StringType("clientDataJSON"),
|
||||
"authData" => new StringType("authData"),
|
||||
"signature" => new StringType("signature"),
|
||||
]);
|
||||
$this->loginRequired = false;
|
||||
$this->loginRequired = true;
|
||||
$this->csrfTokenRequired = false;
|
||||
}
|
||||
|
||||
public function _execute(): bool {
|
||||
|
||||
$session = $this->user->getSession();
|
||||
if (!$session) {
|
||||
$currentUser = $this->context->getUser();
|
||||
if (!$currentUser) {
|
||||
return $this->createError("You are not logged in.");
|
||||
}
|
||||
|
||||
$twoFactorToken = $this->user->getTwoFactorToken();
|
||||
$twoFactorToken = $currentUser->getTwoFactorToken();
|
||||
if (!$twoFactorToken) {
|
||||
return $this->createError("You did not add a two factor token yet.");
|
||||
} else if (!($twoFactorToken instanceof KeyBasedTwoFactorToken)) {
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -3,12 +3,12 @@
|
||||
namespace Api;
|
||||
|
||||
use Api\Parameter\StringType;
|
||||
use Objects\User;
|
||||
use Objects\Context;
|
||||
|
||||
class VerifyCaptcha extends Request {
|
||||
|
||||
public function __construct(User $user, bool $externalCall = false) {
|
||||
parent::__construct($user, $externalCall, array(
|
||||
public function __construct(Context $context, bool $externalCall = false) {
|
||||
parent::__construct($context, $externalCall, array(
|
||||
"captcha" => new StringType("captcha"),
|
||||
"action" => new StringType("action"),
|
||||
));
|
||||
@@ -17,7 +17,7 @@ class VerifyCaptcha extends Request {
|
||||
}
|
||||
|
||||
public function _execute(): bool {
|
||||
$settings = $this->user->getConfiguration()->getSettings();
|
||||
$settings = $this->context->getSettings();
|
||||
if (!$settings->isRecaptchaEnabled()) {
|
||||
return $this->createError("Google reCaptcha is not enabled.");
|
||||
}
|
||||
|
||||
@@ -2,11 +2,11 @@
|
||||
|
||||
namespace Api {
|
||||
|
||||
use Objects\User;
|
||||
use Objects\Context;
|
||||
|
||||
abstract class VisitorsAPI extends Request {
|
||||
public function __construct(User $user, bool $externalCall = false, array $params = []) {
|
||||
parent::__construct($user, $externalCall, $params);
|
||||
public function __construct(Context $context, bool $externalCall = false, array $params = []) {
|
||||
parent::__construct($context, $externalCall, $params);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -21,18 +21,18 @@ namespace Api\Visitors {
|
||||
use Driver\SQL\Expression\Add;
|
||||
use Driver\SQL\Query\Select;
|
||||
use Driver\SQL\Strategy\UpdateStrategy;
|
||||
use Objects\User;
|
||||
use Objects\Context;
|
||||
|
||||
class ProcessVisit extends VisitorsAPI {
|
||||
public function __construct(User $user, bool $externalCall = false) {
|
||||
parent::__construct($user, $externalCall, array(
|
||||
public function __construct(Context $context, bool $externalCall = false) {
|
||||
parent::__construct($context, $externalCall, array(
|
||||
"cookie" => new StringType("cookie")
|
||||
));
|
||||
$this->isPublic = false;
|
||||
}
|
||||
|
||||
public function _execute(): bool {
|
||||
$sql = $this->user->getSQL();
|
||||
$sql = $this->context->getSQL();
|
||||
$cookie = $this->getParam("cookie");
|
||||
$day = (new DateTime())->format("Ymd");
|
||||
$sql->insert("Visitor", array("cookie", "day"))
|
||||
@@ -47,8 +47,8 @@ namespace Api\Visitors {
|
||||
}
|
||||
|
||||
class Stats extends VisitorsAPI {
|
||||
public function __construct(User $user, bool $externalCall = false) {
|
||||
parent::__construct($user, $externalCall, array(
|
||||
public function __construct(Context $context, bool $externalCall = false) {
|
||||
parent::__construct($context, $externalCall, array(
|
||||
'type' => new StringType('type', 32),
|
||||
'date' => new Parameter('date', Parameter::TYPE_DATE, true, new DateTime())
|
||||
));
|
||||
@@ -81,7 +81,7 @@ namespace Api\Visitors {
|
||||
$date = $this->getParam("date");
|
||||
$type = $this->getParam("type");
|
||||
|
||||
$sql = $this->user->getSQL();
|
||||
$sql = $this->context->getSQL();
|
||||
$query = $sql->select($sql->count(), "day")
|
||||
->from("Visitor")
|
||||
->where(new Compare("count", 1, ">"))
|
||||
|
||||
Reference in New Issue
Block a user