0 */ private $id = null; /** Id of the user * * @var int > 0 */ private $userId = null; /** base62 coded key * * @var string */ private $key = null; /** what you can do with this key * * @var array(string) */ private $rights = null; /** until when the key is valid * * @var DateTime */ private $endDate = null; /** Constructor * * sets all the members: * - converts the params to the internal type * - provides input sanitation * * @param mixed $id unique identifier of the apiKey * @param mixed $userId $id of the user the apiKey belongs to * @param mixed $key key identifier/representation * @param mixed $rights set of rights describing what the key is valid for * @param mixed $endDate the last day the key will be valid */ public function __construct($id, $userId, $key, $rights, $endDate) { $this->id = filterId($id); $this->userId = filterId($userId); $this->key = self::isWellFormatted($key) ? $key : null; $this->rights = explode(',', $rights); $this->endDate = DateTime::createFromFormat('Y-m-d', $endDate); // @todo It would be safer to set an endDate in the past as "default" value if ($this->endDate == false) { $this->endDate = null; } } /** Getter for the userId * * @return int >0 representing the id of the user the apiKey is for */ public function getUserId() { return $this->userId; } /** Getter for the apiKey * * @return string base62 coded string representing the apiKey */ public function getKey(){ return $this->key; } /** Checking if the apiKey is valid for a certain action * * @param string $action the action to test the apiKey against * @return boolean true if apiKey is valid for the action, false otherwise */ public function isValidFor(string $action) { // @todo add as validation: does the user exist and is 'active' (?) $today = new DateTime(); return ( $this->id != null && in_array($action, $this->rights) && ($this->endDate->format('Y-m-d') >= $today->format('Y-m-d')) ); } /** request a specific apiKey from the db * * @param string $key the key to request * @return ApiKey found in the db, null otherwise */ public static function loadFromDb(string $key) { if (!self::isWellFormatted($key)) { return null; } $query = 'SELECT * FROM `cwsvjudo`.`participo_apiKeys` WHERE apiKey = :key;'; $params = [':key' => ['value' => $key, 'data_type' => PDO::PARAM_STR]]; $response = dbConnector::query($query, $params); // apiKeys are considered unique. so every other count is treated as error to prevent unprivileged access if (count($response) != 1) { return null; } return ApiKey::fromDbArray($response[0]); } /** Add a key to the DB * * @return void */ public function addToDb() { $query = 'INSERT INTO `cwsvjudo`.`participo_apiKeys` (userId, apiKey, rights, endDate) VALUES (:userId, :apiKey, :rights, :endDate);'; $params = [ ':userId' => ['value' => $this->userId, 'data_type' => PDO::PARAM_INT], ':apiKey' => ['value' => $this->key, 'data_type' => PDO::PARAM_STR], ':rights' => ['value' => implode(',', $this->rights), 'data_type' => PDO::PARAM_STR], ':endDate' => ['value' => $this->endDate->format('Y-m-d'), 'data_type' => PDO::PARAM_STR] ]; $response = dbConnector::query($query, $params); // @todo use the response in an error handling/messaging // @todo differentiate between inserting and updating if the id is set it should only be updated (e.g. prolonging) } /** create an Api key from the return of an sql select */ private static function fromDbArray(array $apiKey) { return new ApiKey( $apiKey['id'] ?? null, $apiKey['userId'] ?? null, $apiKey['apiKey'] ?? null, $apiKey['rights'] ?? null, $apiKey['endDate'] ?? null ); } /** * List of symbols that can be used for the encoding * * @var string */ private static $BASE = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'; /** quick and dirty implementation of a convert_to_base62 * * stolen from https://stackoverflow.com/a/4964352 * * @param [int] $num * @param integer $b * @return void */ private static function toBase($num, $b = 62) :string { $b = filter_var($id, FILTER_VALIDATE_INT, ['options' => ['default' => strlen(self::$BASE), 'min_range' => 1]]); // @todo What is with negative numbers? How are they supposed to be converted? $r = $num % $b ; $res = ApiKey::$BASE[$r]; $q = floor($num / $b); while ($q) { $r = $q % $b; $q = floor($q / $b); $res = ApiKey::$BASE[$r] . $res; } return $res; } /** simple check if a string is a well formatted apiKey * * Basically checks, if it consists only of 0-9, a-z or A-Z * * @param string $string string to check * @return boolean true if it is base62 encoded, false otherwise */ public static function isWellFormatted(string $string) { return (bool) preg_match('/^[0-9a-zA-Z]+$/', $string); } /** provides a random api key value * * @return string a random api key value */ public static function create() { // @todo What is with negative numbers? How are they supposed to be converted? return ApiKey::toBase(random_int(0, PHP_INT_MAX)); } /** more of a backup */ private static function createTable() { dbConnector::query("CREATE TABLE `cwsvjudo`.`participo_apiKeys` (`id` INT NOT NULL AUTO_INCREMENT COMMENT 'unique identifier' , `userId` INT NOT NULL COMMENT 'id of the user the key belongs to' , `apiKey` VARCHAR(16) NOT NULL COMMENT 'the apiKey itself' , `rights` INT NOT NULL COMMENT 'a comma separated list of rights for the key' , `endDate` DATE NOT NULL COMMENT 'endDate for the apiKey' , PRIMARY KEY (`id`), UNIQUE (`key`)); "); } }