diff --git a/homepage/participo/api.apiKeys.add.php b/homepage/participo/api.apiKeys.add.php new file mode 100644 index 0000000..276caf0 --- /dev/null +++ b/homepage/participo/api.apiKeys.add.php @@ -0,0 +1,38 @@ + false])); + } + + if (!$allowKey->isValidFor('apiKeys.create')) { + die(json_encode(['success' => false])); + } + + $newKey = ApiKey::create(); + $newLoginApiKey = new ApiKey(null, $call['userId'], $newKey, 'login', $call['endDate']); + $newLoginApiKey->addToDb(); + $insertedApiKey = ApiKey::loadFromDb($newKey); + if (!$insertedApiKey) { + die(json_encode(['success' => false])); + } + echo(json_encode(['success' => true, 'apiKey' => $newKey])); +} diff --git a/homepage/participo/config/participo.php b/homepage/participo/config/participo.php index 5770e23..8dd86e0 100644 --- a/homepage/participo/config/participo.php +++ b/homepage/participo/config/participo.php @@ -1,17 +1,12 @@ diff --git a/homepage/participo/events.php b/homepage/participo/events.php index 0e5f5e9..50ed4cc 100644 --- a/homepage/participo/events.php +++ b/homepage/participo/events.php @@ -29,13 +29,10 @@ include_once 'events.inc.php'; function openModal(modalId){ var modalElement = document.querySelector(modalId); if( modalElement === null ){ - console.log(`No modalElement by name ${modalId} found. Won't open!`); return; } var modalInstance = M.Modal.getInstance(modalElement); - console.log("before opening: ", modalInstance); modalInstance.open(); - console.log("after opening: ", modalInstance); } // What to do when the document is loaded. diff --git a/homepage/participo/index.php b/homepage/participo/index.php index eea3e71..084063d 100644 --- a/homepage/participo/index.php +++ b/homepage/participo/index.php @@ -5,8 +5,10 @@ require_once './local/cwsvJudo.php'; require_once './lib/db.php'; // should be replaced require_once './lib/api.php'; // should be replaced + require_once 'participoLib/participo.php'; require_once 'participoLib/planer.php'; +require_once 'participoLib/apiKey.php'; require_once 'config/phpcount.config.php'; require_once 'phpcount/phpcount.php'; @@ -18,10 +20,12 @@ dbConnector::connect( $cwsvJudoConfig['db']['user'], $cwsvJudoConfig['db']['password'] ); + eventPlaner::setDbConnection(dbConnector::getDbConnection()); participo::authentificate(); $userData = getUserData(dbConnector::getDbConnection(), $_SESSION['user']['userId']); ?> +
diff --git a/homepage/participo/lib/api.php b/homepage/participo/lib/api.php index b39ccb0..1b54126 100644 --- a/homepage/participo/lib/api.php +++ b/homepage/participo/lib/api.php @@ -1,15 +1,16 @@ getMessage(); + } catch(Exception $e) { + echo 'Message: ' . $e->getMessage(); } } -function attendancesAssocArray2text($attendancesAssocArray){ - $ret = ""; - foreach($attendancesAssocArray as $date => $attendees){ - $ret .= $date."\n"; - foreach($attendees as $a){ +function attendancesAssocArray2text($attendancesAssocArray) +{ + $ret = ''; + foreach ($attendancesAssocArray as $date => $attendees) { + $ret .= $date . "\n"; + foreach ($attendees as $a) { $ret .= "\n"; - $ret .= "Name: ".$a['name'].", ".$a['vorname']."\n"; - $ret .= "PLZ: ".$a['corona_PLZ']."\n"; - $ret .= "Tel.: ".$a['corona_telephon']."\n"; - $ret .= "eMail: ".$a['corona_eMail']."\n"; + $ret .= 'Name: ' . $a['name'] . ', ' . $a['vorname'] . "\n"; + $ret .= 'PLZ: ' . $a['corona_PLZ'] . "\n"; + $ret .= 'Tel.: ' . $a['corona_telephon'] . "\n"; + $ret .= 'eMail: ' . $a['corona_eMail'] . "\n"; } $ret .= "\n"; } -return $ret; + return $ret; } -function attendancesAssocArray2mdList($attendancesAssocArray, $date=null){ - if($date == null) - $date=new DateTime(); - $ret = "# Anwesenheitsliste zur Corona-Kontaktverfolgung der Abteilung Judo des CWSV vom ".$date->format("Y-m-d")."\n\n"; - foreach($attendancesAssocArray as $d => $attendees){ - $ret .= "## ".$d."\n"; - $i=0; - foreach($attendees as $a){ +function attendancesAssocArray2mdList($attendancesAssocArray, $date = null) +{ + if ($date == null) { + $date = new DateTime(); + } + $ret = '# Anwesenheitsliste zur Corona-Kontaktverfolgung der Abteilung Judo des CWSV vom ' . $date->format('Y-m-d') . "\n\n"; + foreach ($attendancesAssocArray as $d => $attendees) { + $ret .= '## ' . $d . "\n"; + $i = 0; + foreach ($attendees as $a) { $i += 1; $ret .= "\n"; - $ret .= $i." ".$a['name'].", ".$a['vorname']."\n"; - $ret .= " - PLZ: ".$a['corona_PLZ']."\n"; - $ret .= " - Tel.: ".$a['corona_telephon']."\n"; - $ret .= " - eMail: ".$a['corona_eMail']."\n"; + $ret .= $i . ' ' . $a['name'] . ', ' . $a['vorname'] . "\n"; + $ret .= ' - PLZ: ' . $a['corona_PLZ'] . "\n"; + $ret .= ' - Tel.: ' . $a['corona_telephon'] . "\n"; + $ret .= ' - eMail: ' . $a['corona_eMail'] . "\n"; } $ret .= "\n"; } -return $ret; + return $ret; } //! Checks if multiple keys exist in an array @@ -89,19 +92,20 @@ return $ret; //! @param array|string $keys keys to check for //! //! @return bool true, if *all* keys are set in the array -function array_keys_exist( array $array, $keys ) { - if ( ! is_array( $keys ) ) { +function array_keys_exist(array $array, $keys) +{ + if (!is_array($keys)) { $keys = func_get_args(); - array_shift( $keys ); + array_shift($keys); } $count = 0; - foreach ( $keys as $key ) { - if ( isset( $array[$key] ) || array_key_exists( $key, $array ) ) { + foreach ($keys as $key) { + if (isset($array[$key]) || array_key_exists($key, $array)) { $count++; } } - return count( $keys ) === $count; + return count($keys) === $count; } /// updates users password without checking any rights @@ -109,22 +113,22 @@ function array_keys_exist( array $array, $keys ) { /// - $db : pdoDbConnection to use /// - $userId : id of the user with the password to change /// - $password : the password to set -function updateUserPassword($db, $userId, $password){ +function updateUserPassword($db, $userId, $password) +{ // we don't save the actual password but it's hash - if($password != ""){ - $password = password_hash( $password, PASSWORD_DEFAULT); + if ($password != '') { + $password = password_hash($password, PASSWORD_DEFAULT); + } else { + $password = null; } - else{ - $password = NULL; - } - - $query = "UPDATE `cwsvjudo`.`wkParticipo_Users` SET `pwHash`=:val WHERE `id`=:id;"; - $params = array( - ':val' => array('value'=>$password, 'data_type'=>PDO::PARAM_STR), - ':id' => array('value'=>$userId, 'data_type'=>PDO::PARAM_INT) - ); + + $query = 'UPDATE `cwsvjudo`.`wkParticipo_Users` SET `pwHash`=:val WHERE `id`=:id;'; + $params = [ + ':val' => ['value' => $password, 'data_type' => PDO::PARAM_STR], + ':id' => ['value' => $userId, 'data_type' => PDO::PARAM_INT] + ]; dbConnector::query($query, $params); - + return; } @@ -134,43 +138,42 @@ function updateUserPassword($db, $userId, $password){ /// - $changerId: userId who changes the password /// - $changeeId: userId whose password should be changed /// - $ownPassword: password of the user who changes the password -/// - $newPasword: the new password +/// - $newPassword: the new password /// - $newPasswordAgain: controllInput of the new password -function changePassword($db, $changerId, $changeeId, $changerPassword, $newPassword, $newPasswordAgain){ +function changePassword($db, $changerId, $changeeId, $changerPassword, $newPassword, $newPasswordAgain) +{ // we need a dbConnection - if( !$db ){ + if (!$db) { // echo("No DB!"); return false; } - + $changerInfo = getUserData($db, $changerId); - + // check the password of the changer - if( !password_verify( $changerPassword, $changerInfo['pwHash']) ){ + if (!password_verify($changerPassword, $changerInfo['pwHash'])) { // echo("Wrong changerPasswod"); return false; } - + // check if the changer is allowed to change the changees password - if ( $changerId != $changeeId ){ + if ($changerId != $changeeId) { $changersKidsIds = getUsersKidsIds($db, $changerId); - + // if( !in_array($changeeId, $changersKidsIds) ){ - if( !isUserInKidIds($changeeId, $changersKidsIds) ){ + if (!isUserInKidIds($changeeId, $changersKidsIds)) { // echo("not your child: ".$changeeId." not in "); var_dump($changersKidsIds); return false; } } - + // check if the two inputs are the same - if( $newPassword != $newPasswordAgain ){ + if ($newPassword != $newPasswordAgain) { // echo("new pw missmatch"); return false; } - + updateUserPassword($db, $changeeId, $newPassword); - + return true; } - -?> diff --git a/homepage/participo/lib/participoLib/apiKey.php b/homepage/participo/lib/participoLib/apiKey.php new file mode 100644 index 0000000..59956f6 --- /dev/null +++ b/homepage/participo/lib/participoLib/apiKey.php @@ -0,0 +1,153 @@ +id = filter_var($id, FILTER_VALIDATE_INT, ['options' => ['default' => null, 'min_range' => 1]]); + $this->userId = filter_var($userId, FILTER_VALIDATE_INT, ['options' => ['default' => null, 'min_range' => 1]]); + $this->key = self::isWellFormatted($key) ? $key : null; + $this->rights = explode(',', $rights); + $this->endDate = DateTime::createFromFormat('Y-m-d', $endDate); + + if ($this->endDate == false) { + $this->endDate = null; + } + } + + public function getUserId() + { + return $this->userId; + } + + /** + * testing 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]); + } + + 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 + } + + /** 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 + ); + } + + 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 + { + // @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 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)); + } + + 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`)); "); + } +} diff --git a/homepage/participo/lib/participoLib/dbConnector.php b/homepage/participo/lib/participoLib/dbConnector.php new file mode 100644 index 0000000..a9ba3c9 --- /dev/null +++ b/homepage/participo/lib/participoLib/dbConnector.php @@ -0,0 +1,123 @@ + array('value'=>$anUserId, 'data_type'=>PDO::PARAM_INT), + /// ':attributeId'=> array('value'=>$anAttributeId, 'data_type'=>PDO::PARAM_INT) ) + /// @param $someOption + public static function query($aQueryString, $aBindArray = [], $someOptions = []) + { + // var_dump($aQueryString, $aBindArray); + // Standardbelegungen + if (empty($someOptions['dbCharset'])) { + $someOptions['dbCharset'] = 'ISO-8859-1'; + } + if (empty($someOptions['outCharset'])) { + $someOptions['outCharset'] = 'UTF-8'; + } + if (empty($someOptions['dontFetch'])) { + $someOptions['dontFetch'] = false; + } + + /// @toDo: Bisher wird nur die Rückgabe konvertiert. Eigentlich muss + /// doch auch die Eingabe konvertiert werden. Aber das jetzt + /// umzustellen wird schwer! Die User im Wettkampfplaner sind ja z.B. + /// als UTF8 in latin1(?) gespeichert. + /// @toDo: Die Standardwerte sollten vielleicht aus einer config + /// kommen, nicht hardcoded + try { + $pdoStatement = self::$db->prepare($aQueryString); + foreach ($aBindArray as $bindName => $bind) { + if ($bind['data_type'] == PDO::PARAM_STR) { + $bind['value'] = iconv( + $someOptions['outCharset'], + $someOptions['dbCharset'], + $bind['value'] + ); + } + $pdoStatement->bindValue( + $bindName, + $bind['value'], + (isset($bind['data_type']) ? $bind['data_type'] : PDO::PARAM_STR) + ); + } + $pdoResult = $pdoStatement->execute(); + if (!$pdoResult) { + echo("Error during dbQuery!\n"); + echo("DB-Error:\n"); + var_dump(self::$db->errorInfo()); + } + if ($someOptions['dontFetch']) { + $ret = null; + } else { + $ret = $pdoStatement->fetchAll(PDO::FETCH_ASSOC); + } + } catch(PDOException $db_error) { + print 'Error!: ' . $db_error->getMessage() . '