From 9cb06dd6e9e30b5cbadf01904aac79bfa9edb90f Mon Sep 17 00:00:00 2001 From: Fahmi Auliya Date: Mon, 17 Feb 2025 21:34:30 +0700 Subject: [PATCH 1/4] [DEV] Add buuild workflow --- .github/workflows/build.yml | 50 +++++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) create mode 100644 .github/workflows/build.yml diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 0000000..a6f09b0 --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,50 @@ +name: Build + +on: + push: + branches: [ master ] + pull_request: + branches: [ master ] + + workflow_dispatch: + +jobs: + build: + runs-on: ubuntu-latest + + strategy: + matrix: + php-versions: ['8.1', '8.2', '8.3'] + + steps: + - name: Checkout source + uses: actions/checkout@v2 + + - name: Setup PHP + uses: shivammathur/setup-php@v2 + with: + php-version: ${{ matrix.php-versions }} + ini-values: memory_limit=2048M + + - name: Get composer cache directory + id: composer-cache + run: echo "::set-output name=dir::$(composer config cache-files-dir)" + + - name: Cache dependencies + uses: actions/cache@v2 + with: + path: ${{ steps.composer-cache.outputs.dir }} + key: ${{ matrix.php-versions }}-composer-${{ hashFiles('**/composer.json') }} + restore-keys: ${{ matrix.php-versions }}-composer- + + - name: Install dependencies + run: composer install --prefer-dist + + - name: Check code standards + run: vendor/bin/phpcs --standard=PSR1,PSR2 -n src + + - name: Run useragent string tests + run: php bin/runner.php --show check + + - name: Run unit tests + run: vendor/bin/phpunit --no-coverage tests/unit \ No newline at end of file From 0a2b9e4adede8e89726454d84788badd71275ca6 Mon Sep 17 00:00:00 2001 From: Fahmi Auliya Date: Wed, 19 Feb 2025 21:20:33 +0700 Subject: [PATCH 2/4] [DEV] Add validator and exception handler. --- source/AlnumVigenereCipher.php | 34 +++++++++++++++++++++ source/BasicVigenereCipher.php | 34 +++++++++++++++++++++ source/VigenereCipherBlueprint.php | 12 ++++++-- source/exceptions/InvalidAlnumException.php | 12 ++++++++ source/exceptions/InvalidBasicException.php | 12 ++++++++ 5 files changed, 102 insertions(+), 2 deletions(-) create mode 100644 source/exceptions/InvalidAlnumException.php create mode 100644 source/exceptions/InvalidBasicException.php diff --git a/source/AlnumVigenereCipher.php b/source/AlnumVigenereCipher.php index bf14c3a..c2ea34d 100644 --- a/source/AlnumVigenereCipher.php +++ b/source/AlnumVigenereCipher.php @@ -1,6 +1,9 @@ key); + + if (! $isValid) { + throw new InvalidAlnumException('Key'); + } + + if ($this->process == ProcessType::ENCRYPT->value) { + $isValid = preg_match($pattern, $this->plainText) && $isValid; + + if (! $isValid) { + throw new InvalidAlnumException('Plain text'); + } + } else { + $isValid = preg_match($pattern, $this->cipherText) && $isValid; + + if (! $isValid) { + throw new InvalidAlnumException('Cipher text'); + } + } + } catch(InvalidAlnumException $e) { + echo $e->errorMessage(); + exit(); + } + + return true; + } } diff --git a/source/BasicVigenereCipher.php b/source/BasicVigenereCipher.php index 80f151b..0f34f60 100644 --- a/source/BasicVigenereCipher.php +++ b/source/BasicVigenereCipher.php @@ -1,6 +1,9 @@ key); + + if (! $isValid) { + throw new InvalidBasicException('Key'); + } + + if ($this->process == ProcessType::ENCRYPT->value) { + $isValid = preg_match($pattern, $this->plainText) && $isValid; + + if (! $isValid) { + throw new InvalidBasicException('Plain text'); + } + } else { + $isValid = preg_match($pattern, $this->cipherText) && $isValid; + + if (! $isValid) { + throw new InvalidBasicException('Cipher text'); + } + } + } catch(InvalidBasicException $e) { + echo $e->errorMessage(); + exit(); + } + + return true; + } } diff --git a/source/VigenereCipherBlueprint.php b/source/VigenereCipherBlueprint.php index c1d58cb..d6e0969 100644 --- a/source/VigenereCipherBlueprint.php +++ b/source/VigenereCipherBlueprint.php @@ -49,17 +49,25 @@ public function __construct(string $process = 'encrypt', string $data = null, st if (! is_null($data) && ! is_null($key)) { $this->setPlainText($data); $this->setKey($key); - $this->encrypt(); + + if ($this->isValid()) { + $this->encrypt(); + } } } else { if (! is_null($data) && ! is_null($key)) { $this->setCipherText($data); $this->setKey($key); - $this->decrypt(); + + if ($this->isValid()) { + $this->decrypt(); + } } } } + abstract public function isValid(): bool; + /** * Method to get current process * diff --git a/source/exceptions/InvalidAlnumException.php b/source/exceptions/InvalidAlnumException.php new file mode 100644 index 0000000..a550793 --- /dev/null +++ b/source/exceptions/InvalidAlnumException.php @@ -0,0 +1,12 @@ +getLine() . ' in ' . $this->getFile() . ': '. PHP_EOL; + $message .= $this->getMessage() . ' is invalid, must be combination of a-z, A-Z, and 0-9!' . PHP_EOL; + + return $message; + } +} diff --git a/source/exceptions/InvalidBasicException.php b/source/exceptions/InvalidBasicException.php new file mode 100644 index 0000000..70e293a --- /dev/null +++ b/source/exceptions/InvalidBasicException.php @@ -0,0 +1,12 @@ +getLine() . ' in ' . $this->getFile() . ': '. PHP_EOL; + $message .= $this->getMessage() . ' is invalid, must be combination of a-z!' . PHP_EOL; + + return $message; + } +} From 74da64d2042f5a74acdf8a4548d30acee1f5f9ab Mon Sep 17 00:00:00 2001 From: Fahmi Auliya Date: Wed, 26 Feb 2025 13:29:15 +0700 Subject: [PATCH 3/4] [TEST] Add Negative Cases for VigenereCipher --- tests/VIgenereCipherTest.php | 57 +++++++++++++++++++++++++++++++----- 1 file changed, 50 insertions(+), 7 deletions(-) diff --git a/tests/VIgenereCipherTest.php b/tests/VIgenereCipherTest.php index 9669c13..fb9befb 100644 --- a/tests/VIgenereCipherTest.php +++ b/tests/VIgenereCipherTest.php @@ -6,9 +6,12 @@ final class VigenereCipherTest extends TestCase { - public function testCanEncryptWithBasicMode():void + const BASIC_ALLOWED_CHARS = '/[a-z]/'; + const ALNUM_ALLOWED_CHARS = '/[a-zA-Z0-9]/'; + + public function testCanEncryptInBasicMode():void { - $allowedChars = '/[a-z]/'; + $allowedChars = $this::BASIC_ALLOWED_CHARS; $data = 'encryptionprocess'; $key = 'thekey'; @@ -25,9 +28,19 @@ public function testCanEncryptWithBasicMode():void $this->assertMatchesRegularExpression($allowedChars, $encrypted); } - public function testCanDecryptWithBasicMode():void + public function testCanNotEncryptInBasicModeWithInvalidKey():void + { + $data = 'encryptionprocess'; + $key = 'thekey-'; + + $encrypted = VigenereCipher::encrypt($data, $key, VigenereMode::BASIC->value); + + $this->assertNull($encrypted); + } + + public function testCanDecryptInBasicMode():void { - $allowedChars = '/[a-z]/'; + $allowedChars = $this::BASIC_ALLOWED_CHARS; $data = 'xugbcnmpsxtphjicw'; $key = 'thekey'; @@ -44,9 +57,19 @@ public function testCanDecryptWithBasicMode():void $this->assertMatchesRegularExpression($allowedChars, $decrypted); } - public function testCanEncryptWithAlphaNumericMode():void + public function testCanNotDecryptInBasicModeWithInvalidKey():void + { + $data = 'xugbcnmpsxtphjicw'; + $key = 'thekey-'; + + $encrypted = VigenereCipher::decrypt($data, $key, VigenereMode::BASIC->value); + + $this->assertNull($encrypted); + } + + public function testCanEncryptInAlphaNumericMode():void { - $allowedChars = '/[a-zA-Z0-9]/'; + $allowedChars = $this::ALNUM_ALLOWED_CHARS; $data = 'Encrypti0nProC3s5'; $key = 'th3kEy'; @@ -63,9 +86,19 @@ public function testCanEncryptWithAlphaNumericMode():void $this->assertMatchesRegularExpression($allowedChars, $encrypted); } + public function testCanNotEncryptInAlphaNumericModeWithInvalidKey():void + { + $data = 'Encrypti0nProC3s5'; + $key = 'th3kEy-'; + + $encrypted = VigenereCipher::encrypt($data, $key, VigenereMode::ALPHA_NUMERIC->value); + + $this->assertNull($encrypted); + } + public function testCanDecryptWithAlphaNumericMode():void { - $allowedChars = '/[a-zA-Z0-9]/'; + $allowedChars = $this::ALNUM_ALLOWED_CHARS; $data = 'Xu5B2NMpTxjPHJWCz'; $key = 'th3kEy'; @@ -82,6 +115,16 @@ public function testCanDecryptWithAlphaNumericMode():void $this->assertMatchesRegularExpression($allowedChars, $decrypted); } + public function testCanNotDecryptInAlphaNumericModeWithInvalidKey():void + { + $data = 'Xu5B2NMpTxjPHJWCz'; + $key = 'th3kEy-'; + + $encrypted = VigenereCipher::decrypt($data, $key, VigenereMode::ALPHA_NUMERIC->value); + + $this->assertNull($encrypted); + } + public function testCanGetBasicVigenereClass(): void { $path = 'amculin\cryptography\classic\\'; From 801d2020f400729f06b49329cd962349a02f3592 Mon Sep 17 00:00:00 2001 From: Fahmi Auliya Date: Wed, 26 Feb 2025 13:31:19 +0700 Subject: [PATCH 4/4] [DEV] Change declaration type --- source/AlnumVigenereCipher.php | 3 ++- source/BasicVigenereCipher.php | 3 ++- source/VigenereCipher.php | 4 ++-- source/VigenereCipherBlueprint.php | 4 ++-- 4 files changed, 8 insertions(+), 6 deletions(-) diff --git a/source/AlnumVigenereCipher.php b/source/AlnumVigenereCipher.php index c2ea34d..301377a 100644 --- a/source/AlnumVigenereCipher.php +++ b/source/AlnumVigenereCipher.php @@ -46,7 +46,8 @@ public function isValid(): bool } } catch(InvalidAlnumException $e) { echo $e->errorMessage(); - exit(); + + return false; } return true; diff --git a/source/BasicVigenereCipher.php b/source/BasicVigenereCipher.php index 0f34f60..f4b615e 100644 --- a/source/BasicVigenereCipher.php +++ b/source/BasicVigenereCipher.php @@ -43,7 +43,8 @@ public function isValid(): bool } } catch(InvalidBasicException $e) { echo $e->errorMessage(); - exit(); + + return false; } return true; diff --git a/source/VigenereCipher.php b/source/VigenereCipher.php index 7695caa..e0aa1a2 100644 --- a/source/VigenereCipher.php +++ b/source/VigenereCipher.php @@ -17,7 +17,7 @@ public static function getClassName(string $mode): string } } - public static function encrypt(string $data, string $key, string $mode = 'basic'): string + public static function encrypt(string $data, string $key, string $mode = 'basic'): string|null { $className = self::getClassName($mode); @@ -28,7 +28,7 @@ public static function encrypt(string $data, string $key, string $mode = 'basic' return $encrypt->getCipherText(); } - public static function decrypt(string $data, string $key, string $mode = 'basic'): string + public static function decrypt(string $data, string $key, string $mode = 'basic'): string|null { $className = self::getClassName($mode); diff --git a/source/VigenereCipherBlueprint.php b/source/VigenereCipherBlueprint.php index d6e0969..bd434d6 100644 --- a/source/VigenereCipherBlueprint.php +++ b/source/VigenereCipherBlueprint.php @@ -94,7 +94,7 @@ public function setProcess(string $process): void * * @return string */ - public function getPlainText(): string + public function getPlainText(): string|null { return $this->plainText; } @@ -138,7 +138,7 @@ public function setKey(string $key): void * * @return string */ - public function getCipherText(): string + public function getCipherText(): string|null { return $this->cipherText; }