From 36cb0ccd93be6a478853cab941cf80da04e7dcc4 Mon Sep 17 00:00:00 2001 From: Jaspaul Bola Date: Wed, 28 Feb 2018 22:50:50 -0500 Subject: [PATCH] Introduce link and rule for testing safe links --- composer.json | 19 +++++++- phpunit.xml | 1 + resources/config/safe-links.php | 8 +++ resources/translations/safe-links.php | 7 +++ src/Link.php | 70 +++++++++++++++++++++++++++ src/SafeLinkRule.php | 31 ++++++++++++ src/ServiceProvider.php | 45 +++++++++++++++++ tests/LinkTest.php | 26 ++++++++++ tests/SafeLinkRuleTest.php | 26 ++++++++++ tests/TestCase.php | 13 +++++ 10 files changed, 245 insertions(+), 1 deletion(-) create mode 100644 resources/config/safe-links.php create mode 100644 resources/translations/safe-links.php create mode 100644 src/Link.php create mode 100644 src/SafeLinkRule.php create mode 100644 src/ServiceProvider.php create mode 100644 tests/LinkTest.php create mode 100644 tests/SafeLinkRuleTest.php diff --git a/composer.json b/composer.json index dbaa025..152101b 100644 --- a/composer.json +++ b/composer.json @@ -9,7 +9,14 @@ "email": "jaspaul.b@gmail.com" } ], - "require": {}, + "require": { + "google/apiclient": "^2.2", + "google/apiclient-services": "^0.48.0", + "guzzlehttp/guzzle": "^6.3", + "illuminate/config": "^5.6", + "illuminate/support": "^5.6", + "illuminate/translation": "^5.6" + }, "require-dev": { "phpunit/phpunit": "^7.0", "mockery/mockery": "^1.0", @@ -26,5 +33,15 @@ "psr-4": { "Tests\\": "tests/" } + }, + "config": { + "sort-packages": true + }, + "extra": { + "laravel": { + "providers": [ + "Jaspaul\\SafeLinkValidator\\ServiceProvider" + ] + } } } diff --git a/phpunit.xml b/phpunit.xml index 5759ad1..a9e48e0 100644 --- a/phpunit.xml +++ b/phpunit.xml @@ -19,5 +19,6 @@ + diff --git a/resources/config/safe-links.php b/resources/config/safe-links.php new file mode 100644 index 0000000..9dd9dff --- /dev/null +++ b/resources/config/safe-links.php @@ -0,0 +1,8 @@ + env('GOOGLE_SERVICE_API_KEY', ''), + 'types' => explode(',', env('SAFE_LINKS_THREAT_TYPES', 'THREAT_TYPE_UNSPECIFIED,MALWARE,SOCIAL_ENGINEERING,UNWANTED_SOFTWARE,POTENTIALLY_HARMFUL_APPLICATION')), + 'platforms' => explode(',', env('SAFE_LINKS_PLATFORM_TYPES', 'PLATFORM_TYPE_UNSPECIFIED,WINDOWS,LINUX,ANDROID,OSX,IOS,ANY_PLATFORM,ALL_PLATFORMS,CHROME')), + 'entry-types' => explode(',', env('SAFE_LINKS_ENTRY_TYPES', 'THREAT_ENTRY_TYPE_UNSPECIFIED,URL,EXECUTABLE')), +]; diff --git a/resources/translations/safe-links.php b/resources/translations/safe-links.php new file mode 100644 index 0000000..ff816a6 --- /dev/null +++ b/resources/translations/safe-links.php @@ -0,0 +1,7 @@ + [ + 'link' => 'The :attribute field contained an unsafe link.', + ] +]; diff --git a/src/Link.php b/src/Link.php new file mode 100644 index 0000000..210f43b --- /dev/null +++ b/src/Link.php @@ -0,0 +1,70 @@ +uri = $uri; + } + + /** + * Determines if the link is safe or not. + * + * @return boolean + */ + public function isSafe(): bool + { + $client = new Google_Client(); + $client->setDeveloperKey(config('safe-links.api-key')); + + $threatEntry = new Google_Service_Safebrowsing_ThreatEntry(); + $threatEntry->setUrl((string) $this->uri); + + $threatInfo = new Google_Service_Safebrowsing_ThreatInfo(); + $threatInfo->setThreatTypes(config('safe-links.types')); + $threatInfo->setPlatformTypes(config('safe-links.platforms')); + $threatInfo->setThreatEntryTypes(config('safe-links.entry-types')); + $threatInfo->setThreatEntries([$threatEntry]); + + $request = new Google_Service_Safebrowsing_FindThreatMatchesRequest(); + $request->setThreatInfo($threatInfo); + + $service = new Google_Service_Safebrowsing($client); + $matches = $service->threatMatches->find($request)->getMatches(); + + return empty($matches); + } +} diff --git a/src/SafeLinkRule.php b/src/SafeLinkRule.php new file mode 100644 index 0000000..fe94255 --- /dev/null +++ b/src/SafeLinkRule.php @@ -0,0 +1,31 @@ +isSafe(); + } + + /** + * The message to return when it failes. + * + * @return string + */ + public function message() + { + return trans('safe-links::validation.link'); + } +} diff --git a/src/ServiceProvider.php b/src/ServiceProvider.php new file mode 100644 index 0000000..3306599 --- /dev/null +++ b/src/ServiceProvider.php @@ -0,0 +1,45 @@ +publishConfigurations(); + $this->loadTranslationsFrom(__DIR__ . '/../resources/translations', 'safe-links'); + } + + /** + * Register bindings in the container. + * + * @return void + */ + public function register() + { + $this->mergeConfigFrom(__DIR__ . '/../resources/config/safe-links.php', 'safe-links'); + } + + /** + * Adds our configuration file to the publishes array. + * + * @return void + */ + protected function publishConfigurations() + { + $this->publishes([ + __DIR__ . '/../resources/config/safe-links.php' => config_path('safe-links.php'), + ]); + + $this->publishes([ + __DIR__ . '/../resources/translations' => resource_path('lang/vendor/safe-links'), + ]); + } +} diff --git a/tests/LinkTest.php b/tests/LinkTest.php new file mode 100644 index 0000000..f9d2fa5 --- /dev/null +++ b/tests/LinkTest.php @@ -0,0 +1,26 @@ +assertFalse($link->isSafe()); + } + + /** + * @test + */ + public function isSafe_returns_true_if_you_provide_a_safe_link() + { + $link = Link::fromString('http://www.google.com/'); + $this->assertTrue($link->isSafe()); + } +} diff --git a/tests/SafeLinkRuleTest.php b/tests/SafeLinkRuleTest.php new file mode 100644 index 0000000..fdcf0ea --- /dev/null +++ b/tests/SafeLinkRuleTest.php @@ -0,0 +1,26 @@ +assertFalse($rule->passes('attribute', 'http://malware.testing.google.test/testing/malware/')); + } + + /** + * @test + */ + public function passes_returns_true_if_you_provide_a_safe_link() + { + $rule = new SafeLinkRule(); + $this->assertTrue($rule->passes('attribute', 'http://www.google.com')); + } +} diff --git a/tests/TestCase.php b/tests/TestCase.php index 393f971..26fe4e7 100644 --- a/tests/TestCase.php +++ b/tests/TestCase.php @@ -4,6 +4,7 @@ use Mockery; use Orchestra\Testbench\TestCase as Base; +use Jaspaul\SafeLinkValidator\ServiceProvider; abstract class TestCase extends Base { @@ -15,4 +16,16 @@ protected function setUpMockery() Mockery::getConfiguration()->allowMockingNonExistentMethods(false); Mockery::getConfiguration()->allowMockingMethodsUnnecessarily(false); } + + /** + * @param \Illuminate\Foundation\Application $app + * + * @return array + */ + protected function getPackageProviders($app) + { + return [ + ServiceProvider::class, + ]; + } }