From 6a6680757d95483571f2a31e1184955d9fa84d6e Mon Sep 17 00:00:00 2001 From: Bartek Fabiszewski Date: Wed, 3 Apr 2019 12:15:10 +0200 Subject: [PATCH 1/3] Enable stale probot --- .github/stale.yml | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 .github/stale.yml diff --git a/.github/stale.yml b/.github/stale.yml new file mode 100644 index 0000000..dc90e5a --- /dev/null +++ b/.github/stale.yml @@ -0,0 +1,17 @@ +# Number of days of inactivity before an issue becomes stale +daysUntilStale: 60 +# Number of days of inactivity before a stale issue is closed +daysUntilClose: 7 +# Issues with these labels will never be considered stale +exemptLabels: + - pinned + - security +# Label to use when marking an issue as stale +staleLabel: wontfix +# Comment to post when marking an issue as stale. Set to `false` to disable +markComment: > + This issue has been automatically marked as stale because it has not had + recent activity. It will be closed if no further activity occurs. Thank you + for your contributions. +# Comment to post when closing a stale issue. Set to `false` to disable +closeComment: false From eeb7ec7532561ea2edc6888115bc9fd17540b427 Mon Sep 17 00:00:00 2001 From: Bartek Fabiszewski Date: Wed, 22 May 2019 15:38:19 +0200 Subject: [PATCH 2/3] Fix: setup script problem with sqlite, fixes #90 --- .docker/init.sh | 9 +++- .tests/tests/DbTest.php | 63 ++++++++++++++++++++++ .tests/tests/SetupTest.php | 49 +++++++++++++++++ helpers/db.php | 44 +++++++++++++++ scripts/setup.php | 107 ++++++++++++++++++++----------------- 5 files changed, 220 insertions(+), 52 deletions(-) create mode 100644 .tests/tests/DbTest.php create mode 100644 .tests/tests/SetupTest.php diff --git a/.docker/init.sh b/.docker/init.sh index 1ef40d9..73a9d92 100644 --- a/.docker/init.sh +++ b/.docker/init.sh @@ -10,8 +10,13 @@ chown nginx:nginx /run/nginx sed -i "s/^nobody:.*$/nobody:x:1000:50::nobody:\/:\/sbin\/nologin/" /etc/passwd sed -i "s/^nobody:.*$/nobody:x:50:/" /etc/group -sed -i "s/^\$dbuser = .*$/\$dbuser = \"ulogger\";/" /var/www/html/config.php -sed -i "s/^\$dbpass = .*$/\$dbpass = \"${DB_USER_PASS}\";/" /var/www/html/config.php +if [ "$ULOGGER_DB_DRIVER" = "sqlite" ]; then + sed -i "s/^\$dbuser = .*$//" /var/www/html/config.php + sed -i "s/^\$dbpass = .*$//" /var/www/html/config.php +else + sed -i "s/^\$dbuser = .*$/\$dbuser = \"ulogger\";/" /var/www/html/config.php + sed -i "s/^\$dbpass = .*$/\$dbpass = \"${DB_USER_PASS}\";/" /var/www/html/config.php +fi if [ "$ULOGGER_DB_DRIVER" = "pgsql" ]; then export PGDATA=/data diff --git a/.tests/tests/DbTest.php b/.tests/tests/DbTest.php new file mode 100644 index 0000000..558eadf --- /dev/null +++ b/.tests/tests/DbTest.php @@ -0,0 +1,63 @@ +assertEquals($testDbName, uDb::getDbName($dsn)); + } + } + + public function testGetDbNameEmptyNames() { + $testDbName = ""; + $defaultDSNs = [ + "mysql:host=db.example.com;port=3306;dbname=", + "mysql:host=db.example.com;port=3306", + "", + null, + "unsupported:host=localhost;port=5432;dbname=;user=test;password=mypass", + "corrupt", + "pgsql:", + "sqlite", + "sqlite3", + "sqlite:" + ]; + + foreach ($defaultDSNs as $dsn) { + $this->assertEquals($testDbName, uDb::getDbName($dsn)); + } + + } + + public function testGetDbFilename() { + $testFileNames = [ + "C:\\Program Files\\Database.db", + ":memory:", + "/tmp/testdb.db3" + ]; + + foreach ($testFileNames as $fileName) { + $this->assertEquals($fileName, uDb::getDbName("sqlite:$fileName")); + } + } +} + +?> \ No newline at end of file diff --git a/.tests/tests/SetupTest.php b/.tests/tests/SetupTest.php new file mode 100644 index 0000000..88be791 --- /dev/null +++ b/.tests/tests/SetupTest.php @@ -0,0 +1,49 @@ +http->get($this->script); + $this->assertEquals(200, $response->getStatusCode(), "Unexpected status code"); + $body = (string) $response->getBody(); + $this->assertContains("", $body); + } + + public function testSetupPhase() { + $options = [ + "http_errors" => false, + "form_params" => [ "command" => "setup" ] + ]; + $response = $this->http->post($this->script, $options); + $this->assertEquals(200, $response->getStatusCode(), "Unexpected status code"); + $body = (string) $response->getBody(); + $this->assertContains("", $body); + } + + public function testAdduserPhase() { + $options = [ + "http_errors" => false, + "form_params" => [ + "command" => "adduser", + "login" => $this->testUser, + "pass" => $this->testPass, + "pass2" => $this->testPass + ] + ]; + $response = $this->http->post($this->script, $options); + $this->assertEquals(200, $response->getStatusCode(), "Unexpected status code"); + $body = (string) $response->getBody(); + $this->assertContains("", $body); + $this->assertEquals(2, $this->getConnection()->getRowCount("users"), "Wrong row count"); + $expected = [ "id" => 2, "login" => $this->testUser ]; + $actual = $this->getConnection()->createQueryTable("users", "SELECT id, login FROM users WHERE id = 2"); + $this->assertTableContains($expected, $actual, "Wrong actual table data"); + $this->assertTrue(password_verify($this->testPass, $this->pdoGetColumn("SELECT password FROM users WHERE id = 2")), "Wrong actual password hash"); + } + +} + +?> \ No newline at end of file diff --git a/helpers/db.php b/helpers/db.php index adbfc3c..de6392c 100644 --- a/helpers/db.php +++ b/helpers/db.php @@ -101,6 +101,11 @@ return self::$tables[$name]; } + /** + * Returns function name for getting date-time column value as unix timestamp + * @param string $column + * @return string + */ public function unix_timestamp($column) { switch (self::$driver) { default: @@ -116,6 +121,11 @@ } } + /** + * Returns function name for getting date-time column value as 'YYYY-MM-DD hh:mm:ss' + * @param string $column + * @return string + */ public function from_unixtime($column) { switch (self::$driver) { default: @@ -131,10 +141,44 @@ } } + /** + * Set character set + * @param string $charset + */ private function setCharset($charset) { if (self::$driver == "pgsql" || self::$driver == "mysql") { $this->query("SET NAMES '$charset'"); } } + + /** + * Extract database name from DSN + * @param string $dsn + * @return string Empty string if not found + */ + static public function getDbName($dsn) { + $name = ""; + if (strpos($dsn, ":") !== false) { + list($scheme, $dsnWithoutScheme) = explode(":", $dsn, 2); + switch ($scheme) { + case "sqlite": + case "sqlite2": + case "sqlite3": + $pattern = "/(.+)/"; + break; + case "pgsql": + $pattern = "/dbname=([^; ]+)/"; + break; + default: + $pattern = "/dbname=([^;]+)/"; + break; + } + $result = preg_match($pattern, $dsnWithoutScheme, $matches); + if ($result === 1) { + $name = $matches[1]; + } + } + return $name; + } } ?> diff --git a/scripts/setup.php b/scripts/setup.php index b606431..f86246a 100644 --- a/scripts/setup.php +++ b/scripts/setup.php @@ -24,50 +24,52 @@ $enabled = false; /* -------------------------------------------- */ /* no user modifications should be needed below */ -if (version_compare(PHP_VERSION, '5.4.0', '<')) { +if (version_compare(PHP_VERSION, "5.4.0", "<")) { die("Sorry, ulogger will not work with PHP version lower than 5.4 (you have " . PHP_VERSION . ")"); } define("ROOT_DIR", dirname(__DIR__)); -require_once(ROOT_DIR . "/helpers/user.php"); +require_once(ROOT_DIR . "/helpers/db.php"); require_once(ROOT_DIR . "/helpers/config.php"); -require_once(ROOT_DIR . "/helpers/utils.php"); require_once(ROOT_DIR . "/helpers/lang.php"); +require_once(ROOT_DIR . "/helpers/user.php"); +require_once(ROOT_DIR . "/helpers/utils.php"); -$command = uUtils::postString('command'); +$command = uUtils::postString("command"); $lang = (new uLang(uConfig::$lang))->getStrings(); $langSetup = (new uLang(uConfig::$lang))->getSetupStrings(); -$prefix = preg_replace('/[^a-z0-9_]/i', '', uConfig::$dbprefix); +$prefix = preg_replace("/[^a-z0-9_]/i", "", uConfig::$dbprefix); $tPositions = $prefix . "positions"; $tTracks = $prefix . "tracks"; $tUsers = $prefix . "users"; -$dbDriver = null; $messages = []; + switch ($command) { case "setup": $error = false; try { - $options = [ PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION ]; - $pdo = new PDO(uConfig::$dbdsn, uConfig::$dbuser, uConfig::$dbpass, $options); - $dbDriver = $pdo->getAttribute(PDO::ATTR_DRIVER_NAME); + $pdo = getPdo(); } catch (PDOException $e) { $messages[] = "{$langSetup["dbconnectfailed"]}"; - $messages[] = sprintf($langSetup["serversaid"], "" . $e->getMessage() . ""); + $messages[] = sprintf($langSetup["serversaid"], "" . htmlentities($e->getMessage()) . ""); $messages[] = $langSetup["checkdbsettings"]; break; } try { - $queries = getQueries(); + $queries = getQueries($pdo->getAttribute(PDO::ATTR_DRIVER_NAME)); + $pdo->beginTransaction(); foreach ($queries as $query) { $pdo->query($query); } + $pdo->commit(); } catch (PDOException $e) { + $pdo->rollBack(); $messages[] = "{$langSetup["dbqueryfailed"]}"; - $messages[] = sprintf($langSetup["serversaid"], "" . $e->getMessage() . ""); + $messages[] = sprintf($langSetup["serversaid"], "" . htmlentities($e->getMessage()) . ""); $error = true; } $pdo = null; @@ -85,8 +87,8 @@ switch ($command) { break; case "adduser": - $login = uUtils::postString('login'); - $pass = uUtils::postPass('pass'); + $login = uUtils::postString("login"); + $pass = uUtils::postPass("pass"); if (uUser::add($login, $pass) !== false) { $messages[] = "{$langSetup["congratulations"]}"; @@ -107,7 +109,7 @@ switch ($command) { $messages[] = "
"; break; } - if (!function_exists('password_hash')) { + if (!function_exists("password_hash")) { $messages[] = $langSetup["passfuncwarn"]; $messages[] = $langSetup["passfunchack"]; $messages[] = sprintf($langSetup["lineshouldread"], "
//require_once(ROOT_DIR . \"/helpers/password.php\");
", "
require_once(ROOT_DIR . \"/helpers/password.php\");"); @@ -121,18 +123,7 @@ switch ($command) { $messages[] = "
"; break; } - if (empty(uConfig::$dbdsn) || ($dbDriver != "sqlite" && empty(uConfig::$dbuser))) { - if ($dbDriver == "sqlite") { - $required = "\$dbdsn"; - } else { - $required = "\$dbdsn, \$dbuser, \$dbpass"; - } - $messages[] = sprintf($langSetup["nodbsettings"], $required); - $messages[] = $langSetup["dorestart"]; - $messages[] = "
"; - break; - } - if (ini_get("session.auto_start") == '1') { + if (ini_get("session.auto_start") == "1") { $messages[] = sprintf($langSetup["optionwarn"], "session.auto_start", "0 (off)"); $messages[] = $langSetup["dorestart"]; $messages[] = "
"; @@ -144,14 +135,42 @@ switch ($command) { $messages[] = "
"; break; } - $messages[] = sprintf($langSetup["scriptdesc"], "'$tPositions', '$tTracks', '$tUsers'", "" . getDbname(uConfig::$dbdsn) . ""); + if (empty(uConfig::$dbdsn)) { + $messages[] = sprintf($langSetup["nodbsettings"], "\$dbdsn"); + $messages[] = $langSetup["dorestart"]; + $messages[] = "
"; + break; + } + try { + $pdo = getPdo(); + } catch (PDOException $e) { + $isSqlite = stripos(uConfig::$dbdsn, "sqlite") === 0; + if (!$isSqlite && empty(uConfig::$dbuser)) { + $messages[] = sprintf($langSetup["nodbsettings"], "\$dbuser, \$dbpass"); + } else { + $messages[] = $langSetup["dbconnectfailed"]; + $messages[] = $langSetup["checkdbsettings"]; + $messages[] = sprintf($langSetup["serversaid"], "" . htmlentities($e->getMessage()) . ""); + } + $messages[] = $langSetup["dorestart"]; + $messages[] = "
"; + break; + } + $pdo = null; + $dbName = uDb::getDbName(uConfig::$dbdsn); + $dbName = empty($dbName) ? '""' : "" . htmlentities($dbName) . ""; + $messages[] = sprintf($langSetup["scriptdesc"], "'$tPositions', '$tTracks', '$tUsers'", $dbName); $messages[] = $langSetup["scriptdesc2"]; $messages[] = "
"; break; } -function getQueries() { - global $tPositions, $tUsers, $tTracks, $dbDriver; +/** + * @param string $dbDriver + * @return array + */ +function getQueries($dbDriver) { + global $tPositions, $tUsers, $tTracks; $queries = []; switch ($dbDriver) { @@ -284,26 +303,14 @@ function getQueries() { return $queries; } -function getDbname($dsn) { - if (strpos($dsn, ':') !== false) { - list($scheme, $dsnWithoutScheme) = explode(':', $dsn, 2); - switch ($scheme) { - case 'sqlite': - case 'sqlite2': - case 'sqlite3': - return $dsnWithoutScheme; - break; - - default: - $pattern = '~dbname=([^;]*)(?:;|$)~'; - $result = preg_match($pattern, $dsnWithoutScheme, $matches); - if ($result === 1 && !empty($matches[1])) { - return $matches[1]; - } - break; - } - } - return "noname"; +/** + * @return PDO + * @throws PDOException + */ +function getPdo() { + $options = [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION]; + $pdo = new PDO(uConfig::$dbdsn, uConfig::$dbuser, uConfig::$dbpass, $options); + return $pdo; } ?> From cd5255cbb83a52c96cdca4d68b20be8c8d245bea Mon Sep 17 00:00:00 2001 From: Bartek Fabiszewski Date: Thu, 23 May 2019 10:58:57 +0200 Subject: [PATCH 3/3] Minor code cleanup --- .tests/lib/UloggerAPITestCase.php | 4 ++-- .tests/tests/ImportTest.php | 7 ++++++- .tests/tests/InternalAPITest.php | 7 ++++++- .tests/tests/PositionTest.php | 2 +- composer.json | 5 +++-- helpers/auth.php | 7 +++++-- helpers/position.php | 4 +--- helpers/track.php | 5 ----- helpers/user.php | 2 -- scripts/import_cli.php | 4 ++-- utils/export.php | 1 - 11 files changed, 26 insertions(+), 22 deletions(-) diff --git a/.tests/lib/UloggerAPITestCase.php b/.tests/lib/UloggerAPITestCase.php index c98334e..45eb67e 100644 --- a/.tests/lib/UloggerAPITestCase.php +++ b/.tests/lib/UloggerAPITestCase.php @@ -35,8 +35,8 @@ class UloggerAPITestCase extends BaseDatabaseTestCase { /** * Authenticate on server - * @param string $user Login - * + * @param string|null $user Login (defaults to test user) + * @param string|null $pass Optional password (defaults to test password) * @return bool true on success, false otherwise */ public function authenticate($user = NULL, $pass = NULL) { diff --git a/.tests/tests/ImportTest.php b/.tests/tests/ImportTest.php index 0febee2..a59a9f1 100644 --- a/.tests/tests/ImportTest.php +++ b/.tests/tests/ImportTest.php @@ -1,5 +1,7 @@ assertEquals(0, $this->getConnection()->getRowCount("positions"), "Wrong row count"); } - + /** + * @param ResponseInterface $response + * @return bool|SimpleXMLElement + */ private function getXMLfromResponse($response) { $xml = false; libxml_use_internal_errors(true); diff --git a/.tests/tests/InternalAPITest.php b/.tests/tests/InternalAPITest.php index 8828954..ea8f652 100644 --- a/.tests/tests/InternalAPITest.php +++ b/.tests/tests/InternalAPITest.php @@ -1,5 +1,7 @@ assertEquals(1, $this->getConnection()->getRowCount("users"), "Wrong row count"); } - + /** + * @param ResponseInterface $response + * @return bool|SimpleXMLElement + */ private function getXMLfromResponse($response) { $xml = false; libxml_use_internal_errors(true); diff --git a/.tests/tests/PositionTest.php b/.tests/tests/PositionTest.php index 72bf59f..98a6f0b 100644 --- a/.tests/tests/PositionTest.php +++ b/.tests/tests/PositionTest.php @@ -133,7 +133,7 @@ class PositionTest extends UloggerDatabaseTestCase { $this->assertEquals($trackId2, $position->trackId); break; default: - $this->assert("Unexpected position: {$position->id}"); + $this->assertTrue(false, "Unexpected position: {$position->id}"); } } } diff --git a/composer.json b/composer.json index 4561df0..292e2b0 100644 --- a/composer.json +++ b/composer.json @@ -3,7 +3,9 @@ "ulrichsg/getopt-php": "^3.2", "ext-json": "*", "ext-pdo": "*", - "ext-xmlwriter": "*" + "ext-xmlwriter": "*", + "ext-simplexml": "*", + "ext-libxml": "*" }, "scripts": { "test": "./vendor/bin/phpunit" @@ -13,6 +15,5 @@ "vlucas/phpdotenv": "^3.3", "guzzlehttp/guzzle": "^6.3", "phpunit/dbunit": "^2.0" - } } diff --git a/helpers/auth.php b/helpers/auth.php index 056fac4..6206bd2 100644 --- a/helpers/auth.php +++ b/helpers/auth.php @@ -28,6 +28,7 @@ class uAuth { private $isAuthenticated = false; + /** @var null|uUser */ public $user = null; public function __construct() { @@ -105,9 +106,11 @@ } /** - * Process log in request + * Check valid pass for given login * - * @return void + * @param $login + * @param $pass + * @return boolean True if valid */ public function checkLogin($login, $pass) { if (!is_null($login) && !is_null($pass)) { diff --git a/helpers/position.php b/helpers/position.php index 887e39e..10e6cca 100644 --- a/helpers/position.php +++ b/helpers/position.php @@ -57,8 +57,6 @@ public $isValid = false; - private static $db; - /** * Constructor * @param integer $positionId Position id @@ -235,7 +233,7 @@ * * @param int $userId Optional limit to given user id * @param int $trackId Optional limit to given track id - * @return array|bool Array of uPosition positions, false on error + * @return uPosition[]|bool Array of uPosition positions, false on error */ public static function getAll($userId = NULL, $trackId = NULL) { $rules = []; diff --git a/helpers/track.php b/helpers/track.php index 3e7eacc..e2aecf2 100644 --- a/helpers/track.php +++ b/helpers/track.php @@ -31,11 +31,6 @@ public $isValid = false; - /** - * @var uDb $db - */ - private static $db = null; - /** * Constructor * diff --git a/helpers/user.php b/helpers/user.php index 7496829..1decc2a 100644 --- a/helpers/user.php +++ b/helpers/user.php @@ -34,8 +34,6 @@ public $isAdmin = false; public $isValid = false; - private static $db = null; - /** * Constructor * diff --git a/scripts/import_cli.php b/scripts/import_cli.php index cd811af..30ff49d 100644 --- a/scripts/import_cli.php +++ b/scripts/import_cli.php @@ -47,7 +47,7 @@ $getopt->addOptions([ Option::create('h', 'help') ->setDescription('Show usage/help'), - Option::create('u', 'user-id', \GetOpt\GetOpt::OPTIONAL_ARGUMENT) + Option::create('u', 'user-id', GetOpt::OPTIONAL_ARGUMENT) ->setDescription('Which user to import the track(s) for (default: 1)') ->setDefaultValue(1) ->setValidation('is_numeric', '%s has to be an integer'), @@ -60,7 +60,7 @@ $getopt->addOptions([ ]); $getopt->addOperand( - Operand::create('gpx', \GetOpt\Operand::MULTIPLE + \GetOpt\Operand::REQUIRED) + Operand::create('gpx', Operand::MULTIPLE + Operand::REQUIRED) ->setDescription('One or more GPX files to import') ->setValidation('is_readable', '%s: %s is not readable') ); diff --git a/utils/export.php b/utils/export.php index f5f1005..8154a2e 100644 --- a/utils/export.php +++ b/utils/export.php @@ -123,7 +123,6 @@ if ($trackId && $userId) { $totalSeconds = 0; $coordinate = []; foreach ($positionsArr as $position) { - /** @var uPosition $prevPosition */ $distance = isset($prevPosition) ? $position->distanceTo($prevPosition) : 0; $seconds = isset($prevPosition) ? $position->secondsTo($prevPosition) : 0; $prevPosition = $position;