diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..f0c5241 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +composer.lock +vendor +.php_cs.cache diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..b812d8c --- /dev/null +++ b/.travis.yml @@ -0,0 +1,21 @@ +language: php + +php: + - 5.6 + - 7.0 + - 7.1 + +matrix: + fast_finish: true + +before_script: + - composer self-update + - composer install --prefer-source --no-interaction + - composer dump-autoload -o + +script: + - bin/kahlan --coverage=4 --reporter=verbose --clover=build/logs/clover.xml + - if [[ $TRAVIS_PHP_VERSION = 7.1 ]]; then bin/coveralls -v --exclude-no-stmt; fi + +notifications: + email: false diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..8557f35 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,17 @@ +CONTRIBUTING +------------ +To contribute, you can send pull requests with : + +- Typo fix. +- Use PSR-2 Coding Standard. +- patch(es) need new/updated test(s). +- new feature(s) need test(s). + +Tests +----- +You can run test with : +```shell +$ composer install +$ bin/kahlan --coverage=4 +``` +and make sure there is no regression. \ No newline at end of file diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..2110199 --- /dev/null +++ b/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2017 Abdul Malik Ikhsan + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..97e1c12 --- /dev/null +++ b/README.md @@ -0,0 +1,71 @@ +ForceHttpsModule +================ + +[![Latest Version](https://img.shields.io/github/release/samsonasik/ForceHttpsModule.svg?style=flat-square)](https://github.com/samsonasik/ForceHttpsModule/releases) +[![Build Status](https://travis-ci.org/samsonasik/ForceHttpsModule.svg?branch=master)](https://travis-ci.org/samsonasik/ForceHttpsModule) +[![Coverage Status](https://coveralls.io/repos/github/samsonasik/ForceHttpsModule/badge.svg?branch=master)](https://coveralls.io/github/samsonasik/ForceHttpsModule?branch=master) +[![Downloads](https://img.shields.io/packagist/dt/samsonasik/force-https-module.svg?style=flat-square)](https://packagist.org/packages/samsonasik/force-https-module) + +Introduction +------------ + +ForceHttpsModule is a configurable module for force https in your ZF2/ZF3 Mvc Application. + +Features +-------- + +- [x] enable/disable force https +- [x] Force Https to All routes +- [x] Force Https to specific routes only + +Installation +------------ + +**1. Require this module uses [composer](https://getcomposer.org/).** + +```sh +composer require samsonasik/force-https-module +``` + +**4. Copy `force-https-module.local.php.dist` config to your local's autoload and configure it** + +| source | destination | +|------------------------------------------------------------------------------|---------------------------------------------| +| vendor/samsonasik/force-https-module/config/force-https-module.local.php.dist | config/autoload/force-https-module.local.php | + +Or run copy command: + +```sh +cp vendor/samsonasik/force-https-module/config/force-https-module.local.php.dist config/autoload/force-https-module.local.php +``` + +When done, you can modify `config/autoload/force-https-module.local.php` config in your's local config: + +```php + [ + 'enable' => true, + 'force_all_routes' => true, + 'force_specific_routes' => [ + // a lists of specific routes to be https + // only works if previous config 'force_all_routes' => false + ], + ], +]; +``` + +**5. Lastly, enable it** +```php +// config/modules.config.php or config/application.config.php +return [ + 'Application' + 'ForceHttpsModule', // register here +], +``` + + +Contributing +------------ +Contributions are very welcome. Please read [CONTRIBUTING.md](https://github.com/samsonasik/ForceHttpsModule/blob/master/CONTRIBUTING.md) diff --git a/bin/.gitignore b/bin/.gitignore new file mode 100644 index 0000000..c96a04f --- /dev/null +++ b/bin/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore \ No newline at end of file diff --git a/build/logs/.gitignore b/build/logs/.gitignore new file mode 100644 index 0000000..c96a04f --- /dev/null +++ b/build/logs/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore \ No newline at end of file diff --git a/composer.json b/composer.json new file mode 100644 index 0000000..bdd3590 --- /dev/null +++ b/composer.json @@ -0,0 +1,42 @@ +{ + "name": "samsonasik/force-https-module", + "type": "library", + "description": "Force Https Module", + "keywords": ["zf2", "zf3", "force", "https", "http"], + "homepage": "https://github.com/samsonasik/ForceHttpsModule", + "license": "MIT", + "authors": [ + { + "name": "Abdul Malik Ikhsan", + "email": "samsonasik@gmail.com", + "homepage": "http://samsonasik.wordpress.com", + "role": "Developer" + } + ], + "require":{ + "php": "^5.6 || ^7.0", + "zendframework/zend-console": "^2.5", + "zendframework/zend-mvc": "^2.5 || ^3.0" + }, + "require-dev": { + "kahlan/kahlan": "^3.0" + }, + "autoload": { + "psr-4": { + "ForceHttpsModule\\": "src/" + } + }, + "autoload-dev": { + "psr-4": { + "ForceHttpsModule\\Spec\\": "spec/" + } + }, + "config": { + "bin-dir": "bin" + }, + "extra": { + "zf": { + "module": "ForceHttpsModule" + } + } +} diff --git a/config/force-https-module.local.php.dist b/config/force-https-module.local.php.dist new file mode 100644 index 0000000..dfd86a1 --- /dev/null +++ b/config/force-https-module.local.php.dist @@ -0,0 +1,12 @@ + [ + 'enable' => true, + 'force_all_routes' => true, + 'force_specific_routes' => [ + // a lists of specific routes to be https + // only works if previous config 'force_all_routes' => false + ], + ], +]; diff --git a/config/module.config.php b/config/module.config.php new file mode 100644 index 0000000..2396da3 --- /dev/null +++ b/config/module.config.php @@ -0,0 +1,14 @@ + [ + 'factories' => [ + Listener\ForceListener::class => Listener\ForceHttpsFactory::class, + ], + ], + 'listeners' => [ + Listener\ForceListener::class, + ], +]; diff --git a/spec/Listener/ForceHttpsFactorySpec.php b/spec/Listener/ForceHttpsFactorySpec.php new file mode 100644 index 0000000..f68b943 --- /dev/null +++ b/spec/Listener/ForceHttpsFactorySpec.php @@ -0,0 +1,5 @@ +config = $config; + } + + /** + * @param EventManagerInterface $events + * @param int $priority + */ + public function attach(EventManagerInterface $events, $priority = 1) + { + if (Console::isConsole()) { + return; + } + + $this->listeners[] = $events->attach(MvcEvent::EVENT_ROUTE, [$this, 'forceHttps']); + } + + public function forceHttps(MvcEvent $e) + { + if (! $this->config['enable']) { + return; + } + + $uri = $e->getRequest()->getUri(); + $uriScheme = $uri->getScheme(); + if ($uriScheme === 'https') { + return; + } + + $httpsRequestUri = $uri->setScheme('https')->getRequestUri(); + if ($this->config['force_all_routes']) { + return $this->redirectWithHttps($e); + } + + $routeName = $e->getRouteMatch()->getMatchedRouteName(); + if (! in_array($routeName, $this->config['force_specific_routes'])) { + return; + } + + return $this->redirectWithHttps($e); + } + + private function redirectWithHttps(MvcEvent $e) + { + $response = $e->getResponse(); + $response->setStatusCode(302); + $response->getHeaders() + ->addHeaderLine('Location', $httpsRequestUri); + + return $e->stopPropagation(); + } +} diff --git a/src/Listener/ForceHttpsFactory.php b/src/Listener/ForceHttpsFactory.php new file mode 100644 index 0000000..c5b40ca --- /dev/null +++ b/src/Listener/ForceHttpsFactory.php @@ -0,0 +1,11 @@ +get('config')['force-https-module']) + } +} diff --git a/src/Module.php b/src/Module.php new file mode 100644 index 0000000..b890d0a --- /dev/null +++ b/src/Module.php @@ -0,0 +1,11 @@ +