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() . '
'; + return null; + } + + // Zeichensatzkonvertierung + if (is_array($ret)) { + foreach ($ret as &$entry) { + array_walk( + $entry, + function (&$value, $key, $someOptions) { + $value = iconv($someOptions['dbCharset'], $someOptions['outCharset'], $value); + }, + $someOptions + ); + } + } + return $ret; + } + + // get a Connection to the database + private static function connectToPdo($hostname, $dbName, $user, $password) + { + // var_dump($hostname, $dbName, $user, $password); + $dbConnection = null; + try { + $dbConnection = new PDO( + 'mysql:host=' . $hostname . ';dbname=' . $dbName, + $user, + $password + ); + } catch(PDOException $dbError) { + echo('Error whilst getting a dbConnection!: ' . $dbError->getMessage()); + } + return $dbConnection; + } + + // set the dbConnection (just setting, no establishing) + private static function setDbConnection($dbConnection) + { + $success = false; + if ($dbConnection instanceof PDO) { + self::$db = $dbConnection; + $success = true; + } else { + self::$db = null; + } + } +} diff --git a/homepage/participo/lib/participoLib/participo.php b/homepage/participo/lib/participoLib/participo.php index e8808f2..b617318 100644 --- a/homepage/participo/lib/participoLib/participo.php +++ b/homepage/participo/lib/participoLib/participo.php @@ -1,4 +1,6 @@ isValidFor('login')) { + // query *all* users with the entered name + // @todo check for e.g., len(user)=1 + // @todo getUser? + $user = dbConnector::query( + 'SELECT `id`, `loginName`, `config` FROM `wkParticipo_Users` WHERE `id` = :id', + ['id' => ['value' => $key->getUserId(), 'data_type' => PDO::PARAM_INT]] + ); + $user = $user[0]; + + // case valid login: Set the session data + $_SESSION = [ + 'login' => true, + 'user' => [ + 'username' => $user['loginName'], + 'userId' => $user['id'], + 'userConfig' => json_decode($user['config'], true) + ] + ]; + }; + } + } + if (!self::isLoginValid()) { header('Location: login?returnToUrl=' . urlencode($_SERVER['REQUEST_URI'] . ($_POST['fragment'] ?? '')), true, 301); exit(); // should'nt matter @@ -430,126 +460,6 @@ function logLoginsToJsonFile($userName, $fileName = 'lastLogins.json') } } -/** - * interface for connecting and communicating with a database - */ -class dbConnector -{ - private static $db = null; - - // connect to the database - public static function connect($hostname, $dbName, $user, $password) - { - return self::setDbConnection(self::connectToPdo($hostname, $dbName, $user, $password)); - } - - public static function getDbConnection() - { - return self::$db; - } - - /// perform a pdo-query - /// - /// @param $aQueryString - /// @param $aBindArray e.g. array( - /// ':userId' => 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 = []) - { - // 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() . '
'; - return null; - } - - // Zeichensatzkonvertierung - if (is_array($ret)) { - foreach ($ret as &$entry) { - array_walk( - $entry, - function (&$value, $key, $someOptions) { - $value = iconv($someOptions['dbCharset'], $someOptions['outCharset'], $value); - }, - $someOptions - ); - } - } - return $ret; - } - - // get a Connection to the database - private static function connectToPdo($hostname, $dbName, $user, $password) - { - $dbConnection = null; - try { - $dbConnection = new PDO( - 'mysql:host=' . $hostname . ';dbname=' . $dbName, - $user, - $password - ); - } catch(PDOException $dbError) { - echo('Error whilst getting a dbConnection!: ' . $dbError->getMessage()); - } - return $dbConnection; - } - - // set the dbConnection (just setting, no establishing) - private static function setDbConnection($dbConnection) - { - $success = false; - if ($dbConnection instanceof PDO) { - self::$db = $dbConnection; - $success = true; - } else { - self::$db = null; - } - } -} - /** * User for the Participo system */ diff --git a/homepage/participo/lib/participoLib/planer.php b/homepage/participo/lib/participoLib/planer.php index 8857836..e3eaad8 100644 --- a/homepage/participo/lib/participoLib/planer.php +++ b/homepage/participo/lib/participoLib/planer.php @@ -1,4 +1,5 @@ "Es wurden nicht alle Felder ausgefüllt."]; + $message = ['error' => 'Es wurden nicht alle Felder ausgefüllt.']; } else { - if( participo::checkCredentials( $_POST['f']['username'], $_POST['f']['password']) ){ - $returnToUrl = ($_POST['returnToUrl'] ?? ".").($_POST['fragment'] ?? ""); - participo::addMessage('success', "
weiter zum Inhalt.
"); - participo::addMessage('notice', "OnlineApps - cwsvJudo"); - header("Location: " . $returnToUrl, TRUE, 301 ); + if (participo::checkCredentials($_POST['f']['username'], $_POST['f']['password'])) { + $returnToUrl = ($_POST['returnToUrl'] ?? '.') . ($_POST['fragment'] ?? ''); + participo::addMessage('success', '
weiter zum Inhalt.
'); + participo::addMessage('notice', 'OnlineApps - cwsvJudo'); + header('Location: ' . $returnToUrl, true, 301); } } } @@ -44,14 +46,14 @@ else{ - + cwsvJudo Online Apps

Loginseite der Online-Apps der Judoka des CWSV

- +
Benutzerdaten @@ -63,8 +65,12 @@ else{ - "); ?> - "); ?> + '); + } ?> + '); + } ?>