diff --git a/.travis.yml b/.travis.yml index 54eaca7..2434d90 100644 --- a/.travis.yml +++ b/.travis.yml @@ -8,28 +8,41 @@ cache: - $HOME/.composer/cache php: - - 5.4 - - 5.5 - - 5.6 - - 7.0 + - 7.2 - 7.1 + - 7.0 + - 5.6 + - 5.5 + - 5.4 + - nightly - hhvm - + matrix: - allow_failures: - - php: hhvm - - php: 7.1 + allow_failures: + - php: nightly + - php: hhvm # run build against hhvm but allow them to fail env: - TYPE=mysql DSN=mysql://root@localhost/spot_test - TYPE=pgsql DSN=pgsql://postgres@localhost/spot_test" - - TYPE=sqlite DSN=sqlite::memory + - TYPE=sqlite DSN=sqlite:/tmp/db.sqlite install: - composer install # execute any number of scripts before the test run, custom env's are available as variables before_script: + # Disable the HHVM JIT for faster Unit Testing + - if [[ $TRAVIS_PHP_VERSION = hhv* ]]; then + echo 'hhvm.jit = 0' >> /etc/hhvm/php.ini; + echo 'open_basedir = /tmp:/home/travis/' >> /etc/hhvm/php.ini; + fi + # Disable DEPRECATE messages during PHPUnit initialization on PHP 7.2. To fix them, PHPUnit should be updated to 6.* + - if [[ $TRAVIS_PHP_VERSION == 7.2 ]] || [[ $TRAVIS_PHP_VERSION == "nightly" ]]; then + echo 'Disabled DEPRECATED notifications for PHP 7.2'; + echo 'error_reporting = E_ALL & ~E_DEPRECATED' >> /tmp/php-config.ini; + phpenv config-add /tmp/php-config.ini; + fi - if [[ "$TYPE" == "mysql" ]]; then mysql -e "create database IF NOT EXISTS spot_test;" -uroot; fi - if [[ "$TYPE" == "pgsql" ]]; then psql -c 'create database spot_test;' -U postgres; fi diff --git a/lib/Config.php b/lib/Config.php index 2bb7b5a..703a50d 100644 --- a/lib/Config.php +++ b/lib/Config.php @@ -189,7 +189,7 @@ public static function parseDsn($dsn) $parsed['dbsyntax'] = $str; } - if ( !count( $dsn ) ) { + if ( !isset( $dsn ) ) { return $parsed; } diff --git a/tests/Entity.php b/tests/Entity.php index c51dbb8..1c10544 100644 --- a/tests/Entity.php +++ b/tests/Entity.php @@ -37,6 +37,7 @@ public static function tearDownAfterClass() public function testEntitySetDataProperties() { + $currentDateTime = new \DateTime(); $mapper = test_spot_mapper('SpotTest\Entity\Post'); $post = new \SpotTest\Entity\Post(); @@ -44,6 +45,7 @@ public function testEntitySetDataProperties() $post->title = "My Awesome Post"; $post->body = "

Body

"; $post->author_id = 1; + $post->date_created = $currentDateTime; $data = $post->data(); ksort($data); @@ -53,7 +55,7 @@ public function testEntitySetDataProperties() 'title' => 'My Awesome Post', 'body' => '

Body

', 'status' => 0, - 'date_created' => new \DateTime(), + 'date_created' => $currentDateTime, 'data' => null, 'author_id' => 1 ]; @@ -66,14 +68,15 @@ public function testEntitySetDataProperties() public function testEntitySetDataConstruct() { + $currentDateTime = new \DateTime(); $mapper = test_spot_mapper('SpotTest\Entity\Post'); $post = new \SpotTest\Entity\Post([ 'title' => 'My Awesome Post', 'body' => '

Body

', 'author_id' => 1, - 'date_created' => new \DateTime() + 'date_created' => $currentDateTime ]); - + $data = $post->data(); ksort($data); @@ -85,7 +88,7 @@ public function testEntitySetDataConstruct() 'date_created' => null, 'data' => null, 'author_id' => 1, - 'date_created' => new \DateTime() + 'date_created' => $currentDateTime ]; ksort($testData); diff --git a/tests/Relations.php b/tests/Relations.php index 8d8afdf..cd6208c 100644 --- a/tests/Relations.php +++ b/tests/Relations.php @@ -102,6 +102,7 @@ public function testHasManyRelationCountZero() $post = $mapper->get(); $post->title = "No Comments"; $post->body = "

Comments relation test

"; + $post->author_id = 1; $mapper->save($post); $this->assertSame(0, count($post->comments)); diff --git a/tests/Type/Encrypted.php b/tests/Type/Encrypted.php index 7cac484..0b380a7 100644 --- a/tests/Type/Encrypted.php +++ b/tests/Type/Encrypted.php @@ -7,11 +7,13 @@ class Encrypted extends Type { public static $key; + private static $hashing = 'SHA256'; + private static $cipher = 'AES-128-CBC'; public function convertToPHPValue($value, AbstractPlatform $platform) { if (is_string($value)) { - $value = self::aes256_decrypt(self::$key, base64_decode($value)); + $value = self::aes256_decrypt(self::$key, self::$hashing, self::$cipher, base64_decode($value)); } else { $value = null; } @@ -21,7 +23,7 @@ public function convertToPHPValue($value, AbstractPlatform $platform) public function convertToDatabaseValue($value, AbstractPlatform $platform) { - return base64_encode(self::aes256_encrypt(self::$key, $value)); + return base64_encode(self::aes256_encrypt(self::$key, self::$hashing, self::$cipher, $value)); } public function getName() @@ -34,21 +36,51 @@ public function getSqlDeclaration(array $fieldDeclaration, AbstractPlatform $pla return 'TEXT'; } - private function aes256_encrypt($key, $data) + private function aes256_encrypt($key, $hashing, $cipher, $data) { - if(32 !== strlen($key)) $key = hash('SHA256', $key, true); - $padding = 16 - (strlen($data) % 16); - $data .= str_repeat(chr($padding), $padding); - - return mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $key, $data, MCRYPT_MODE_CBC, str_repeat("\0", 16)); + if(32 !== strlen($key)) $key = hash($hashing, $key, true); + + $ivlen = openssl_cipher_iv_length($cipher); + $iv = openssl_random_pseudo_bytes($ivlen); + $ciphertext_raw = openssl_encrypt($data, $cipher, $key, $options = OPENSSL_RAW_DATA, $iv); + $hmac = hash_hmac($hashing, $ciphertext_raw, $key, $as_binary = true); + + return $iv.$hmac.$ciphertext_raw; } - private function aes256_decrypt($key, $data) + private function aes256_decrypt($key, $hashing, $cipher, $data) { - if(32 !== strlen($key)) $key = hash('SHA256', $key, true); - $data = mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $key, $data, MCRYPT_MODE_CBC, str_repeat("\0", 16)); - $padding = ord($data[strlen($data) - 1]); + if(32 !== strlen($key)) $key = hash($hashing, $key, true); + + $ivlen = openssl_cipher_iv_length($cipher); + $iv = substr($data, 0, $ivlen); + $hmac = substr($data, $ivlen, $sha2len = 32); + $ciphertext_raw = substr($data, $ivlen + $sha2len); + $original = openssl_decrypt($ciphertext_raw, $cipher, $key, $options = OPENSSL_RAW_DATA, $iv); + $calcmac = hash_hmac($hashing, $ciphertext_raw, $key, $as_binary = true); + + if (hash_equals($hmac, $calcmac)) { // PHP 5.6+ timing attack safe comparison + return $original; + } else { + throw new \RuntimeException("Timing attack safe string comparison failed."); + } + } +} - return substr($data, 0, -$padding); +/* + * Added hash_equals to support PHP 5.4 and PHP 5.5 + * hash_equals is built-in from PHP 5.6 + * Source: http://php.net/manual/en/function.hash-equals.php + */ +if(!function_exists('hash_equals')) { + function hash_equals($str1, $str2) { + if(strlen($str1) != strlen($str2)) { + return false; + } else { + $res = $str1 ^ $str2; + $ret = 0; + for($i = strlen($res) - 1; $i >= 0; $i--) $ret |= ord($res[$i]); + return !$ret; + } } }