mode = $mode;} public function Add($field, $value, $table = null) { $this->list[] = ["field" => $field, "value" => $value, "table" => $table]; return $this; } public function Sub(Condition $condition) { $this->subs[] = $condition; return $this; } private function checkValue($is, $should) { if (is_array($is)) { if (array_key_exists("ID", $is)) { return $should==$is["ID"]; } else { foreach ($is as $entry) { if ($this->checkValue($entry, $should)) { return true; } } return false; } return in_array($should, $is); } else { return $should==$is; } } public function CheckInput($json) { if ($this->mode=="and") { foreach ($this->list as $cond) { if (!$this->checkValue($json[$cond["field"]], $cond["value"])) { return false; } } foreach ($this->subs as $sub) { if (!$sub->CheckInput($json)) { return false; } } return true; } else if ($this->mode=="or") { foreach ($this->list as $cond) { if ($this->checkValue($json[$cond["field"]], $cond["value"])) { return true; } } foreach ($this->subs as $sub) { if ($sub->CheckInput($json)) { return true; } } return false; } return false; // Failsafe if mode was misconfigured } public function GetFilterCondition() { $conditionList = new \Filter\ConditionList($this->mode); foreach ($this->list as $cond) { $conditionList->Add(new \Filter\Condition($cond["field"], "=", $cond["value"], $cond["table"])); } foreach ($this->subs as $sub) { $conditionList->Add($sub->GetFilterCondition()); } return $conditionList; } public function Export() { if (sizeof($this->list) + sizeof($this->subs) == 1) { return empty($this->list) ? $this->subs[0]->Export() : $this->list[0]; } $ret = [ "mode" => $this->mode, "conditions" => $this->list ]; foreach ($this->subs as &$condition) { $ret["conditions"][] = $condition->Export(); } return $ret; } public static function Make($mode = "and") { return (new self($mode)); } } class Restriction { protected $condition = null; protected $limits = []; public function AddCondition(\Condition $condition) { if (is_null($this->condition)) { $this->condition = \Condition::Make("or"); } $this->condition->Sub($condition); return $this; } public function AddLimits($fields) { if (is_array($fields)) { foreach ($fields as $field) { $this->limits[] = $field; } } else { $this->limits[] = $fields; } return $this; } public function CheckInput($id = null, $json = []) { // Check limits if (!empty($json) && !empty($this->limits)) { foreach ($json as $field => $value) { if (!in_array($field, $this->limits)) { return false; } } } // Check condition return is_null($this->condition) || $this->condition->CheckInput(array_merge(["ID" => $id], $json)); } public function GetFilterCondition() { return is_null($this->condition) ? null : $this->condition->GetFilterCondition(); } public function Export() { return [ "limits" => $this->limits, "condition" => is_null($this->condition) ? null : $this->condition->Export() ]; } } class Right { protected $requiredRight = null; protected $restriction = null; protected $allow = []; public function __construct($requiredRight = null) { $this->requiredRight = $requiredRight; } public function IsApplicable() { return is_null($this->requiredRight) || \Login::HasRight($this->requiredRight); } public function IsAdmin() { return sizeof($this->allow)==6 && is_null($this->restriction); } public function Allow($allow = "readonly") { switch ($allow) { case "admin": $this->allow = ["get", "update", "insert", "remove", "upload", "erase"]; break; case "nodelete": $this->allow = ["get", "update", "insert", "upload"]; break; case "justdata": $this->allow = ["get", "update", "insert", "remove"]; break; case "update": $this->allow = ["get", "update"]; break; case "readonly": $this->allow = ["get"]; break; default: $this->allow = []; } return $this; } public function Require(\Condition $condition) { if (is_null($this->restriction)) { $this->restriction = new \Restriction(); } $this->restriction->AddCondition($condition); return $this; } public function Limit($fields) { if (is_null($this->restriction)) { $this->restriction = new \Restriction(); } $this->restriction->AddLimits($fields); return $this; } public function GetAllowed() { return $this->allow; } public function GetRestriction() { return $this->restriction; } public static function Make($requiredRight = null) { return (new self($requiredRight)); } public static function AllowSelf() { return self::Make()->Allow("readonly")->Require(\Condition::Make()->Add("ID", \Login::ID())); } public static function AllowUpdateSelf() { return self::Make()->Allow("update")->Require(\Condition::Make()->Add("ID", \Login::ID())); } } class Rights { // false == not allowed // array with refs to restrictions [a ... n] == restrictions apply // true == allowed without restrictions protected $actions = [ "get" => false, "update" => false, "insert" => false, "remove" => false, "upload" => false, "erase" => false ]; public function __construct() {} public function Add($right) { // If user already has admin rights or does not posess this right, skip if ($right->IsApplicable()) { $restriction = $right->GetRestriction(); // Parse the right for every action foreach ($right->GetAllowed() as $action) { if (is_null($restriction)) { // No restriction in the added right, so just overwrite current restrictions $this->actions[$action] = true; } else if (is_array($this->actions[$action])) { // Restrictions applied before (or nothing was allowed) and in the new one, so add new restrictions $this->actions[$action][] = $restriction; } else if ($this->actions[$action]===false) { // Not allowed before, but now restrictions apply $this->actions[$action] = [$restriction]; } } } return $this; } public function CheckInput($action, $id = null, $json = []) { if (!is_array($this->actions[$action])) { return $this->actions[$action]; } // At this point, some but not everything is allowed for this user and this action, so check more carefully foreach ($this->actions[$action] as $restriction) { if ($restriction->CheckInput($id, $json)) { return true; } } return false; } public function RestrictFilter() { if (is_array($this->actions["get"])) { $restrictions = new \Filter\ConditionList("or"); foreach ($this->actions["get"] as $restriction) { $filterCondition = $restriction->GetFilterCondition(); if (!is_null($filterCondition)) { $restrictions->Add($filterCondition); } } \Filter\Filter::Restrict($restrictions); return true; } else { return $this->actions["get"]; } } public function Export() { $ret = []; foreach ($this->actions as $action => $restrictions) { if (is_array($restrictions)) { $ret[$action] = []; foreach ($restrictions as $restriction) { $ret[$action][] = $restriction->Export(); } } else { $ret[$action] = $restrictions; } } return $ret; } public static function Make() { return (new self())->Add(\Right::Make("ADMIN")->Allow("admin")); } }