diff --git a/.env b/.env index 77a8897..cd1902a 100644 --- a/.env +++ b/.env @@ -1 +1,2 @@ -SECRET_KEY="rahul_chavan" \ No newline at end of file +SECRET_KEY="rahul_chavan" +FILE_NAME='/home/rahul/Documents/hashlist' \ No newline at end of file diff --git a/src/Exception/FileEncryptorException.php b/src/Exception/FileEncryptorException.php index 11c54af..824be6f 100644 --- a/src/Exception/FileEncryptorException.php +++ b/src/Exception/FileEncryptorException.php @@ -7,7 +7,7 @@ class FileEncryptorException extends Exception { - public function __construct($message = "could not encrypt file", $code = 0, Throwable $previous = null) + public function __construct(string $message = "could not encrypt file", int $code = 0, Throwable $previous = null) { parent::__construct($message, $code, $previous); } diff --git a/src/Exception/FileHandlerException.php b/src/Exception/FileHandlerException.php index a8267a9..97b4d26 100644 --- a/src/Exception/FileHandlerException.php +++ b/src/Exception/FileHandlerException.php @@ -7,7 +7,7 @@ class FileHandlerException extends Exception { - public function __construct($message = "There was an error", $code = 0, Throwable $previous = null) + public function __construct(string $message = "There was an error", int $code = 0, Throwable $previous = null) { parent::__construct($message, $code, $previous); } diff --git a/src/Exception/HashException.php b/src/Exception/HashException.php new file mode 100644 index 0000000..97f9e4f --- /dev/null +++ b/src/Exception/HashException.php @@ -0,0 +1,14 @@ +filename)) { + throw new HashException('file not found'); + } + } + + /** + * @param object $fileHandler + * @param string $storedHashesFile + * @param string $algo + * @return bool + * @throws Exception\FileHandlerException + * @throws HashException + */ + + public function verifyHash(object $fileHandler, string $storedHashesFile, string $algo = self::ALGO_256): bool + { + if (!$fileHandler instanceof FileHandler) { + throw new HashException("object must be instance of " . FileHandler::class); + } + + if (!$storedHashesFile) { + throw new HashException('file not found'); + } + + $file = $fileHandler->open(filename: $storedHashesFile)->searchInCsvFile( + $this->filename, + 'File', + FileHandler::ARRAY_FORMAT + ); + + if (!$file) { + throw new HashException('this file is not hashed'); + } + + $expectedHash = $file['Hash']; + $hash = $this->hashFile($algo); + + if ($hash !== $expectedHash) { + return false; + } + + return true; + } + + /** + * @param string $algo + * @return string + * @throws HashException + */ + + public function hashFile(string $algo = self::ALGO_256): string + { + if (!in_array($algo, [self::ALGO_512, self::ALGO_256])) { + throw new HashException('algorithm not supported'); + } + return hash_file($algo, $this->filename); + } +} diff --git a/tests/unit/FileEncryptorTest.php b/tests/unit/FileEncryptorTest.php index d76d4e5..5b7db54 100644 --- a/tests/unit/FileEncryptorTest.php +++ b/tests/unit/FileEncryptorTest.php @@ -14,12 +14,26 @@ class FileEncryptorTest extends TestCase private static string $secret; + protected function setUp(): void + { + $this->fileEncryptor = new FileEncryptor('movie.csv', self::$secret); + parent::setUp(); + } + + protected function tearDown(): void + { + parent::tearDown(); + $this->fileEncryptor = null; + } + public static function setUpBeforeClass(): void { $dotenv = new Dotenv(); $dotenv->load('.env'); - self::$secret = getenv('SECRET_KEY'); + self::$secret = $_ENV['SECRET_KEY']; + + $content = "Film,Genre,Lead Studio,Audience score %,Profitability,Rotten Tomatoes %,Worldwide Gross,Year\n" . "Zack and Miri Make a Porno,Romance,The Weinstein Company,70,1.747541667,64,$41.94 ,2008\n" . "Youth in Revolt,Comedy,The Weinstein Company,52,1.09,68,$19.62 ,2010\n" @@ -62,7 +76,7 @@ public function throwExceptionIfAlreadyEncrypted() #[Test] public function throwExceptionIfDecryptionFails() { - $this->fileEncryptor = new FileEncryptor("movie.csv", 'wrongSecret'); + $this->fileEncryptor = new FileEncryptor("movie.csv", 'wrong'); $this->expectException(FileEncryptorException::class); $this->expectExceptionMessage('could not decrypt file'); $this->fileEncryptor->decryptFile(); @@ -75,16 +89,4 @@ public function canDecryptFile() $this->assertTrue($isFileDecrypted); } - - protected function setUp(): void - { - $this->fileEncryptor = new FileEncryptor('movie.csv', self::$secret); - parent::setUp(); - } - - protected function tearDown(): void - { - parent::tearDown(); - $this->fileEncryptor = null; - } } diff --git a/tests/unit/FileHashCheckerTest.php b/tests/unit/FileHashCheckerTest.php new file mode 100644 index 0000000..d1e9c62 --- /dev/null +++ b/tests/unit/FileHashCheckerTest.php @@ -0,0 +1,106 @@ +load('.env'); + + $file = $_ENV['FILE_NAME']; // this file contains list of all hashes + + self::$file = $file; + + + file_put_contents("test", "hello world"); + } + + public static function tearDownAfterClass(): void + { + parent::tearDownAfterClass(); + unlink("test"); + unlink("sample"); + } + + #[Test] + public function shouldGenerateValidHashForDifferentAlgo() + { + $expectedHash = "644bcc7e564373040999aac89e7622f3ca71fba1d972fd94a31c3bfbf24e3938"; + + $actualHash = $this->fileHasher->hashFile(); //default ALGO_256 + + $this->assertEquals($expectedHash, $actualHash); + + $expectedHash = "840006653e9ac9e95117a15c915caab81662918e925de9e004f774ff82d7079a40d4d27b1b372657c61d46d470304c88c788b3a4527ad074d1dccbee5dbaa99a"; + + $actualHash = $this->fileHasher->hashFile(FileHashChecker::ALGO_512); + + $this->assertEquals($expectedHash, $actualHash); + } + + #[Test] + public function checkFileIntegrityReturnsTrueIfHashMatch() + { + $isVerified = $this->fileHasher->verifyHash(new FileHandler(), self::$file); + + $this->assertTrue($isVerified); + } + + #[Test] + public function shouldReturnFalseIfFileIsModified() + { + $backup = file_get_contents("test"); + file_put_contents("test", "modified", FILE_APPEND); + + $isVerified = $this->fileHasher->verifyHash(new FileHandler(), self::$file); + + $this->assertfalse($isVerified); + + file_put_contents("test", $backup); + } + + #[Test] + public function shouldReturnFalseIfDifferentAlgoIsUsedForVerifyHash() + { + $isVerified = $this->fileHasher->verifyHash(new FileHandler(), self::$file, FileHashChecker::ALGO_512); + + $this->assertFalse($isVerified); + } + + #[Test] + public function shouldThrowExceptionIfFileIsNotHashed() + { + file_put_contents("sample", "this file is not hashed"); + $this->fileHasher = new FileHashChecker("sample"); + + $this->expectException(HashException::class); + $this->expectExceptionMessage("this file is not hashed"); + $this->fileHasher->verifyHash(new FileHandler(), self::$file, FileHashChecker::ALGO_512); + } + + protected function setUp(): void + { + parent::setUp(); + $this->fileHasher = new FileHashChecker("test"); + } + + protected function tearDown(): void + { + parent::tearDown(); + $this->fileHasher = null; + } +}