├── .gitignore
├── view
└── adminhtml
│ ├── web
│ ├── js
│ │ └── .DS_Store
│ ├── assets
│ │ ├── .DS_Store
│ │ ├── layers.png
│ │ ├── spinner.gif
│ │ ├── throbber.gif
│ │ ├── layers-2x.png
│ │ ├── select2-cf.png
│ │ ├── select2x2-cf.png
│ │ ├── details-arrows.png
│ │ ├── hero-bg-clouds.png
│ │ ├── icon-bolt.svg
│ │ ├── vertical-range.png
│ │ ├── yjs-background.jpg
│ │ ├── icons-seee324dde5.png
│ │ ├── select2-cf-white.png
│ │ ├── select2x2-cf-white.png
│ │ ├── yjs-background_2x.jpg
│ │ ├── icons_2x-s6333fe7591.png
│ │ ├── modal-two-factor-auth.png
│ │ ├── icon-shield.svg
│ │ ├── modal-two-factor-auth_2x.png
│ │ ├── icon-lock.svg
│ │ ├── icon-pin.svg
│ │ ├── request-submitted-success.svg
│ │ ├── plan-changed-success.svg
│ │ ├── analytics-welcome.svg
│ │ ├── overview-welcome.svg
│ │ ├── logo.svg
│ │ ├── logo-symbol.svg
│ │ ├── overview-welcome-yjs.svg
│ │ ├── yjs-logo.svg
│ │ └── logo-reverse.svg
│ ├── fonts
│ │ ├── FontAwesome.otf
│ │ ├── opensans-300.eot
│ │ ├── opensans-300.ttf
│ │ ├── opensans-300.woff
│ │ ├── opensans-300.woff2
│ │ ├── opensans-300i.eot
│ │ ├── opensans-300i.ttf
│ │ ├── opensans-300i.woff
│ │ ├── opensans-400.eot
│ │ ├── opensans-400.ttf
│ │ ├── opensans-400.woff
│ │ ├── opensans-400.woff2
│ │ ├── opensans-400i.eot
│ │ ├── opensans-400i.ttf
│ │ ├── opensans-400i.woff
│ │ ├── opensans-600.eot
│ │ ├── opensans-600.ttf
│ │ ├── opensans-600.woff
│ │ ├── opensans-600.woff2
│ │ ├── opensans-700.eot
│ │ ├── opensans-700.ttf
│ │ ├── opensans-700.woff
│ │ ├── opensans-700.woff2
│ │ ├── cloudflare-font.eot
│ │ ├── cloudflare-font.ttf
│ │ ├── cloudflare-font.woff
│ │ ├── opensans-300i.woff2
│ │ ├── opensans-400i.woff2
│ │ ├── fontawesome-webfont.eot
│ │ ├── fontawesome-webfont.ttf
│ │ ├── fontawesome-webfont.woff
│ │ ├── fontawesome-cloudflare.eot
│ │ ├── fontawesome-cloudflare.ttf
│ │ ├── fontawesome-cloudflare.woff
│ │ ├── fontawesome-cloudflare.svg
│ │ └── cloudflare-font.svg
│ ├── config.js
│ ├── stylesheets
│ │ └── hacks.css
│ └── lang
│ │ └── en.js
│ ├── layout
│ └── cloudflare_plugin_index.xml
│ └── templates
│ └── plugin
│ └── index.phtml
├── registration.php
├── etc
├── module.xml
├── adminhtml
│ ├── routes.xml
│ └── menu.xml
├── frontend
│ └── di.xml
├── events.xml
└── di.xml
├── Model
├── KeyValue.php
├── ResourceModel
│ └── KeyValue.php
└── Layout
│ └── LayoutPlugin.php
├── Backend
├── ClientRoutes.php
├── PluginRoutes.php
├── PluginAPI.php
├── MagentoConfig.php
├── MagentoIntegration.php
├── ClientActions.php
├── ClientAPI.php
├── MagentoHttpClient.php
├── DataStore.php
├── CacheTags.php
├── MagentoAPI.php
└── PluginActions.php
├── Test
├── Unit
│ ├── Backend
│ │ ├── PluginRoutesTest.php
│ │ ├── DataStoreTest.php
│ │ ├── PluginActionsTest.php
│ │ ├── ClientActionsTest.php
│ │ ├── CacheTagsTest.php
│ │ └── MagentoAPITest.php
│ ├── Observer
│ │ ├── FlushAllCloudFlareObserverTest.php
│ │ └── InvalidateCloudFlareObserverTest.php
│ ├── Model
│ │ └── Layout
│ │ │ └── LayoutPluginTest.php
│ └── Controller
│ │ └── Adminhtml
│ │ └── Plugin
│ │ └── ProxyTest.php
└── bootstrap.php
├── .github
└── workflows
│ └── semgrep.yml
├── CHANGELOG.md
├── Observer
├── FlushAllCloudFlareObserver.php
└── InvalidateCloudFlareObserver.php
├── composer.json
├── LICENSE.md
├── README.md
├── .travis.yml
├── Controller
└── Adminhtml
│ └── Plugin
│ ├── Index.php
│ └── Proxy.php
├── Block
└── Adminhtml
│ └── Index.php
├── Setup
└── InstallSchema.php
└── CONTRIBUTING.md
/.gitignore:
--------------------------------------------------------------------------------
1 | auth.json
2 | sync.sh
3 | vendor/
4 |
--------------------------------------------------------------------------------
/view/adminhtml/web/js/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cloudflare/Cloudflare-Magento/master/view/adminhtml/web/js/.DS_Store
--------------------------------------------------------------------------------
/view/adminhtml/web/assets/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cloudflare/Cloudflare-Magento/master/view/adminhtml/web/assets/.DS_Store
--------------------------------------------------------------------------------
/view/adminhtml/web/assets/layers.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cloudflare/Cloudflare-Magento/master/view/adminhtml/web/assets/layers.png
--------------------------------------------------------------------------------
/view/adminhtml/web/assets/spinner.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cloudflare/Cloudflare-Magento/master/view/adminhtml/web/assets/spinner.gif
--------------------------------------------------------------------------------
/view/adminhtml/web/assets/throbber.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cloudflare/Cloudflare-Magento/master/view/adminhtml/web/assets/throbber.gif
--------------------------------------------------------------------------------
/view/adminhtml/web/assets/layers-2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cloudflare/Cloudflare-Magento/master/view/adminhtml/web/assets/layers-2x.png
--------------------------------------------------------------------------------
/view/adminhtml/web/assets/select2-cf.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cloudflare/Cloudflare-Magento/master/view/adminhtml/web/assets/select2-cf.png
--------------------------------------------------------------------------------
/view/adminhtml/web/fonts/FontAwesome.otf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cloudflare/Cloudflare-Magento/master/view/adminhtml/web/fonts/FontAwesome.otf
--------------------------------------------------------------------------------
/view/adminhtml/web/assets/select2x2-cf.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cloudflare/Cloudflare-Magento/master/view/adminhtml/web/assets/select2x2-cf.png
--------------------------------------------------------------------------------
/view/adminhtml/web/fonts/opensans-300.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cloudflare/Cloudflare-Magento/master/view/adminhtml/web/fonts/opensans-300.eot
--------------------------------------------------------------------------------
/view/adminhtml/web/fonts/opensans-300.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cloudflare/Cloudflare-Magento/master/view/adminhtml/web/fonts/opensans-300.ttf
--------------------------------------------------------------------------------
/view/adminhtml/web/fonts/opensans-300.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cloudflare/Cloudflare-Magento/master/view/adminhtml/web/fonts/opensans-300.woff
--------------------------------------------------------------------------------
/view/adminhtml/web/fonts/opensans-300.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cloudflare/Cloudflare-Magento/master/view/adminhtml/web/fonts/opensans-300.woff2
--------------------------------------------------------------------------------
/view/adminhtml/web/fonts/opensans-300i.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cloudflare/Cloudflare-Magento/master/view/adminhtml/web/fonts/opensans-300i.eot
--------------------------------------------------------------------------------
/view/adminhtml/web/fonts/opensans-300i.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cloudflare/Cloudflare-Magento/master/view/adminhtml/web/fonts/opensans-300i.ttf
--------------------------------------------------------------------------------
/view/adminhtml/web/fonts/opensans-300i.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cloudflare/Cloudflare-Magento/master/view/adminhtml/web/fonts/opensans-300i.woff
--------------------------------------------------------------------------------
/view/adminhtml/web/fonts/opensans-400.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cloudflare/Cloudflare-Magento/master/view/adminhtml/web/fonts/opensans-400.eot
--------------------------------------------------------------------------------
/view/adminhtml/web/fonts/opensans-400.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cloudflare/Cloudflare-Magento/master/view/adminhtml/web/fonts/opensans-400.ttf
--------------------------------------------------------------------------------
/view/adminhtml/web/fonts/opensans-400.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cloudflare/Cloudflare-Magento/master/view/adminhtml/web/fonts/opensans-400.woff
--------------------------------------------------------------------------------
/view/adminhtml/web/fonts/opensans-400.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cloudflare/Cloudflare-Magento/master/view/adminhtml/web/fonts/opensans-400.woff2
--------------------------------------------------------------------------------
/view/adminhtml/web/fonts/opensans-400i.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cloudflare/Cloudflare-Magento/master/view/adminhtml/web/fonts/opensans-400i.eot
--------------------------------------------------------------------------------
/view/adminhtml/web/fonts/opensans-400i.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cloudflare/Cloudflare-Magento/master/view/adminhtml/web/fonts/opensans-400i.ttf
--------------------------------------------------------------------------------
/view/adminhtml/web/fonts/opensans-400i.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cloudflare/Cloudflare-Magento/master/view/adminhtml/web/fonts/opensans-400i.woff
--------------------------------------------------------------------------------
/view/adminhtml/web/fonts/opensans-600.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cloudflare/Cloudflare-Magento/master/view/adminhtml/web/fonts/opensans-600.eot
--------------------------------------------------------------------------------
/view/adminhtml/web/fonts/opensans-600.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cloudflare/Cloudflare-Magento/master/view/adminhtml/web/fonts/opensans-600.ttf
--------------------------------------------------------------------------------
/view/adminhtml/web/fonts/opensans-600.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cloudflare/Cloudflare-Magento/master/view/adminhtml/web/fonts/opensans-600.woff
--------------------------------------------------------------------------------
/view/adminhtml/web/fonts/opensans-600.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cloudflare/Cloudflare-Magento/master/view/adminhtml/web/fonts/opensans-600.woff2
--------------------------------------------------------------------------------
/view/adminhtml/web/fonts/opensans-700.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cloudflare/Cloudflare-Magento/master/view/adminhtml/web/fonts/opensans-700.eot
--------------------------------------------------------------------------------
/view/adminhtml/web/fonts/opensans-700.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cloudflare/Cloudflare-Magento/master/view/adminhtml/web/fonts/opensans-700.ttf
--------------------------------------------------------------------------------
/view/adminhtml/web/fonts/opensans-700.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cloudflare/Cloudflare-Magento/master/view/adminhtml/web/fonts/opensans-700.woff
--------------------------------------------------------------------------------
/view/adminhtml/web/fonts/opensans-700.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cloudflare/Cloudflare-Magento/master/view/adminhtml/web/fonts/opensans-700.woff2
--------------------------------------------------------------------------------
/view/adminhtml/web/assets/details-arrows.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cloudflare/Cloudflare-Magento/master/view/adminhtml/web/assets/details-arrows.png
--------------------------------------------------------------------------------
/view/adminhtml/web/assets/hero-bg-clouds.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cloudflare/Cloudflare-Magento/master/view/adminhtml/web/assets/hero-bg-clouds.png
--------------------------------------------------------------------------------
/view/adminhtml/web/assets/icon-bolt.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/view/adminhtml/web/assets/vertical-range.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cloudflare/Cloudflare-Magento/master/view/adminhtml/web/assets/vertical-range.png
--------------------------------------------------------------------------------
/view/adminhtml/web/assets/yjs-background.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cloudflare/Cloudflare-Magento/master/view/adminhtml/web/assets/yjs-background.jpg
--------------------------------------------------------------------------------
/view/adminhtml/web/fonts/cloudflare-font.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cloudflare/Cloudflare-Magento/master/view/adminhtml/web/fonts/cloudflare-font.eot
--------------------------------------------------------------------------------
/view/adminhtml/web/fonts/cloudflare-font.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cloudflare/Cloudflare-Magento/master/view/adminhtml/web/fonts/cloudflare-font.ttf
--------------------------------------------------------------------------------
/view/adminhtml/web/fonts/cloudflare-font.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cloudflare/Cloudflare-Magento/master/view/adminhtml/web/fonts/cloudflare-font.woff
--------------------------------------------------------------------------------
/view/adminhtml/web/fonts/opensans-300i.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cloudflare/Cloudflare-Magento/master/view/adminhtml/web/fonts/opensans-300i.woff2
--------------------------------------------------------------------------------
/view/adminhtml/web/fonts/opensans-400i.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cloudflare/Cloudflare-Magento/master/view/adminhtml/web/fonts/opensans-400i.woff2
--------------------------------------------------------------------------------
/view/adminhtml/web/assets/icons-seee324dde5.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cloudflare/Cloudflare-Magento/master/view/adminhtml/web/assets/icons-seee324dde5.png
--------------------------------------------------------------------------------
/view/adminhtml/web/assets/select2-cf-white.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cloudflare/Cloudflare-Magento/master/view/adminhtml/web/assets/select2-cf-white.png
--------------------------------------------------------------------------------
/view/adminhtml/web/assets/select2x2-cf-white.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cloudflare/Cloudflare-Magento/master/view/adminhtml/web/assets/select2x2-cf-white.png
--------------------------------------------------------------------------------
/view/adminhtml/web/assets/yjs-background_2x.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cloudflare/Cloudflare-Magento/master/view/adminhtml/web/assets/yjs-background_2x.jpg
--------------------------------------------------------------------------------
/view/adminhtml/web/fonts/fontawesome-webfont.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cloudflare/Cloudflare-Magento/master/view/adminhtml/web/fonts/fontawesome-webfont.eot
--------------------------------------------------------------------------------
/view/adminhtml/web/fonts/fontawesome-webfont.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cloudflare/Cloudflare-Magento/master/view/adminhtml/web/fonts/fontawesome-webfont.ttf
--------------------------------------------------------------------------------
/view/adminhtml/web/assets/icons_2x-s6333fe7591.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cloudflare/Cloudflare-Magento/master/view/adminhtml/web/assets/icons_2x-s6333fe7591.png
--------------------------------------------------------------------------------
/view/adminhtml/web/fonts/fontawesome-webfont.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cloudflare/Cloudflare-Magento/master/view/adminhtml/web/fonts/fontawesome-webfont.woff
--------------------------------------------------------------------------------
/view/adminhtml/web/assets/modal-two-factor-auth.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cloudflare/Cloudflare-Magento/master/view/adminhtml/web/assets/modal-two-factor-auth.png
--------------------------------------------------------------------------------
/view/adminhtml/web/fonts/fontawesome-cloudflare.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cloudflare/Cloudflare-Magento/master/view/adminhtml/web/fonts/fontawesome-cloudflare.eot
--------------------------------------------------------------------------------
/view/adminhtml/web/fonts/fontawesome-cloudflare.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cloudflare/Cloudflare-Magento/master/view/adminhtml/web/fonts/fontawesome-cloudflare.ttf
--------------------------------------------------------------------------------
/view/adminhtml/web/fonts/fontawesome-cloudflare.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cloudflare/Cloudflare-Magento/master/view/adminhtml/web/fonts/fontawesome-cloudflare.woff
--------------------------------------------------------------------------------
/view/adminhtml/web/assets/icon-shield.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/view/adminhtml/web/assets/modal-two-factor-auth_2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cloudflare/Cloudflare-Magento/master/view/adminhtml/web/assets/modal-two-factor-auth_2x.png
--------------------------------------------------------------------------------
/view/adminhtml/web/assets/icon-lock.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/registration.php:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/view/adminhtml/web/assets/icon-pin.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/etc/adminhtml/routes.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/Model/KeyValue.php:
--------------------------------------------------------------------------------
1 | _init('CloudFlare\Plugin\Model\ResourceModel\KeyValue');
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/etc/frontend/di.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/etc/adminhtml/menu.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
6 |
7 |
--------------------------------------------------------------------------------
/Backend/ClientRoutes.php:
--------------------------------------------------------------------------------
1 | array(
9 | 'class' => 'CloudFlare\Plugin\Backend\ClientActions',
10 | 'methods' => array(
11 | 'GET' => array(
12 | 'function' => 'getZonesReturnMagentoZone'
13 | )
14 | )
15 | )
16 | );
17 | }
18 |
--------------------------------------------------------------------------------
/Model/ResourceModel/KeyValue.php:
--------------------------------------------------------------------------------
1 | _init(InstallSchema::CLOUDFLARE_DATA_TABLE_NAME, InstallSchema::CLOUDFLARE_DATA_TABLE_ID_COLUMN);
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/Backend/PluginRoutes.php:
--------------------------------------------------------------------------------
1 | $route) {
15 | $route['class'] = '\CloudFlare\Plugin\Backend\PluginActions';
16 | $routeList[$routePath] = $route;
17 | }
18 |
19 | return $routeList;
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/Backend/PluginAPI.php:
--------------------------------------------------------------------------------
1 | magentoHttpClient = $magentoHttpClient;
17 | $this->magentoHttpClient->setEndpoint($this->getEndpoint());
18 | $this->setHttpClient($this->magentoHttpClient);
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/Test/Unit/Backend/PluginRoutesTest.php:
--------------------------------------------------------------------------------
1 | array(
13 | 'class' => 'Any/Other/Class'
14 | )
15 | );
16 |
17 | $newRoutes = PluginRoutes::getRoutes($routes);
18 |
19 | $this->assertEquals('\CloudFlare\Plugin\Backend\PluginActions', $newRoutes['account']['class']);
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/Test/bootstrap.php:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/Backend/MagentoConfig.php:
--------------------------------------------------------------------------------
1 | config = [];
17 | }
18 |
19 | /**
20 | * @param Array $config
21 | */
22 | public function setConfig($config)
23 | {
24 | $this->config = $config;
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # Change Log
2 | All notable changes to this project will be documented in this file.
3 | This project adheres to [Semantic Versioning](http://semver.org/).
4 |
5 | ## [1.1.8](#1.1.8) - 2018-07-23
6 | ## Fixed
7 | - Magento 2 js minification bug [#72](https://github.com/cloudflare/Cloudflare-Magento/pull/72)
8 |
9 | ## [1.1.7](#1.1.7) - 2017-11-29
10 | ## Added
11 | - Support for PHP version 7.x. [#68](https://github.com/cloudflare/Cloudflare-Magento/pull/68)
12 |
13 | ## [1.1.6](#1.1.6) - 2017-05-24
14 | ## Fixed
15 | - Fixed bug where DB errors weren't being caught. [#59](https://github.com/cloudflare/Cloudflare-Magento/pull/59)
16 |
17 | ## [1.1.5](#1.1.5) - 2017-04-21
18 | ## Fixed
19 | - Fixed bug where Magento 2.1 DI couldn't inject PHP classes from non Magento module composer classes [#55](https://github.com/cloudflare/Cloudflare-Magento/pull/55)
20 |
--------------------------------------------------------------------------------
/view/adminhtml/web/config.js:
--------------------------------------------------------------------------------
1 | {
2 | "debug": false,
3 | "featureManagerIsFullZoneProvisioningEnabled": false,
4 | "isDNSPageEnabled": false,
5 | "isSubdomainCheckEnabled": false,
6 | "homePageCards": [
7 | "ApplyDefaultSettingsCard",
8 | "PluginSpecificCacheTagCard",
9 | "PurgeCacheCard"
10 | ],
11 | "moreSettingsCards": {
12 | "container.moresettings.security": [
13 | "SecurityLevelCard",
14 | "WAFCard"
15 | ],
16 | "container.moresettings.performance": [
17 | "BypassCacheByCookieCard",
18 | "AlwaysOnlineCard",
19 | "ImageOptimizationCard",
20 | "DevelopmentModeCard"
21 | ]
22 | },
23 | "locale": "en",
24 | "integrationName": "Magento",
25 | "useHostAPILogin": false,
26 | "version": "1.1.8"
27 | }
28 |
--------------------------------------------------------------------------------
/Observer/FlushAllCloudFlareObserver.php:
--------------------------------------------------------------------------------
1 | config = $config;
34 | $this->cacheTags = $cacheTags;
35 | }
36 |
37 | /**
38 | * Flush CloudFlare cache
39 | *
40 | * @param \Magento\Framework\Event\Observer $observer
41 | * @return void
42 | */
43 | public function execute(Observer $observer)
44 | {
45 | if ($this->config->isEnabled()) {
46 | $this->cacheTags->purgeCache();
47 | }
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/composer.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "cloudflare/cloudflare-magento",
3 | "description": "Cloudflare Plugin for Magento2",
4 | "version": "1.1.8",
5 | "homepage": "https://github.com/cloudflare/Cloudflare-Magento",
6 | "scripts": {
7 | "test": "vendor/phpunit/phpunit/phpunit --bootstrap Test/bootstrap.php Test/ && rm -rf phpUnitGeneratedFiles/",
8 | "lint": "vendor/bin/phpcs -n --standard=PSR2 Backend/ Block/ Controller/ Model/ Observer/ Setup/ Test/",
9 | "format": "vendor/bin/phpcbf --standard=PSR2 Backend/ Block/ Controller/ Model/ Observer/ Setup/ Test/"
10 | },
11 | "repositories": [
12 | {
13 | "type": "composer",
14 | "url": "https://repo.magento.com/"
15 | }
16 | ],
17 | "require": {
18 | "php": "~5.6.0|~7.0",
19 | "cloudflare/cloudflare-plugin-backend": "^2.1"
20 | },
21 | "type": "magento2-module",
22 | "license": [
23 | "BSD-3-Clause"
24 | ],
25 | "autoload": {
26 | "files": [ "registration.php" ],
27 | "psr-4": {
28 | "CloudFlare\\Plugin\\": ""
29 | }
30 | },
31 | "minimum-stability": "alpha",
32 | "require-dev": {
33 | "squizlabs/php_codesniffer": "^2.8",
34 | "phpunit/phpunit": "4.1.0",
35 | "magento/module-backend": "100.1.*",
36 | "magento/module-store": "100.1.*",
37 | "magento/framework": "100.1.*"
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/Test/Unit/Observer/FlushAllCloudFlareObserverTest.php:
--------------------------------------------------------------------------------
1 | mockCacheTags = $this->getMockBuilder('\CloudFlare\Plugin\Backend\CacheTags')
17 | ->disableOriginalConstructor()
18 | ->getMock();
19 | $this->mockConfig = $this->getMockBuilder('\Magento\PageCache\Model\Config')
20 | ->disableOriginalConstructor()
21 | ->getMock();
22 | $this->mockObserver = $this->getMockBuilder('\Magento\Framework\Event\Observer')
23 | ->disableOriginalConstructor()
24 | ->getMock();
25 | $this->flushAllCloudFlareObserver = new FlushAllCloudFlareObserver($this->mockConfig, $this->mockCacheTags);
26 | }
27 |
28 | public function testExecuteCallsPurgeCache()
29 | {
30 | $this->mockConfig->method('isEnabled')->willReturn(true);
31 | $this->mockCacheTags->expects($this->once())->method('purgeCache');
32 |
33 | $this->flushAllCloudFlareObserver->execute($this->mockObserver);
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/LICENSE.md:
--------------------------------------------------------------------------------
1 | Copyright (c) 2016, Cloudflare. All rights reserved.
2 |
3 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
4 |
5 | 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
6 |
7 | 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
8 |
9 | 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
10 |
11 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
--------------------------------------------------------------------------------
/Backend/MagentoIntegration.php:
--------------------------------------------------------------------------------
1 | httpClient = $httpClient;
26 | parent::__construct($config, $integrationAPI, $dataStore, $logger);
27 | }
28 |
29 | /**
30 | * @return HttpClientInterface $httpClient
31 | */
32 | public function getHttpClient()
33 | {
34 | return $this->httpClient;
35 | }
36 |
37 | /**
38 | * @param HttpClientInterface $httpClient
39 | */
40 | public function setHttpClient(HttpClientInterface $httpClient)
41 | {
42 | $this->httpClient = $httpClient;
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Notice: This plugin has been deprecated and is no longer officially supported by Cloudflare.
2 | ## For information regarding using Magento & Cloudflare, please see [this support article](https://support.cloudflare.com/hc/en-us/articles/360021023712-Best-Practices-Speed-up-your-Site-with-Custom-Caching-via-Cloudflare-Page-Rules).
3 |
4 | [](https://travis-ci.org/cloudflare/Cloudflare-Magento)
5 |
6 | ## Installing the Cloudflare Magento2 extension
7 | From the magento2 root directory run the following commands:
8 |
9 | 1. `composer require cloudflare/cloudflare-magento`
10 | 2. `composer update`
11 | 3. `bin/magento setup:upgrade`
12 | 4. `bin/magento setup:di:compile`
13 |
14 | ## Versions of Magento2 supported
15 | * Up to Magento2 CE 2.2.0
16 |
17 | ## Development
18 | You'll need to get [authorization keys](http://devdocs.magento.com/guides/v2.0/install-gde/prereq/connect-auth.html) from the Magento marketplace and make an `auth.json`:
19 | ```
20 | {
21 | "http-basic": {
22 | "repo.magento.com": {
23 | "username": "[MAGENTO USERNAME]",
24 | "password": "[MAGENTO PASSWORD]"
25 | }
26 | }
27 | }
28 | ```
29 | This will allow `composer install` to authenticate against `repo.magento.com/`.
30 |
31 | ### Development Commands
32 | 1. `composer test`
33 | 2. `composer lint`
34 | 3. `composer format`
35 |
36 | ## Tests
37 | `vendor/phpunit/phpunit/phpunit -c dev/tests/unit/phpunit.xml.dist vendor/cloudflare/cloudflare-magento/Test/Unit/`
38 |
--------------------------------------------------------------------------------
/Observer/InvalidateCloudFlareObserver.php:
--------------------------------------------------------------------------------
1 | config = $config;
33 | $this->cacheTags = $cacheTags;
34 | }
35 |
36 | /**
37 | * Purges CloudFlare cache by tag
38 | *
39 | * @param \Magento\Framework\Event\Observer $observer
40 | * @return void
41 | */
42 | public function execute(\Magento\Framework\Event\Observer $observer)
43 | {
44 | if (!$this->config->isEnabled()) {
45 | return;
46 | }
47 | $object = $observer->getEvent()->getObject();
48 |
49 | if ($object instanceof \Magento\Framework\DataObject\IdentityInterface === false
50 | || empty($object->getIdentities())) {
51 | return;
52 | }
53 |
54 | $this->cacheTags->purgeCacheTags($object->getIdentities());
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: php
2 | sudo: false
3 | php:
4 | - 5.6
5 | - 7.0
6 | install:
7 | - echo "{\"http-basic\":{\"repo.magento.com\":{\"username\":\"${MAGENTO_USERNAME}\",\"password\":\"${MAGENTO_PASSWORD}\"}}}" > auth.json
8 | - composer install
9 | script:
10 | - composer lint
11 | - composer test
12 | env:
13 | global:
14 | - secure: "0Nl50VCOPwGTp54r1wbM0uFdBi7Do9Y0c2DyCizW2wGFW3UR06s0ps/ZSbwECXjTssL8yQV2I0YGLfnH7KcTKDdUH7IcMcn8RBjv+pJcnxSbgFI9EaGb2/gRjys687607Dtr/annx3fzKo2ao0ndxOdTRqEUU/FhKPM9pRkY+sTzePJfzEH6mnAcjK9r849nguaG/6wkiUlMG0WfAZ8x9z7DFUnQU6Iv+xpQfZO+qn5Da02gk/CNHlLoIQLvrNQ+Tfzki+F1moQQXslKSvq2noxo4SNdkUEgVPPq7x1IVXk56v0ovadLEF/MahB6wWuxcmD6pTh2r02sTJYS0lHY7LMnvGD9buq/hIo5Td2PAEVmmMBy2GUFtbBRp8kUv1dXgR7bm3ICiraufddftgYkcwLYdfP+q7PTdL5bzRodXaw97O48wwiKs7X1AjxO0tpzg3J+btSKuKS/wJmXtR188iven8BY4nq0+uFlz4U7aYEG3UG+nBqbDIF+amAkhPB9xlDzvrCYHsE9KRhX6b5zNAzlOJg71OpBSCNvxWwp99hnHz5km2Fx0NVYLf2NV7c5/fnw4JfWt7MWKzUPMq8fQME7B7K9lrw7mZnSWg7i0QRetyQ8rlcwNif7aq/XGSzy7ABmN2mrHgTbfeKVqvT8o3RSoS9bjt6gPjuq+Rrwzhs="
15 | - secure: "6tcytWunexBbAeEAmpPgKPFW6dlzV/soHtuOiomS4a0p75rDrnlnc3BiLuFGFw2tp1MNrKdtwCSr+gvE/uu59afhY/a5HmOZwxhS8qUY6+RDEbVIolgaIDxhgdyAUBum/waz01r4orhGAtyVvG/ABVkKMqex6+bVGzzyRq+hpOhlboVrLVnFvVeCSQjlmsgLC55aqGcdOT0lRgi33EUKED4GXg7zLANeRfmOmFv7JC3sqEgEsUaiz4JoWQrH43LtDWYegJKAWgLS8joErnlsuSVCYAOxIPGFT9Dhiqz6P3wV+CXxDaUprln98Kk/bUGHa7TaURSHVEBYScKoElaL44nEJQQWPY27PeUShlJtYPmhUCcV1HhzdVpb3rytnCmKWBLnvLfxhM2EKMpSB+fxI8/NMXGKRnsHt9vRmSOqYDhKGDf8UAtTPs6BYmGHzbRqO75dbCmxPuLRTzDm69YiUjmWdQJemS1FwR2wPbccyk0NtF3Jd0BLdozCypiuRpuvvlc5fPDddUJC16C9wUjRilJJINIekYypk5pm5Lp/SDnqcm+P2aQLmEU1uRjeaD55w524tlYgI5F2Aqh24BHM65EEBgdZALiyv8OtlE3eT9DxAFoVboH5qnE3EE6Lp2i9lovLGCaQfxzx3fJfd11xFhkIgWtjko5QcGHKngYh13E="
16 |
--------------------------------------------------------------------------------
/view/adminhtml/templates/plugin/index.phtml:
--------------------------------------------------------------------------------
1 |
40 |
41 |
42 |
--------------------------------------------------------------------------------
/Controller/Adminhtml/Plugin/Index.php:
--------------------------------------------------------------------------------
1 | resultPageFactory = $resultPageFactory;
39 | $this->scopeConfig = $scopeConfig; // Needed to retrieve config values
40 | $this->logger = $logger;
41 | }
42 |
43 | /**
44 | * Index Action*
45 | * @return void
46 | */
47 | public function execute()
48 | {
49 | /** @var \Magento\Backend\Model\View\Result\Page $resultPage */
50 | $resultPage = $this->resultPageFactory->create();
51 | $resultPage->setActiveMenu('CloudFlare_Plugin::index');
52 | $resultPage->addBreadcrumb(__('System'), __('System'));
53 | $resultPage->addBreadcrumb(__('CloudFlare'), __('Cloudflare'));
54 | $resultPage->getConfig()->getTitle()->prepend(__('Cloudflare'));
55 | return $resultPage;
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/Test/Unit/Model/Layout/LayoutPluginTest.php:
--------------------------------------------------------------------------------
1 | mockCacheTags = $this->getMockBuilder('\CloudFlare\Plugin\Backend\CacheTags')
17 | ->disableOriginalConstructor()
18 | ->getMock();
19 | $this->mockConfig = $this->getMockBuilder('\Magento\PageCache\Model\Config')
20 | ->disableOriginalConstructor()
21 | ->getMock();
22 | $this->mockLogger = $this->getMockBuilder('\Psr\Log\LoggerInterface')
23 | ->disableOriginalConstructor()
24 | ->getMock();
25 | $this->mockResponse = $this->getMockBuilder('\Magento\Framework\App\ResponseInterface')
26 | ->disableOriginalConstructor()
27 | ->getMock();
28 | $this->layoutPlugin = new LayoutPlugin(
29 | $this->mockResponse,
30 | $this->mockConfig,
31 | $this->mockLogger,
32 | $this->mockCacheTags
33 | );
34 | }
35 |
36 | public function testLayoutPluginCallsSetCloudFlareCacheTagsResponseHeaderOnce()
37 | {
38 | $mockSubject = $this->getMockBuilder('\Magento\Framework\View\Layout')
39 | ->disableOriginalConstructor()
40 | ->getMock();
41 | $mockSubject->method('isCacheable')->willReturn(true);
42 | $mockSubject->method('getAllBlocks')->willReturn(array());
43 | $this->mockConfig->method('isEnabled')->willReturn(true);
44 | $this->mockCacheTags->expects($this->once())
45 | ->method('setCloudFlareCacheTagsResponseHeader');
46 |
47 | $this->layoutPlugin->afterGetOutput($mockSubject, null);
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/Test/Unit/Observer/InvalidateCloudFlareObserverTest.php:
--------------------------------------------------------------------------------
1 | mockCacheTags = $this->getMockBuilder('\CloudFlare\Plugin\Backend\CacheTags')
19 | ->disableOriginalConstructor()
20 | ->getMock();
21 | $this->mockConfig = $this->getMockBuilder('\Magento\PageCache\Model\Config')
22 | ->disableOriginalConstructor()
23 | ->getMock();
24 |
25 | $this->mockEvent = $this->getMock('Magento\Framework\Event', ['getObject'], [], '', false);
26 |
27 | $this->mockObject = $this->getMockBuilder('\Magento\Framework\DataObject\IdentityInterface')
28 | ->disableOriginalConstructor()
29 | ->getMock();
30 | $this->mockObserver = $this->getMockBuilder('\Magento\Framework\Event\Observer')
31 | ->disableOriginalConstructor()
32 | ->getMock();
33 | $this->invalidateCloudFlareObserver = new InvalidateCloudFlareObserver($this->mockConfig, $this->mockCacheTags);
34 | }
35 |
36 | public function testExecuteCallsPurgeCacheTags()
37 | {
38 | $this->mockConfig->method('isEnabled')->willReturn(true);
39 | $this->mockObject->method('getIdentities')->willReturn(array('cacheTagToPurge'));
40 | $this->mockEvent->method('getObject')->willReturn($this->mockObject);
41 | $this->mockObserver->method('getEvent')->willReturn($this->mockEvent);
42 | $this->mockCacheTags->expects($this->once())->method('purgeCacheTags');
43 |
44 | $this->invalidateCloudFlareObserver->execute($this->mockObserver);
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/Block/Adminhtml/Index.php:
--------------------------------------------------------------------------------
1 | assetRepository = $context->getAssetRepository();
32 | $this->dataStore = $dataStore;
33 | $this->magentoAPI = $magentoAPI;
34 | $this->logger = $context->getLogger();
35 | $this->urlBuilder = $urlBuilder;
36 |
37 | parent::__construct($context);
38 | }
39 |
40 | /*
41 | * $this->set*() are "magic" in that you can call set[THING]() and magento store and expose a
42 | * get[THING]() for you to retrieve the value on the front end.
43 | */
44 | protected function _prepareLayout()
45 | {
46 | //Generate link to CloudFlare/Plugin/view/web/js/compiled.min.js
47 | $asset = $this->assetRepository->createAsset('CloudFlare_Plugin::js/compiled.min.js');
48 | $compiledJsUrl = $asset->getUrl();
49 | $this->setCompiledJsUrl($compiledJsUrl);
50 |
51 | $restProxyPrefix = str_replace(self::COMPILED_JS_PATH, "", $compiledJsUrl);
52 | $this->setRestProxyPrefix($restProxyPrefix);
53 |
54 | $this->setProxyUrl($this->urlBuilder->getUrl("cloudflare/plugin/proxy"));
55 | $this->setCloudflareEmail($this->dataStore->getCloudFlareEmail());
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/Model/Layout/LayoutPlugin.php:
--------------------------------------------------------------------------------
1 | response = $response;
48 | $this->config = $config;
49 | $this->logger = $logger;
50 | $this->cacheTagsUtil = $cacheTagsUtil;
51 | }
52 |
53 |
54 | /**
55 | * Set X-Cache-Tags header with all the Magento Cache Tags so
56 | * they can be purged by the CloudFlare API
57 | *
58 | * @param \Magento\Framework\View\Layout $subject
59 | * @param $result
60 | * @return mixed
61 | */
62 | public function afterGetOutput(\Magento\Framework\View\Layout $subject, $result)
63 | {
64 | if (!$subject->isCacheable() || !$this->config->isEnabled()) {
65 | return $result;
66 | }
67 |
68 | $tags = [];
69 | foreach ($subject->getAllBlocks() as $block) {
70 | if ($block->getIdentities() !== null) {
71 | $tags = array_merge($tags, $block->getIdentities());
72 | }
73 | }
74 | $tags = array_unique($tags);
75 |
76 | $this->cacheTagsUtil->setCloudFlareCacheTagsResponseHeader($this->response, $tags);
77 |
78 | return $result;
79 | }
80 | }
81 |
--------------------------------------------------------------------------------
/Setup/InstallSchema.php:
--------------------------------------------------------------------------------
1 | startSetup();
21 |
22 | $tableName = $installer->getTable(self::CLOUDFLARE_DATA_TABLE_NAME);
23 |
24 | if ($installer->getConnection()->isTableExists($tableName) != true) {
25 | $table = $installer->getConnection()
26 | ->newTable($tableName)
27 | ->addColumn(
28 | self::CLOUDFLARE_DATA_TABLE_ID_COLUMN,
29 | Table::TYPE_INTEGER,
30 | null,
31 | [
32 | 'identity' => true,
33 | 'unsigned' => true,
34 | 'nullable' => false,
35 | 'primary' => true
36 | ],
37 | 'ID'
38 | )
39 | ->addColumn(
40 | self::CLOUDFLARE_DATA_TABLE_KEY_COLUMN,
41 | Table::TYPE_TEXT,
42 | null,
43 | ['nullable' => false, 'default' => ''],
44 | 'Key'
45 | )
46 | ->addColumn(
47 | self::CLOUDFLARE_DATA_TABLE_VALUE_COLUMN,
48 | Table::TYPE_TEXT,
49 | null,
50 | ['nullable' => true, 'default' => ''],
51 | 'Value'
52 | )
53 | ->setComment('CloudFlare Key/Value Store.')
54 | ->setOption('type', 'InnoDB')
55 | ->setOption('charset', 'utf8');
56 | $installer->getConnection()->createTable($table);
57 | }
58 |
59 | $installer->endSetup();
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/Backend/ClientActions.php:
--------------------------------------------------------------------------------
1 | api = $api;
25 | $this->config = $magentoIntegration->getConfig();
26 | $this->integrationAPI = $magentoIntegration->getIntegrationAPI();
27 | $this->dataStore = $magentoIntegration->getDataStore();
28 | $this->logger = $magentoIntegration->getLogger();
29 | $this->request = $request;
30 | }
31 |
32 | /*
33 | * GET /zones
34 | *
35 | * To ensure the plugin can only be used to manage the current Magento installation we
36 | * hook on this call to only return a list of size one of the current domain.
37 | */
38 | public function getZonesReturnMagentoZone()
39 | {
40 | $magentoDomainName = $this->integrationAPI->getMagentoDomainName();
41 |
42 | $response = $this->api->callAPI($this->request);
43 | if ($this->api->responseOk($response)) {
44 | $magentoZone = null;
45 | $bestMatch = strlen($magentoDomainName);
46 | foreach ($response['result'] as $zone) {
47 | $firstOccurrence = strpos($magentoDomainName, $zone['name']);
48 | if ($firstOccurrence !== false && $firstOccurrence < $bestMatch) {
49 | $bestMatch = $firstOccurrence;
50 | $magentoZone = $zone;
51 | }
52 | }
53 | if ($magentoZone === null) {
54 | $this->logger->warning($magentoDomainName . 'doesn\'t appear to be provisioned on CloudFlare.com.');
55 | $magentoZone = array(
56 | 'name' => $magentoDomainName,
57 | 'plan' => array('name' => ''),
58 | 'type' => '',
59 | 'status' => 'inactive',
60 | );
61 | }
62 | $response['result'] = array($magentoZone);
63 | }
64 |
65 | return $response;
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/Backend/ClientAPI.php:
--------------------------------------------------------------------------------
1 | getHttpClient();
17 | $httpClient->setEndpoint($this->getEndpoint());
18 | $this->setHttpClient($httpClient);
19 |
20 | parent::__construct($integration);
21 | }
22 |
23 | /**
24 | * DELETE zones/:id/purge_cache
25 | * https://api.cloudflare.com/#zone-purge-individual-files-by-url-and-cache-tags
26 | *
27 | * @param String[] $tags
28 | * @return
29 | */
30 | public function zonePurgeCacheByTags($tags)
31 | {
32 | $zoneId = $this->getZoneIdForDomainName($this->integrationAPI->getMagentoDomainName());
33 |
34 | if ($zoneId) {
35 | $request = new Request('DELETE', 'zones/'. $zoneId .'/purge_cache', array(), array('tags' => $tags));
36 |
37 | return $this->callAPI($request);
38 | }
39 | }
40 |
41 | /**
42 | * DELETE zones/:id/purge_cache
43 | * https://api.cloudflare.com/#zone-purge-all-files
44 | *
45 | * @return mixed
46 | */
47 | public function zonePurgeCache()
48 | {
49 | $zoneId = $this->getZoneIdForDomainName($this->integrationAPI->getMagentoDomainName());
50 | if ($zoneId) {
51 | $request = new Request('DELETE', 'zones/'. $zoneId .'/purge_cache', array(), array('purge_everything' => true));
52 |
53 | return $this->callAPI($request);
54 | }
55 | }
56 |
57 | /**
58 | * @param String $domainName
59 | * @return null
60 | */
61 | protected function getZoneIdForDomainName($domainName)
62 | {
63 | $zoneId = $this->data_store->getZoneId($domainName);
64 | if ($zoneId !== null) {
65 | return $zoneId;
66 | }
67 |
68 | $request = new Request('GET', 'zones', array('name' => $domainName), array());
69 | $response = $this->callAPI($request);
70 | try {
71 | if ($this->responseOk($response) && count($response['result']) > 0) {
72 | $zoneId = $response['result'][0]['id'];
73 | $this->data_store->setZoneId($domainName, $zoneId);
74 | return $zoneId;
75 | }
76 | } catch (\Exception $e) {
77 | $this->logger->error($e->getMessage());
78 | }
79 |
80 | return null;
81 | }
82 | }
83 |
--------------------------------------------------------------------------------
/Backend/MagentoHttpClient.php:
--------------------------------------------------------------------------------
1 | logger = $logger;
20 | }
21 |
22 | public function send(Request $request)
23 | {
24 | $client = $this->createZendClient($request);
25 | try {
26 | $response = $client->request();
27 | return json_decode($response->getBody(), true);
28 | } catch (\Zend_Http_Client_Exception $e) {
29 | $this->logAPICall($this->endpoint, array(
30 | 'type' => 'request',
31 | 'method' => $request->getMethod(),
32 | 'path' => $request->getUrl(),
33 | 'headers' => $request->getHeaders(),
34 | 'params' => $request->getParameters(),
35 | 'body' => $request->getBody()), true);
36 | $this->logAPICall($this->endpoint, array('type' => 'response', 'code' => $e->getCode(), 'body' => $e->getMessage(), 'stacktrace' => $e->getTraceAsString()), true);
37 | }
38 |
39 | return null;
40 | }
41 |
42 | /**
43 | * @param Request $request
44 | * @return ZendClient $client
45 | */
46 | public function createZendClient(Request $request)
47 | {
48 | $client = new \Zend_Http_Client();
49 | $client->setUri($this->endpoint . $request->getUrl());
50 |
51 | $client->setMethod($request->getMethod());
52 |
53 | $client->setHeaders($request->getHeaders());
54 | $client->setParameterGet($request->getParameters());
55 |
56 | if ($request->getMethod() !== 'GET') {
57 | $client->setRawData(json_encode($request->getBody()), 'application/json');
58 | }
59 |
60 | return $client;
61 | }
62 |
63 | /**
64 | * @param string $apiName
65 | * @param array $message
66 | * @param bool $isError
67 | */
68 | public function logAPICall($apiName, $message, $isError)
69 | {
70 | $logLevel = 'error';
71 | if ($isError === false) {
72 | $logLevel = 'debug';
73 | }
74 | if (!is_string($message)) {
75 | $message = print_r($message, true);
76 | }
77 | $this->logger->$logLevel('['.$apiName.'] '.$message);
78 | }
79 |
80 | public function setEndpoint($endpoint)
81 | {
82 | $this->endpoint = $endpoint;
83 | }
84 | }
85 |
--------------------------------------------------------------------------------
/Backend/DataStore.php:
--------------------------------------------------------------------------------
1 | magentoAPI = $magentoAPI;
17 | }
18 |
19 | /**
20 | * @param $clientAPIKey
21 | * @param $email
22 | * @param $uniqueId
23 | * @param $userKey
24 | * @return mixed
25 | * @internal param $client_api_key
26 | * @internal param $unique_id
27 | * @internal param $user_key
28 | */
29 | public function createUserDataStore($clientAPIKey, $email, $uniqueId, $userKey)
30 | {
31 | //Magento doesn't use the host api - $uniqueId, $userKey will always be null
32 | $this->set(self::CLIENT_API_KEY, $clientAPIKey);
33 | $this->set(self::CLOUDFLARE_EMAIL, $email);
34 | return true;
35 | }
36 |
37 | /**
38 | * @return mixed
39 | */
40 | public function getHostAPIUserUniqueId()
41 | {
42 | return null;
43 | }
44 |
45 | /**
46 | * @return mixed
47 | */
48 | public function getClientV4APIKey()
49 | {
50 | return $this->get(self::CLIENT_API_KEY);
51 | }
52 |
53 | /**
54 | * @return mixed
55 | */
56 | public function getHostAPIUserKey()
57 | {
58 | return null;
59 | }
60 |
61 | /**
62 | * @return mixed
63 | */
64 | public function getCloudFlareEmail()
65 | {
66 | return $this->get(self::CLOUDFLARE_EMAIL);
67 | }
68 |
69 | /**
70 | * @param $domainName
71 | * @return null
72 | */
73 | public function getZoneId($domainName)
74 | {
75 | return $this->get(self::ZONE_ID_KEY . $domainName);
76 | }
77 |
78 | /**
79 | * @param $domainName
80 | * @param $zoneId
81 | * @return mixed
82 | */
83 | public function setZoneId($domainName, $zoneId)
84 | {
85 | return $this->set(self::ZONE_ID_KEY . $domainName, $zoneId);
86 | }
87 |
88 | /**
89 | * @param $key
90 | * @return mixed
91 | */
92 | public function get($key)
93 | {
94 | return json_decode($this->magentoAPI->getValue($key), true);
95 | }
96 |
97 | /**
98 | * @param $key
99 | * @param $value
100 | * @return mixed
101 | */
102 | public function set($key, $value)
103 | {
104 | return $this->magentoAPI->setValue($key, json_encode($value));
105 | }
106 | }
107 |
--------------------------------------------------------------------------------
/view/adminhtml/web/assets/request-submitted-success.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # Contributing to Cloudflare Plugins
2 |
3 | 👍🎉 First off, thanks for taking the time to contribute! 🎉👍
4 |
5 | ## How To Contribute
6 |
7 | We welcome community contribution to this repository. To help add functionality or address issues, please take the following steps:
8 |
9 | * Fork the repository from the master branch.
10 | * Create a new branch for your features / fixes.
11 | * Make the changes you wish to see.
12 | * Add tests for all changes.
13 | * Create a pull request with details of what changes have been made, explanation of new behaviour, and link to issue that is addressed.
14 | * Addressing (with @...) one or more of the maintainers in the description of the pull request
15 | * Ensure documentation contains the correct information.
16 | * Pull requests will be reviewed and hopefully merged into a release.
17 |
18 | ## Before Contributing
19 |
20 | Cloudflare has multiple plugins using shared codebases.
21 |
22 | [WordPress](https://github.com/cloudflare/Cloudflare-WordPress), [CPanel](https://github.com/cloudflare/CloudFlare-CPanel), [Magento](https://github.com/cloudflare/CloudFlare-Magento) are the main repositories of the plugins. Every plugin has a config.js file which allows them to control the frontend of the plugin.
23 |
24 | Below are Cloudflare maintained repositories the plugins depend on.
25 |
26 | * [cloudflare-frontend](https://github.com/cloudflare/CloudFlare-FrontEnd) is a generic frontend used in plugins. You can add/remove cards simply by editing [config](https://github.com/cloudflare/CloudFlare-FrontEnd/blob/master/config.js) file.
27 | * [cf-ui](https://github.com/cloudflare/cf-ui) is a Cloudflare UI Framework where cloudflare-frontend is using.
28 | * [cloudflare-plugin-backend](https://github.com/cloudflare/cloudflare-plugin-backend) is a generic backend plugins use.
29 | * [cf-ip-rewrite](https://github.com/cloudflare/cf-ip-rewrite) allows to rewrite Cloudflare IP's in Application level.
30 | * [mod_cloudflare](https://github.com/cloudflare/mod_cloudflare) allows Apache to rewrite Cloudflare IP's with user IP's. It is not used in plugins itself but it maybe be a better alternative then `cf-ip-rewrite`.
31 |
32 | ## Frontend Updates
33 |
34 | Each plugin may use different Frontend [versions]((https://github.com/cloudflare/CloudFlare-FrontEnd/releases)). When publishing a Frontend release we copy the following files to other plugins;
35 |
36 | * `assets/`
37 | * `fonts/`
38 | * `lang/`
39 | * `stylesheets/`
40 | * `compiled.min.js` which is created when `gulp compress` command is called within Frontend repository.
41 |
42 | ## Translations
43 |
44 | The plugins use a common language file which is located [here](https://github.com/cloudflare/CloudFlare-FrontEnd/tree/master/lang). English translation is always up to date where as other translations are not. If you have any issues or questions regarding with translations feel free to open an [issue](https://github.com/cloudflare/CloudFlare-FrontEnd/issues).
45 |
--------------------------------------------------------------------------------
/etc/events.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
--------------------------------------------------------------------------------
/view/adminhtml/web/assets/plan-changed-success.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/view/adminhtml/web/assets/analytics-welcome.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/etc/di.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | \Magento\Framework\App\DeploymentConfig\Reader
6 | \CloudFlare\Plugin\Model\KeyValueFactory
7 | \Magento\Store\Model\StoreManagerInterface
8 | \Psr\Log\LoggerInterface
9 |
10 |
11 |
12 |
13 |
14 | \CloudFlare\Plugin\Backend\MagentoAPI
15 |
16 |
17 |
18 |
19 | \Psr\Log\LoggerInterface
20 |
21 |
22 |
23 |
24 |
25 | \CloudFlare\Plugin\Backend\MagentoConfig
26 | \CloudFlare\Plugin\Backend\MagentoAPI
27 | \CloudFlare\Plugin\Backend\DataStore
28 | \Psr\Log\LoggerInterface
29 | \CloudFlare\Plugin\Backend\MagentoHttpClient
30 |
31 |
32 |
33 |
34 |
50 |
51 |
52 |
53 |
54 | - HTTP_CF_CONNECTING_IP
55 |
56 |
57 |
58 |
59 |
--------------------------------------------------------------------------------
/Test/Unit/Backend/DataStoreTest.php:
--------------------------------------------------------------------------------
1 | mockMagentoAPI = $this->getMockBuilder('\CloudFlare\Plugin\Backend\MagentoAPI')
15 | ->disableOriginalConstructor()
16 | ->getMock();
17 | $this->dataStore = new DataStore($this->mockMagentoAPI);
18 | }
19 |
20 | public function testCreateUserDataStoreSavesAPIKeyAndEmail()
21 | {
22 | $apiKey = "apiKey";
23 | $email = "email";
24 |
25 | $this->mockMagentoAPI->expects($this->at(0))
26 | ->method('setValue')
27 | ->with(DataStore::CLIENT_API_KEY, json_encode($apiKey));
28 |
29 | $this->mockMagentoAPI->expects($this->at(1))
30 | ->method('setValue')
31 | ->with(DataStore::CLOUDFLARE_EMAIL, json_encode($email));
32 |
33 | $this->dataStore->createUserDataStore($apiKey, $email, null, null);
34 | }
35 |
36 | public function testGetClientV4APIKeyReturnsCorrectValue()
37 | {
38 | $apiKey = "apiKey";
39 | $this->mockMagentoAPI->method('getValue')->willReturn(json_encode($apiKey));
40 |
41 | $response = $this->dataStore->getClientV4APIKey();
42 | $this->assertEquals($response, $apiKey);
43 | }
44 |
45 | public function testGetCloudFlareEmailReturnsCorrectValue()
46 | {
47 | $email = "email";
48 | $this->mockMagentoAPI->method('getValue')->willReturn(json_encode($email));
49 |
50 | $response = $this->dataStore->getClientV4APIKey();
51 | $this->assertEquals($response, $email);
52 | }
53 |
54 | public function testGetHostAPIUserKeyReturnsNull()
55 | {
56 | $this->assertNull($this->dataStore->getHostAPIUserKey());
57 | }
58 |
59 | public function testGetHostAPIUserUniqueIdReturnsNull()
60 | {
61 | $this->assertNull($this->dataStore->getHostAPIUserUniqueId());
62 | }
63 |
64 | public function testGetZoneIdReturnsValue()
65 | {
66 | $domain = "domain";
67 | $key = DataStore::ZONE_ID_KEY.$domain;
68 | $zoneId = "zoneId";
69 |
70 | $this->mockMagentoAPI->method('getValue')->with($key)->willReturn(json_encode($zoneId));
71 | $response = $this->dataStore->getZoneId($domain);
72 | $this->assertEquals($zoneId, $response);
73 | }
74 |
75 | public function testSetZoneIdSetsValue()
76 | {
77 | $domain = "domain";
78 | $key = DataStore::ZONE_ID_KEY.$domain;
79 | $zoneId = "zoneId";
80 |
81 | $this->mockMagentoAPI->expects($this->once())->method('setValue')->with($key, json_encode($zoneId));
82 | $this->dataStore->setZoneId($domain, $zoneId);
83 | }
84 |
85 | public function testGetCallsMagentoAPIGetValue()
86 | {
87 | $key = "key";
88 | $this->mockMagentoAPI->expects($this->once())->method('getValue')->with($key);
89 | $this->dataStore->get($key);
90 | }
91 |
92 | public function testSetCallsMagentoAPISetValue()
93 | {
94 | $key = "key";
95 | $value = "value";
96 | $this->mockMagentoAPI->expects($this->once())->method('setValue')->with($key, json_encode($value));
97 | $this->dataStore->set($key, $value);
98 | }
99 | }
100 |
--------------------------------------------------------------------------------
/Test/Unit/Backend/PluginActionsTest.php:
--------------------------------------------------------------------------------
1 | mockConfig = $this->getMockBuilder('\CF\Integration\DefaultConfig')
26 | ->disableOriginalConstructor()
27 | ->getMock();
28 | $this->mockClientAPIClient = $this->getMockBuilder('\CF\API\Client')
29 | ->disableOriginalConstructor()
30 | ->getMock();
31 | $this->mockDataStore = $this->getMockBuilder('\CloudFlare\Plugin\Backend\DataStore')
32 | ->disableOriginalConstructor()
33 | ->getMock();
34 | $this->mockLogger = $this->getMockBuilder('\Psr\Log\LoggerInterface')
35 | ->disableOriginalConstructor()
36 | ->getMock();
37 | $this->mockMagentoAPI = $this->getMockBuilder('\CloudFlare\Plugin\Backend\MagentoAPI')
38 | ->disableOriginalConstructor()
39 | ->getMock();
40 | $this->mockPluginAPIClient = $this->getMockBuilder('\CF\API\Client')
41 | ->disableOriginalConstructor()
42 | ->getMock();
43 | $this->mockRequest = $this->getMockBuilder('\CF\API\Request')
44 | ->disableOriginalConstructor()
45 | ->getMock();
46 | $this->mockHttpClientInterface = $this->getMockBuilder('\CloudFlare\Plugin\Backend\MagentoHttpClient')
47 | ->disableOriginalConstructor()
48 | ->getMock();
49 |
50 | $this->mockIntegrationContext = new MagentoIntegration(
51 | $this->mockConfig,
52 | $this->mockMagentoAPI,
53 | $this->mockDataStore,
54 | $this->mockLogger,
55 | $this->mockHttpClientInterface
56 | );
57 | $this->pluginActions = new PluginActions(
58 | $this->mockIntegrationContext,
59 | $this->mockPluginAPIClient,
60 | $this->mockRequest
61 | );
62 | $this->pluginActions->setClientAPI($this->mockClientAPIClient);
63 | }
64 |
65 | public function testPatchZoneSettingThrowsExceptionForBadResponse()
66 | {
67 | $this->setExpectedException(ZoneSettingFailException::class);
68 | $this->mockClientAPIClient->method('callAPI')->willReturn(array('errors' => array()));
69 | $this->pluginActions->patchZoneSetting(null, null, null);
70 | }
71 |
72 | public function testPatchZoneSettingWillReturnTrueForPlanUpgradeError()
73 | {
74 | $this->mockClientAPIClient->method('callAPI')->willReturn(array(
75 | 'errors' => array(
76 | array(
77 | 'code' => '',
78 | 'message' => 'Not allowed to edit setting for polish'
79 | )
80 | )
81 | ));
82 | $this->assertTrue($this->pluginActions->patchZoneSetting(null, null, null));
83 | }
84 |
85 | public function testPostPageRuleThrowsExceptionForBadResponse()
86 | {
87 | $this->setExpectedException(ZoneSettingFailException::class);
88 | $this->mockClientAPIClient->method('callAPI')->willReturn(array('errors' => array()));
89 | $this->pluginActions->postPageRule(null, null, null);
90 | }
91 | }
92 |
--------------------------------------------------------------------------------
/view/adminhtml/web/assets/overview-welcome.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
63 |
--------------------------------------------------------------------------------
/Test/Unit/Backend/ClientActionsTest.php:
--------------------------------------------------------------------------------
1 | mockConfig = $this->getMockBuilder('\CF\Integration\DefaultConfig')
23 | ->disableOriginalConstructor()
24 | ->getMock();
25 | $this->mockDataStore = $this->getMockBuilder('\CloudFlare\Plugin\Backend\DataStore')
26 | ->disableOriginalConstructor()
27 | ->getMock();
28 | $this->mockLogger = $this->getMockBuilder('\Psr\Log\LoggerInterface')
29 | ->disableOriginalConstructor()
30 | ->getMock();
31 | $this->mockMagentoAPI = $this->getMockBuilder('\CloudFlare\Plugin\Backend\MagentoAPI')
32 | ->disableOriginalConstructor()
33 | ->getMock();
34 | $this->mockClientAPIClient = $this->getMockBuilder('\CF\API\Client')
35 | ->disableOriginalConstructor()
36 | ->getMock();
37 | $this->mockRequest = $this->getMockBuilder('\CF\API\Request')
38 | ->disableOriginalConstructor()
39 | ->getMock();
40 | $this->mockHttpClient = $this->getMockBuilder('\CF\API\HttpClientInterface')
41 | ->disableOriginalConstructor()
42 | ->getMock();
43 |
44 | $this->mockIntegrationContext = new MagentoIntegration(
45 | $this->mockConfig,
46 | $this->mockMagentoAPI,
47 | $this->mockDataStore,
48 | $this->mockLogger,
49 | $this->mockHttpClient
50 | );
51 | $this->clientActions = new ClientActions(
52 | $this->mockIntegrationContext,
53 | $this->mockClientAPIClient,
54 | $this->mockRequest
55 | );
56 | }
57 |
58 | public function testGetZonesReturnMagentoZoneReturnsZoneIfItExists()
59 | {
60 | $domain = 'domain.com';
61 | $this->mockMagentoAPI->method('getMagentoDomainName')->willReturn($domain);
62 | $testResult = array('name' => $domain);
63 | $this->mockClientAPIClient->method('callAPI')->willReturn(
64 | array(
65 | "success" => true,
66 | "result" => array($testResult)
67 | )
68 | );
69 | $this->mockClientAPIClient->method('responseOk')->willReturn(true);
70 |
71 | $response = $this->clientActions->getZonesReturnMagentoZone();
72 |
73 | $this->assertEquals($testResult, $response["result"][0]);
74 | $this->assertEquals(1, count($response["result"]));
75 | }
76 |
77 | public function testGetZonesReturnMagentoZoneReturnsInactiveZoneIfItDoesntExists()
78 | {
79 | $this->mockClientAPIClient->method('callAPI')->willReturn(
80 | array(
81 | "success" => true,
82 | "result" => array()
83 | )
84 | );
85 | $this->mockClientAPIClient->method('responseOk')->willReturn(true);
86 |
87 | $response = $this->clientActions->getZonesReturnMagentoZone();
88 |
89 | $this->assertEquals("inactive", $response["result"][0]["status"]);
90 | }
91 |
92 | public function testGetZoneReturnsMagentoZoneReturnsCorrectDomainForListsWithSimilarDomains()
93 | {
94 | $expectedDomain = 'domaindomain.com';
95 | $domain = array('name' => $expectedDomain);
96 | $domain2 = array('name' => 'domain.com');
97 |
98 | $this->mockMagentoAPI->method('getMagentoDomainName')->willReturn($expectedDomain);
99 | //order is important, less specific match needs to come before the most specific match
100 | $this->mockClientAPIClient->method('callAPI')->willReturn(
101 | array(
102 | "success" => true,
103 | "result" => array($domain2, $domain)
104 | )
105 | );
106 | $this->mockClientAPIClient->method('responseOk')->willReturn(true);
107 |
108 | $response = $this->clientActions->getZonesReturnMagentoZone();
109 | $this->assertEquals($expectedDomain, $response['result'][0]['name']);
110 | }
111 | }
112 |
--------------------------------------------------------------------------------
/Backend/CacheTags.php:
--------------------------------------------------------------------------------
1 | clientAPI = $clientAPI;
29 | $this->dataStore = $dataStore;
30 | $this->logger = $logger;
31 | }
32 |
33 | /**
34 | * Sets the X-Cache-Tags header(s) on the response
35 | *
36 | * @param $response
37 | * @param $tags
38 | * @return $response
39 | */
40 | public function setCloudFlareCacheTagsResponseHeader($response, $tags)
41 | {
42 | //hash cache tags to fit more in each header
43 | $tags = $this->hashCacheTags($tags);
44 | $cacheTagHeaderList = $this->get255ByteCacheTagHeaderStringValues($tags);
45 |
46 | /*
47 | * CloudFlare Cache Tags allow for multiple X-Cache-Tags headers but Magento2's
48 | * $response->setHeader() doesn't allow for multiple http headers with the same name
49 | * so we only set the first one in the list
50 | */
51 | if (count($cacheTagHeaderList) > 0) {
52 | $response->setHeader(self::CLOUDFLARE_CACHE_TAG_HEADER, $cacheTagHeaderList[0]);
53 | $this->logger->debug("CloudFlare header '". self::CLOUDFLARE_CACHE_TAG_HEADER . "' set with value '". $cacheTagHeaderList[0] ."'");
54 |
55 | if (count($cacheTagHeaderList) > 1) {
56 | $this->logger->debug("Some CloudFlare cache tags were not set because the total length of the list exceeded 255 bytes.");
57 | }
58 | }
59 |
60 | return $response;
61 | }
62 |
63 | /**
64 | * Generate list of X-Cache-Tag header values which are less than 255 bytes each
65 | *
66 | * @param $cacheTagList
67 | * @return array
68 | */
69 | public function get255ByteCacheTagHeaderStringValues($cacheTagList)
70 | {
71 | $cacheTagHeaderList = array();
72 | $cacheTagHeader = "";
73 |
74 | foreach ($cacheTagList as $cacheTag) {
75 | $cacheTagHeaderEncoding = mb_detect_encoding($cacheTagHeader);
76 | $cacheTagEncoding = mb_detect_encoding($cacheTag);
77 |
78 | //Is this cache tag larger than 255 bytes?
79 | if (mb_strlen($cacheTag, $cacheTagEncoding) >= 255) {
80 | array_push($cacheTagHeaderList, mb_strcut($cacheTag, 1, 255));
81 | } //Would appending the current cache tag to the cache tag header put it over the 255 byte limit?
82 | elseif ((mb_strlen($cacheTagHeader, $cacheTagHeaderEncoding) + mb_strlen(",".$cacheTag, $cacheTagEncoding)) > 255) {
83 | //Start new header
84 | array_push($cacheTagHeaderList, $cacheTagHeader);
85 | $cacheTagHeader = $cacheTag;
86 | } else {
87 | //Append cache tag to cache tag header
88 | if ($cacheTagHeader !== "") { //avoid creating headers that start with a comma.
89 | $cacheTagHeader = $cacheTagHeader . ",";
90 | }
91 | $cacheTagHeader = $cacheTagHeader . $cacheTag;
92 | }
93 | }
94 |
95 | array_push($cacheTagHeaderList, $cacheTagHeader);
96 |
97 | return $cacheTagHeaderList;
98 | }
99 |
100 | /**
101 | * Purge cache by tag
102 | *
103 | * @param $tags
104 | */
105 | public function purgeCacheTags(array $tags)
106 | {
107 | if (!empty($tags) && $this->dataStore->get(\CF\API\Plugin::SETTING_PLUGIN_SPECIFIC_CACHE_TAG)) {
108 | $tags = $this->hashCacheTags($tags);
109 | $this->clientAPI->zonePurgeCacheByTags($tags);
110 | }
111 | }
112 |
113 | /**
114 | * Purge entire cache
115 | *
116 | * @return mixed
117 | */
118 | public function purgeCache()
119 | {
120 | return $this->clientAPI->zonePurgeCache();
121 | }
122 |
123 | /**
124 | * Convert cache tags to 3 character hashes so we can fit more in each header
125 | *
126 | * @param array $tags
127 | * @return array
128 | */
129 | public function hashCacheTags(array $tags)
130 | {
131 | $hashedCacheTags = array();
132 | foreach ($tags as $tag) {
133 | array_push($hashedCacheTags, substr(hash('sha256', $tag), 0, 3));
134 | }
135 |
136 | return $hashedCacheTags;
137 | }
138 | }
139 |
--------------------------------------------------------------------------------
/Test/Unit/Controller/Adminhtml/Plugin/ProxyTest.php:
--------------------------------------------------------------------------------
1 | mockContext = $this->getMockBuilder('Magento\Backend\App\Action\Context')
22 | ->disableOriginalConstructor()
23 | ->getMock();
24 | $this->mockDataStore = $this->getMockBuilder('\CloudFlare\Plugin\Backend\DataStore')
25 | ->disableOriginalConstructor()
26 | ->getMock();
27 | $this->mockHttpClient = $this->getMockBuilder('\CloudFlare\Plugin\Backend\MagentoHttpClient')
28 | ->disableOriginalConstructor()
29 | ->getMock();
30 | $this->mockIntegrationContext = $this->getMockBuilder('\CloudFlare\Plugin\Backend\MagentoIntegration')
31 | ->disableOriginalConstructor()
32 | ->getMock();
33 | $this->mockIntegrationContext->method('getHttpClient')->willReturn($this->mockHttpClient);
34 | $this->mockResultJsonFactory = $this->getMockBuilder('\Magento\Framework\Controller\Result\JsonFactory')
35 | ->disableOriginalConstructor()
36 | ->getMock();
37 | $this->mockLogger = $this->getMockBuilder('Psr\Log\LoggerInterface')
38 | ->disableOriginalConstructor()
39 | ->getMock();
40 | $this->mockMagentoAPI = $this->getMockBuilder('\CloudFlare\Plugin\Backend\MagentoAPI')
41 | ->disableOriginalConstructor()
42 | ->getMock();
43 | $this->mockRequestRouter = $this->getMockBuilder('\CF\Router\RequestRouter')
44 | ->disableOriginalConstructor()
45 | ->getMock();
46 | $this->mockClientAPI = $this->getMockBuilder('\CloudFlare\Plugin\Backend\ClientAPI')
47 | ->disableOriginalConstructor()
48 | ->getMock();
49 | $this->mockPluginAPI = $this->getMockBuilder('\CF\API\Plugin')
50 | ->disableOriginalConstructor()
51 | ->getMock();
52 |
53 | $this->proxy = new Proxy(
54 | $this->mockContext,
55 | $this->mockDataStore,
56 | $this->mockIntegrationContext,
57 | $this->mockResultJsonFactory,
58 | $this->mockLogger,
59 | $this->mockMagentoAPI
60 | );
61 |
62 | $this->proxy->setRequestRouter($this->mockRequestRouter);
63 | $this->proxy->setClientAPI($this->mockClientAPI);
64 | $this->proxy->setPluginAPI($this->mockPluginAPI);
65 | }
66 |
67 | public function testProcessUrlKeysCallsSetJsonFormTokenOnMagentoRequest()
68 | {
69 | $mockAuth = $this->getMockBuilder('\Magento\Backend\Model\Auth')
70 | ->disableOriginalConstructor()
71 | ->getMock();
72 | $mockAuth->method('isLoggedIn')->willReturn(false);
73 | $this->mockContext->method('getAuth')->willReturn($mockAuth);
74 |
75 | $mockProxy = $this->getMock(
76 | 'CloudFlare\Plugin\Controller\Adminhtml\Plugin\Proxy',
77 | array('setJsonFormTokenOnMagentoRequest', 'getJSONBody'),
78 | array(
79 | $this->mockContext,
80 | $this->mockDataStore,
81 | $this->mockIntegrationContext,
82 | $this->mockResultJsonFactory,
83 | $this->mockLogger,
84 | $this->mockMagentoAPI,
85 | $this->mockRequestRouter,
86 | $this->mockClientAPI,
87 | $this->mockPluginAPI)
88 | );
89 | $mockProxy->method('getJSONBody')->willReturn(array(Proxy::FORM_KEY => Proxy::FORM_KEY));
90 |
91 | $mockProxy->expects($this->once())
92 | ->method('setJsonFormTokenOnMagentoRequest');
93 |
94 | $mockProxy->_processUrlKeys();
95 | }
96 |
97 | public function testSetJsonFormTokenOnMagentoRequestSetsTokenCorrectly()
98 | {
99 | $token = "token";
100 |
101 | $mockCookieInterface = $this->getMockBuilder('\Magento\Framework\Stdlib\Cookie\CookieReaderInterface')
102 | ->disableOriginalConstructor()
103 | ->getMock();
104 |
105 | $mockStringUtils = $this->getMockBuilder('\Magento\Framework\Stdlib\StringUtils')
106 | ->disableOriginalConstructor()
107 | ->getMock();
108 |
109 | $mockRequest = new \Magento\Framework\HTTP\PhpEnvironment\Request($mockCookieInterface, $mockStringUtils, null);
110 |
111 | $this->proxy->setJsonFormTokenOnMagentoRequest($token, $mockRequest);
112 |
113 |
114 | $this->assertEquals($token, $mockRequest->getParam(Proxy::FORM_KEY));
115 | }
116 | }
117 |
--------------------------------------------------------------------------------
/Test/Unit/Backend/CacheTagsTest.php:
--------------------------------------------------------------------------------
1 | mockClientAPI = $this->getMockBuilder('\CloudFlare\Plugin\Backend\ClientAPI')
17 | ->disableOriginalConstructor()
18 | ->getMock();
19 | $this->mockDataStore = $this->getMockBuilder('\CloudFlare\Plugin\Backend\DataStore')
20 | ->disableOriginalConstructor()
21 | ->getMock();
22 | $this->mockLogger = $this->getMockBuilder('\Psr\Log\LoggerInterface')
23 | ->disableOriginalConstructor()
24 | ->getMock();
25 | $this->cacheTags = new CacheTags($this->mockClientAPI, $this->mockDataStore, $this->mockLogger);
26 | }
27 |
28 | public function testSetCloudFlareCacheTagsResponseHeaderSetsHeader()
29 | {
30 | $mockResponse = $this->getMockBuilder('\Magento\Framework\App\Response\Http')
31 | ->disableOriginalConstructor()
32 | ->getMock();
33 | $mockResponse->expects($this->once())->method('setHeader');
34 | $tags = array("tags");
35 | $this->cacheTags->setCloudFlareCacheTagsResponseHeader($mockResponse, $tags);
36 | }
37 |
38 | public function testGet255ByteCacheTagHeaderStringValuesReturnsArraySizeOneForInputLessThan255Bytes()
39 | {
40 | $tag = $this->generateByteString(1);
41 | $tags = array($tag);
42 | $response = $this->cacheTags->get255ByteCacheTagHeaderStringValues($tags);
43 | $this->assertEquals(1, count($response));
44 | $this->assertEquals($tag, $response[0]);
45 | }
46 |
47 | public function testGet255ByteCacheTagHeaderStringValuesConcatsMultipleTags()
48 | {
49 | $tag1 = $this->generateByteString(1);
50 | $tag2 = $this->generateByteString(2);
51 | $tags = array($tag1, $tag2);
52 | $response = $this->cacheTags->get255ByteCacheTagHeaderStringValues($tags);
53 | $this->assertEquals($tag1.",".$tag2, $response[0]);
54 | }
55 |
56 | public function testGet255ByteCacheTagHeaderStringValuesTrimsLargeTags()
57 | {
58 | $tag256 = $this->generateByteString(256);
59 | $this->assertEquals(256, mb_strlen($tag256, mb_detect_encoding($tag256)));
60 |
61 | $response = $this->cacheTags->get255ByteCacheTagHeaderStringValues(array($tag256));
62 | $this->assertEquals(255, mb_strlen($response[0], mb_detect_encoding($response[0])));
63 | }
64 |
65 | public function testGet255ByteCacheTagHeaderStringValuesHandlesTagListsLargerThan255Bytes()
66 | {
67 | $tag255 = $this->generateByteString(255);
68 | $tag1 = $this->generateByteString(1);
69 | $tags = array($tag255, $tag1);
70 | $response = $this->cacheTags->get255ByteCacheTagHeaderStringValues($tags);
71 | $this->assertEquals(2, count($response));
72 | }
73 |
74 | protected function generateByteString($length)
75 | {
76 | $string = "";
77 | for ($i = 1; $i<=$length; $i++) {
78 | $string = $string."a";
79 | }
80 | return $string;
81 | }
82 |
83 | public function testPurgeCacheTagsDoesntCallAPIForEmptyArray()
84 | {
85 | $this->mockDataStore->method('get')->willReturn(false);
86 | $tags = array();
87 | $this->mockClientAPI->expects($this->never())->method('zonePurgeCacheByTags');
88 | $this->cacheTags->purgeCacheTags($tags);
89 | }
90 |
91 | public function testPurgeCacheTagsDoesntCallAPIIfAutomaticCacheTagDisabled()
92 | {
93 | $this->mockDataStore->method('get')->with(Plugin::SETTING_PLUGIN_SPECIFIC_CACHE_TAG)->willReturn(false);
94 | $tags = array('tagsToPurge');
95 | $this->mockClientAPI->expects($this->never())->method('zonePurgeCacheByTags');
96 | $this->cacheTags->purgeCacheTags($tags);
97 | }
98 |
99 | public function testPurgeCacheTagsCallsAPIForNonEmptyArray()
100 | {
101 | $this->mockDataStore->method('get')->with(Plugin::SETTING_PLUGIN_SPECIFIC_CACHE_TAG)->willReturn(true);
102 | $tags = array('tagToPurge');
103 | $this->mockClientAPI->expects($this->once())->method('zonePurgeCacheByTags');
104 | $this->cacheTags->purgeCacheTags($tags);
105 | }
106 |
107 | public function testHashCacheTagsHashesWithSha256AndTruncatesToThreeCharacters()
108 | {
109 | $tag = "cacheTag";
110 | $tags = array($tag);
111 | $expectedHash = substr(hash('sha256', $tag), 0, 3);
112 | $hashedCacheTags = $this->cacheTags->hashCacheTags($tags);
113 | $this->assertEquals($expectedHash, $hashedCacheTags[0]);
114 | }
115 |
116 | public function testPurgeCacheCallsPurgeCacheAPI()
117 | {
118 | $this->mockClientAPI->expects($this->once())->method('zonePurgeCache');
119 | $this->cacheTags->purgeCache();
120 | }
121 | }
122 |
--------------------------------------------------------------------------------
/Backend/MagentoAPI.php:
--------------------------------------------------------------------------------
1 | configReader = $configReader;
28 | $this->keyValueFactory = $keyValueFactory;
29 | $this->logger = $logger;
30 | $this->storeManager = $storeManager;
31 |
32 | $this->magentoConfig = $this->configReader->load();
33 | }
34 |
35 | public function getMagentoDomainName()
36 | {
37 |
38 | //getBaseUrl() has format (http | https)://(www)[DOMAIN NAME]/
39 | //need [DOMAIN NAME]
40 | $domainName = $this->storeManager->getStore()->getBaseUrl();
41 | $domainName = str_replace("http://", "", $domainName);
42 | $domainName = str_replace("https://", "", $domainName);
43 | $domainName = str_replace("www.", "", $domainName);
44 | $domainName = rtrim($domainName, "/");
45 |
46 | return $domainName;
47 | }
48 |
49 | public function getMagentoAdminPath()
50 | {
51 | return $this->magentoConfig['backend']['frontName'];
52 | }
53 |
54 | /**
55 | * @param $key
56 | * @return null
57 | */
58 | public function getValue($key)
59 | {
60 | try {
61 | $keyValueModel = $this->keyValueFactory->create();
62 | $keyValueModel->load($key, InstallSchema::CLOUDFLARE_DATA_TABLE_KEY_COLUMN);
63 | $result = $keyValueModel->getData();
64 |
65 | if (array_key_exists(InstallSchema::CLOUDFLARE_DATA_TABLE_VALUE_COLUMN, $result)) {
66 | return $result[InstallSchema::CLOUDFLARE_DATA_TABLE_VALUE_COLUMN];
67 | }
68 | } catch (\Zend_Db_Statement_Exception $e) {
69 | $this->logger->error($e->getMessage() . $e->getTraceAsString());
70 | }
71 |
72 | return null;
73 | }
74 |
75 | /**
76 | * @param $key
77 | * @param $value
78 | * @return bool
79 | */
80 | public function setValue($key, $value)
81 | {
82 | try {
83 | $keyValueModel = $this->keyValueFactory->create();
84 | $keyValueModel->load($key, InstallSchema::CLOUDFLARE_DATA_TABLE_KEY_COLUMN);
85 | if (empty($keyValueModel->getData())) {
86 | //key doesn't exist yet, create new
87 | $keyValueModel = $this->keyValueFactory->create();
88 | $keyValueModel->setData(InstallSchema::CLOUDFLARE_DATA_TABLE_KEY_COLUMN, $key);
89 | $keyValueModel->setData(InstallSchema::CLOUDFLARE_DATA_TABLE_VALUE_COLUMN, $value);
90 | $keyValueModel->save();
91 | } else {
92 | //update existing key
93 | $keyValueModel->setData(InstallSchema::CLOUDFLARE_DATA_TABLE_VALUE_COLUMN, $value);
94 | $keyValueModel->save();
95 | }
96 | return true;
97 | } catch (\Zend_Db_Statement_Exception $e) {
98 | $this->logger->error($e->getMessage() . $e->getTraceAsString());
99 | }
100 | return false;
101 | }
102 |
103 | /**
104 | * @param $domainName
105 | * @return mixed
106 | */
107 | public function getDNSRecords($domainName)
108 | {
109 | return null;
110 | }
111 |
112 | /**
113 | * @param $domainName
114 | * @param DNSRecord $DNSRecord
115 | * @return mixed
116 | */
117 | public function addDNSRecord($domainName, DNSRecord $DNSRecord)
118 | {
119 | return null;
120 | }
121 |
122 | /**
123 | * @param $domain_name
124 | * @param DNSRecord $DNSRecord
125 | * @return mixed
126 | */
127 | public function editDNSRecord($domain_name, DNSRecord $DNSRecord)
128 | {
129 | return null;
130 | }
131 |
132 | /**
133 | * @param $domain_name
134 | * @param DNSRecord $DNSRecord
135 | * @return mixed
136 | */
137 | public function removeDNSRecord($domain_name, DNSRecord $DNSRecord)
138 | {
139 | return null;
140 | }
141 |
142 | /**
143 | * @return mixed
144 | */
145 | public function getHostAPIKey()
146 | {
147 | return null;
148 | }
149 |
150 | /**
151 | * @param null $userId
152 | * @return mixed
153 | */
154 | public function getDomainList($userId = null)
155 | {
156 | return null;
157 | }
158 |
159 | /**
160 | * @return mixed
161 | */
162 | public function getUserId()
163 | {
164 | return null;
165 | }
166 | }
167 |
--------------------------------------------------------------------------------
/Controller/Adminhtml/Plugin/Proxy.php:
--------------------------------------------------------------------------------
1 | dataStore = $dataStore;
54 | $this->integrationContext = $integrationContext;
55 | $this->logger = $logger;
56 | $this->magentoAPI = $magentoAPI;
57 | $this->resultJsonFactory = $resultJsonFactory;
58 |
59 | //PI-1074 - new is bad but a necessary work around here.
60 | $this->clientAPI = new ClientAPI($this->integrationContext);
61 | $this->pluginAPI = new Plugin($this->integrationContext);
62 |
63 | $this->requestRouter = new RequestRouter($this->integrationContext);
64 | $this->requestRouter->addRouter($this->clientAPI, ClientRoutes::$routes);
65 | $this->requestRouter->addRouter($this->pluginAPI, PluginRoutes::getRoutes(\CF\API\PluginRoutes::$routes));
66 |
67 | // php://input can only be read once
68 | $decodedJson = json_decode(file_get_contents('php://input'), true);
69 | if (json_last_error() !== 0) {
70 | $this->logger->error("Error decoding JSON: ". json_last_error_msg());
71 | }
72 | $this->jsonBody = $decodedJson;
73 |
74 | parent::__construct($context);
75 | }
76 |
77 | /**
78 | * @return \Magento\Framework\Controller\Result\Json
79 | */
80 | public function execute()
81 | {
82 | $result = $this->resultJsonFactory->create();
83 |
84 | $magentoRequest = $this->getRequest();
85 | $method = $magentoRequest->getMethod();
86 | $parameters = $magentoRequest->getParams();
87 | $body = $this->getJsonBody();
88 | $path = (strtoupper($method === "GET") ? $parameters['proxyURL'] : $body['proxyURL']);
89 |
90 | $request = new Request($method, $path, $parameters, $body);
91 |
92 | $response = $this->requestRouter->route($request);
93 |
94 | return $result->setData($response);
95 | }
96 |
97 | public function getJsonBody()
98 | {
99 | return $this->jsonBody;
100 | }
101 |
102 | /**
103 | * @param $jsonBody
104 | */
105 | public function setJsonBody($jsonBody)
106 | {
107 | $this->jsonBody = $jsonBody;
108 | }
109 |
110 | /*
111 | * Magento CSRF validation can't find the CSRF Token "form_key" if its in the JSON
112 | * so we copy it from the JSON body to the Magento request parameters.
113 | */
114 | public function _processUrlKeys()
115 | {
116 | $requestJsonBody = $this->getJsonBody();
117 | if ($requestJsonBody !== null && array_key_exists(self::FORM_KEY, $requestJsonBody)) {
118 | $this->setJsonFormTokenOnMagentoRequest($requestJsonBody[self::FORM_KEY], $this->getRequest());
119 | }
120 | return parent::_processUrlKeys();
121 | }
122 |
123 | /**
124 | * @param $token "form_key"
125 | * @param $request
126 | */
127 | public function setJsonFormTokenOnMagentoRequest($token, $request)
128 | {
129 | $parameters = $request->getParams();
130 | $parameters[self::FORM_KEY] = $token;
131 | $request->setParams($parameters);
132 | return $request;
133 | }
134 |
135 | /**
136 | * @param RequestRouter $requestRouter
137 | */
138 | public function setRequestRouter(RequestRouter $requestRouter)
139 | {
140 | $this->requestRouter = $requestRouter;
141 | }
142 |
143 | /**
144 | * @param ClientAPI $clientAPI
145 | */
146 | public function setClientAPI(ClientAPI $clientAPI)
147 | {
148 | $this->clientAPI = $clientAPI;
149 | }
150 |
151 | /**
152 | * @param Plugin $pluginAPI
153 | */
154 | public function setPluginAPI(Plugin $pluginAPI)
155 | {
156 | $this->pluginAPI = $pluginAPI;
157 | }
158 | }
159 |
--------------------------------------------------------------------------------
/Test/Unit/Backend/MagentoAPITest.php:
--------------------------------------------------------------------------------
1 | mockConfigReader = $this->getMockBuilder('\Magento\Framework\App\DeploymentConfig\Reader')
21 | ->disableOriginalConstructor()
22 | ->getMock();
23 | $this->mockKeyValueFactory = $this->getMockBuilder('\CloudFlare\Plugin\Model\KeyValueFactory')
24 | ->disableOriginalConstructor()
25 | ->setMethods(['create'])
26 | ->getMock();
27 | $this->mockKeyValueModel = $this->getMockBuilder('\CloudFlare\Plugin\Model\KeyValue')
28 | ->disableOriginalConstructor()
29 | ->getMock();
30 | $this->mockKeyValueFactory->method('create')->willReturn($this->mockKeyValueModel);
31 | $this->mockLogger = $this->getMockBuilder('\Psr\Log\LoggerInterface')
32 | ->disableOriginalConstructor()
33 | ->getMock();
34 | $this->mockStoreManager = $this->getMockBuilder('\Magento\Store\Model\StoreManagerInterface')
35 | ->disableOriginalConstructor()
36 | ->getMock();
37 | $this->mockStore = $this->getMockBuilder('\Magento\Store\Model\Data\StoreConfig')
38 | ->disableOriginalConstructor()
39 | ->getMock();
40 | $this->mockStoreManager->method('getStore')->willReturn($this->mockStore);
41 | $this->magentoAPI = new MagentoAPI(
42 | $this->mockConfigReader,
43 | $this->mockKeyValueFactory,
44 | $this->mockStoreManager,
45 | $this->mockLogger
46 | );
47 | }
48 |
49 | public function testGetMagentoDomainNameRemovesHttpHttpsSlashFromBaseUrl()
50 | {
51 | $this->mockStore->method('getBaseUrl')->willReturn("http://www.site.com/");
52 | $fqdn = $this->magentoAPI->getMagentoDomainName();
53 | $this->assertEquals("site.com", $fqdn);
54 | }
55 |
56 | public function testGetMagentoAdminPathReturnsConfigPath()
57 | {
58 | $configPath = "configPath";
59 | $this->mockConfigReader->method('load')->willReturn(
60 | array(
61 | 'backend' => array('frontName' => $configPath)
62 | )
63 | );
64 | $this->magentoAPI = new MagentoAPI(
65 | $this->mockConfigReader,
66 | $this->mockKeyValueFactory,
67 | $this->mockStoreManager,
68 | $this->mockLogger
69 | );
70 |
71 | $this->assertEquals($configPath, $this->magentoAPI->getMagentoAdminPath());
72 | }
73 |
74 | public function testGetValueReturnsNullForBadKey()
75 | {
76 | $key = "key";
77 |
78 | $this->mockKeyValueModel->method('load')
79 | ->with($key, "key")
80 | ->willReturn(true);
81 | $this->mockKeyValueModel->method('getData')->willReturn(array());
82 |
83 | $result = $this->magentoAPI->getValue($key);
84 | $this->assertNull($result);
85 | }
86 |
87 | public function testGetValueReturnsCorrectValue()
88 | {
89 | $key = "key";
90 | $value = "value";
91 |
92 | $this->mockKeyValueModel->method('load')
93 | ->with($key, InstallSchema::CLOUDFLARE_DATA_TABLE_KEY_COLUMN)
94 | ->willReturn(true);
95 | $this->mockKeyValueModel->method('getData')->willReturn(array(
96 | 'id' => 'id',
97 | 'key' => $key,
98 | 'value' => $value
99 | ));
100 |
101 | $result = $this->magentoAPI->getValue($key);
102 | $this->assertEquals($value, $result);
103 | }
104 |
105 | public function testSetValueCreatesNewKeyIfItDoesntExist()
106 | {
107 | $key = "key";
108 | $value = "value";
109 |
110 | $this->mockKeyValueModel->method('getData')->willReturn(array());
111 |
112 | $this->mockKeyValueModel->expects($this->at(1))
113 | ->method('create');
114 | $this->mockKeyValueModel->expects($this->at(2))
115 | ->method('setData')
116 | ->with(InstallSchema::CLOUDFLARE_DATA_TABLE_KEY_COLUMN, $key);
117 | $this->mockKeyValueModel->expects($this->at(3))
118 | ->method('setData')
119 | ->with(InstallSchema::CLOUDFLARE_DATA_TABLE_VALUE_COLUMN, $value);
120 | $this->mockKeyValueModel->expects($this->once())->method('save');
121 |
122 | $this->magentoAPI->setValue($key, $value);
123 | }
124 |
125 | public function testSetValueUpdatesExistingKey()
126 | {
127 | $id = "1";
128 | $key = "key";
129 | $value = "value";
130 |
131 | $this->mockKeyValueModel->method('getData')->willReturn(array(
132 | $id => $id,
133 | $key => $key,
134 | $value => $value
135 | ));
136 |
137 | $this->mockKeyValueModel->expects($this->at(1))
138 | ->method('create');
139 | $this->mockKeyValueModel->expects($this->once())
140 | ->method('setData')
141 | ->with(InstallSchema::CLOUDFLARE_DATA_TABLE_VALUE_COLUMN, $value);
142 | $this->mockKeyValueModel->expects($this->once())->method('save');
143 |
144 | $this->magentoAPI->setValue($key, $value);
145 | }
146 | }
147 |
--------------------------------------------------------------------------------
/view/adminhtml/web/fonts/fontawesome-cloudflare.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/Backend/PluginActions.php:
--------------------------------------------------------------------------------
1 | clientAPI = new clientAPI($defaultIntegration);
30 | }
31 |
32 | /*
33 | * PATCH /plugin/:id/settings/default_settings
34 | */
35 | public function applyDefaultSettings()
36 | {
37 | $pathArray = explode('/', $this->request->getUrl());
38 | $zoneId = $pathArray[1];
39 |
40 | $this->patchZoneSetting('zones/'. $zoneId .'/settings/security_level', array(), array('value' => 'medium'));
41 |
42 | $this->patchZoneSetting('zones/'. $zoneId .'/settings/cache_level', array(), array('value' => 'basic'));
43 |
44 | $this->patchZoneSetting('zones/'. $zoneId .'/settings/minify', array(), array('value' => array('css' => 'on', 'html' => 'off', 'js' => 'off')));
45 |
46 | $this->patchZoneSetting('zones/'. $zoneId .'/settings/browser_cache_ttl', array(), array('value' => 14400)); //4 hours
47 |
48 | $this->patchZoneSetting('zones/'. $zoneId .'/settings/always_online', array(), array('value' => 'on'));
49 |
50 | $this->patchZoneSetting('zones/'. $zoneId .'/settings/development_mode', array(), array('value' => 'off'));
51 |
52 | $this->patchZoneSetting('zones/'. $zoneId .'/settings/ipv6', array(), array('value' => 'off'));
53 |
54 | $this->patchZoneSetting('zones/'. $zoneId .'/settings/websockets', array(), array('value' => 'on'));
55 |
56 | $this->patchZoneSetting('zones/'. $zoneId .'/settings/ip_geolocation', array(), array('value' => 'on'));
57 |
58 | $this->patchZoneSetting('zones/'. $zoneId .'/settings/email_obfuscation', array(), array('value' => 'on'));
59 |
60 | $this->patchZoneSetting('zones/'. $zoneId .'/settings/server_side_exclude', array(), array('value' => 'on'));
61 |
62 | $this->patchZoneSetting('zones/'. $zoneId .'/settings/hotlink_protection', array(), array('value' => 'off'));
63 |
64 | $this->patchZoneSetting('zones/'. $zoneId .'/settings/polish', array(), array('value' => 'off'));
65 |
66 | $this->patchZoneSetting('zones/'. $zoneId .'/settings/mirage', array(), array('value' => 'off'));
67 |
68 | $this->patchZoneSetting('zones/'. $zoneId .'/settings/rocket_loader', array(), array('value' => 'off'));
69 |
70 | $adminUrlPattern = $this->integrationAPI->getMagentoDomainName() . '/' . $this->integrationAPI->getMagentoAdminPath() . "*";
71 | $checkoutUrlPattern = $this->integrationAPI->getMagentoDomainName() . '/checkout*';
72 | $setupUrlPattern = $this->integrationAPI->getMagentoDomainName() . '/setup*';
73 |
74 | $this->postPageRule($zoneId, $this->createPageRuleDisablePerformanceCacheBypassJsonBody($adminUrlPattern));
75 | $this->postPageRule($zoneId, $this->createPageRuleDisablePerformanceCacheBypassJsonBody($checkoutUrlPattern));
76 | $this->postPageRule($zoneId, $this->createPageRuleDisablePerformanceCacheBypassJsonBody($setupUrlPattern));
77 | }
78 |
79 | /**
80 | * @param $url
81 | * @param $parameters
82 | * @param $body
83 | * @return bool
84 | * @throws ZoneSettingFailException
85 | */
86 | public function patchZoneSetting($url, $parameters, $body)
87 | {
88 | $response = $this->clientAPI->callAPI(new \CF\API\Request('PATCH', $url, $parameters, $body));
89 |
90 | if (!$this->clientAPI->responseOk($response)) {
91 | foreach ($response['errors'] as $error) {
92 | if (in_array($error['message'], self::$upgradePlanErrors)) {
93 | //error is related to upgrading the plan.
94 | return true;
95 | }
96 | }
97 | throw new ZoneSettingFailException();
98 | }
99 | }
100 |
101 | /**
102 | * @param $zoneId
103 | * @param $body
104 | * @throws ZoneSettingFailException
105 | */
106 | public function postPageRule($zoneId, $body)
107 | {
108 | $response = $this->clientAPI->callAPI(new \CF\API\Request('POST', 'zones/'. $zoneId .'/pagerules', array(), $body));
109 | if (!$this->clientAPI->responseOk($response)) {
110 | throw new ZoneSettingFailException();
111 | }
112 | }
113 |
114 | /**
115 | * @param $urlPattern
116 | * @return array
117 | */
118 | public function createPageRuleDisablePerformanceCacheBypassJsonBody($urlPattern)
119 | {
120 | return array(
121 | 'targets' => array(
122 | array(
123 | 'target' => 'url',
124 | 'constraint' => array(
125 | 'operator' => 'matches',
126 | 'value' => $urlPattern
127 | )
128 | )
129 | ),
130 | 'actions' => array(
131 | array(
132 | 'id' => 'disable_performance'
133 | ),
134 | array(
135 | 'id' => 'cache_level',
136 | 'value' => 'bypass'
137 | )
138 | ),
139 | 'status' => 'active'
140 | );
141 | }
142 | }
143 |
--------------------------------------------------------------------------------
/view/adminhtml/web/assets/logo.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/view/adminhtml/web/assets/logo-symbol.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
92 |
--------------------------------------------------------------------------------
/view/adminhtml/web/assets/overview-welcome-yjs.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/view/adminhtml/web/assets/yjs-logo.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/view/adminhtml/web/assets/logo-reverse.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
130 |
--------------------------------------------------------------------------------
/view/adminhtml/web/stylesheets/hacks.css:
--------------------------------------------------------------------------------
1 | /*
2 | * Currently we're using two style sheets while WWW restyles from Backbone > React.
3 | * Eventually all the styles will live in components.css but until that day we'll hack
4 | * everything here.
5 | */
6 |
7 |
8 | /* Fix black fill in Analytics */
9 | .c3-chart {
10 | fill: transparent;
11 | }
12 |
13 | /* center cf-component-toggle */
14 | .cf-toggle {
15 | margin: 0 auto;
16 | }
17 |
18 | .cf-icon--loading::before {
19 | width: 16px;
20 | }
21 |
22 | .cf-toggle::before, .cf-toggle::after {
23 | font-size: 10px;
24 | }
25 |
26 | #cf-login-page {
27 | max-width: 400px;
28 | margin: 0 auto;
29 | }
30 | #cf-login-page form {
31 | margin-bottom: 20px;
32 | }
33 |
34 | #cf-login-page h3 {
35 | text-align: center;
36 | }
37 |
38 | #cf-login-page .cf-form__fieldset_content {
39 | background-color: #FFF;
40 | border-color: #FFF;
41 | }
42 |
43 | #cf-login-page legend {
44 | display: none;
45 | }
46 |
47 | #cf-login-page .cf-layout__row {
48 | margin-top:15px;
49 | }
50 |
51 | #cf-login-page .cf-layout__column {
52 | text-align: center;
53 | }
54 |
55 | /* Fix z-index issue with Magento Nav */
56 | .cloudflare-partners .header {
57 | z-index: 1;
58 | }
59 |
60 | /* cf-component-select */
61 | /**
62 | * React Select
63 | * ============
64 | * Created by Jed Watson and Joss Mackison for KeystoneJS, http://www.keystonejs.com/
65 | * https://twitter.com/jedwatson https://twitter.com/jossmackison https://twitter.com/keystonejs
66 | * MIT License: https://github.com/keystonejs/react-select
67 | */
68 | .Select {
69 | position: relative;
70 | }
71 | .Select,
72 | .Select div,
73 | .Select input,
74 | .Select span {
75 | -webkit-box-sizing: border-box;
76 | -moz-box-sizing: border-box;
77 | box-sizing: border-box;
78 | }
79 | .Select.is-disabled > .Select-control {
80 | background-color: #f9f9f9;
81 | }
82 | .Select.is-disabled > .Select-control:hover {
83 | box-shadow: none;
84 | }
85 | .Select.is-disabled .Select-arrow-zone {
86 | cursor: default;
87 | pointer-events: none;
88 | }
89 | .Select-control {
90 | background-color: #fff;
91 | border-color: #d9d9d9 #ccc #b3b3b3;
92 | border-radius: 4px;
93 | border: 1px solid #ccc;
94 | color: #333;
95 | cursor: default;
96 | display: table;
97 | height: 36px;
98 | outline: none;
99 | overflow: hidden;
100 | position: relative;
101 | width: 100%;
102 | }
103 | .Select-control:hover {
104 | box-shadow: 0 1px 0 rgba(0, 0, 0, 0.06);
105 | }
106 | .is-searchable.is-open > .Select-control {
107 | cursor: text;
108 | }
109 | .is-open > .Select-control {
110 | border-bottom-right-radius: 0;
111 | border-bottom-left-radius: 0;
112 | background: #fff;
113 | border-color: #b3b3b3 #ccc #d9d9d9;
114 | }
115 | .is-open > .Select-control > .Select-arrow {
116 | border-color: transparent transparent #999;
117 | border-width: 0 5px 5px;
118 | }
119 | .is-searchable.is-focused:not(.is-open) > .Select-control {
120 | cursor: text;
121 | }
122 | .is-focused:not(.is-open) > .Select-control {
123 | border-color: #007eff;
124 | box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075), 0 0 0 3px rgba(0, 126, 255, 0.1);
125 | }
126 | .Select-placeholder,
127 | :not(.Select--multi) > .Select-control .Select-value {
128 | bottom: 0;
129 | color: #000;
130 | left: 0;
131 | line-height: 34px;
132 | padding-left: 10px;
133 | padding-right: 10px;
134 | position: absolute;
135 | right: 0;
136 | top: 0;
137 | max-width: 100%;
138 | overflow: hidden;
139 | text-overflow: ellipsis;
140 | white-space: nowrap;
141 | }
142 | .has-value:not(.Select--multi) > .Select-control > .Select-value .Select-value-label,
143 | .has-value.is-pseudo-focused:not(.Select--multi) > .Select-control > .Select-value .Select-value-label {
144 | color: #333;
145 | }
146 | .has-value:not(.Select--multi) > .Select-control > .Select-value a.Select-value-label,
147 | .has-value.is-pseudo-focused:not(.Select--multi) > .Select-control > .Select-value a.Select-value-label {
148 | cursor: pointer;
149 | text-decoration: none;
150 | }
151 | .has-value:not(.Select--multi) > .Select-control > .Select-value a.Select-value-label:hover,
152 | .has-value.is-pseudo-focused:not(.Select--multi) > .Select-control > .Select-value a.Select-value-label:hover,
153 | .has-value:not(.Select--multi) > .Select-control > .Select-value a.Select-value-label:focus,
154 | .has-value.is-pseudo-focused:not(.Select--multi) > .Select-control > .Select-value a.Select-value-label:focus {
155 | color: #007eff;
156 | outline: none;
157 | text-decoration: underline;
158 | }
159 | .Select-input {
160 | height: 34px;
161 | padding-left: 10px;
162 | padding-right: 10px;
163 | vertical-align: middle;
164 | }
165 | .Select-input > input {
166 | background: none transparent;
167 | border: 0 none;
168 | box-shadow: none;
169 | cursor: default;
170 | display: inline-block;
171 | font-family: inherit;
172 | font-size: inherit;
173 | height: 34px;
174 | margin: 0;
175 | outline: none;
176 | padding: 0;
177 | -webkit-appearance: none;
178 | }
179 | .is-focused .Select-input > input {
180 | cursor: text;
181 | }
182 | .has-value.is-pseudo-focused .Select-input {
183 | opacity: 0;
184 | }
185 | .Select-control:not(.is-searchable) > .Select-input {
186 | outline: none;
187 | }
188 | .Select-loading-zone {
189 | cursor: pointer;
190 | display: table-cell;
191 | position: relative;
192 | text-align: center;
193 | vertical-align: middle;
194 | width: 16px;
195 | }
196 | .Select-loading {
197 | -webkit-animation: Select-animation-spin 400ms infinite linear;
198 | -o-animation: Select-animation-spin 400ms infinite linear;
199 | animation: Select-animation-spin 400ms infinite linear;
200 | width: 16px;
201 | height: 16px;
202 | box-sizing: border-box;
203 | border-radius: 50%;
204 | border: 2px solid #ccc;
205 | border-right-color: #333;
206 | display: inline-block;
207 | position: relative;
208 | vertical-align: middle;
209 | }
210 | .Select-clear-zone {
211 | -webkit-animation: Select-animation-fadeIn 200ms;
212 | -o-animation: Select-animation-fadeIn 200ms;
213 | animation: Select-animation-fadeIn 200ms;
214 | color: #999;
215 | cursor: pointer;
216 | display: table-cell;
217 | position: relative;
218 | text-align: center;
219 | vertical-align: middle;
220 | width: 17px;
221 | }
222 | .Select-clear-zone:hover {
223 | color: #D0021B;
224 | }
225 | .Select-clear {
226 | display: inline-block;
227 | font-size: 18px;
228 | line-height: 1;
229 | }
230 | .Select--multi .Select-clear-zone {
231 | width: 17px;
232 | }
233 | .Select-arrow-zone {
234 | cursor: pointer;
235 | display: table-cell;
236 | position: relative;
237 | text-align: center;
238 | vertical-align: middle;
239 | width: 25px;
240 | padding-right: 5px;
241 | }
242 | .Select-arrow {
243 | border-color: #999 transparent transparent;
244 | border-style: solid;
245 | border-width: 5px 5px 2.5px;
246 | display: inline-block;
247 | height: 0;
248 | width: 0;
249 | }
250 | .is-open .Select-arrow,
251 | .Select-arrow-zone:hover > .Select-arrow {
252 | border-top-color: #666;
253 | }
254 | @-webkit-keyframes Select-animation-fadeIn {
255 | from {
256 | opacity: 0;
257 | }
258 | to {
259 | opacity: 1;
260 | }
261 | }
262 | @keyframes Select-animation-fadeIn {
263 | from {
264 | opacity: 0;
265 | }
266 | to {
267 | opacity: 1;
268 | }
269 | }
270 | .Select-menu-outer {
271 | border-bottom-right-radius: 4px;
272 | border-bottom-left-radius: 4px;
273 | background-color: #fff;
274 | border: 1px solid #ccc;
275 | border-top-color: #e6e6e6;
276 | box-shadow: 0 1px 0 rgba(0, 0, 0, 0.06);
277 | box-sizing: border-box;
278 | margin-top: -1px;
279 | max-height: 200px;
280 | position: absolute;
281 | top: 100%;
282 | width: 100%;
283 | z-index: 214748364;
284 | -webkit-overflow-scrolling: touch;
285 | }
286 | .Select-menu {
287 | max-height: 198px;
288 | overflow-y: auto;
289 | }
290 | .Select-option {
291 | box-sizing: border-box;
292 | background-color: #fff;
293 | color: #666666;
294 | cursor: pointer;
295 | display: block;
296 | padding: 8px 10px;
297 | }
298 | .Select-option:last-child {
299 | border-bottom-right-radius: 4px;
300 | border-bottom-left-radius: 4px;
301 | }
302 | .Select-option.is-focused {
303 | background-color: rgba(0, 126, 255, 0.08);
304 | color: #333;
305 | }
306 | .Select-option.is-disabled {
307 | color: #cccccc;
308 | cursor: default;
309 | }
310 | .Select-noresults {
311 | box-sizing: border-box;
312 | color: #999999;
313 | cursor: default;
314 | display: block;
315 | padding: 8px 10px;
316 | }
317 | .Select--multi .Select-input {
318 | vertical-align: middle;
319 | margin-left: 10px;
320 | padding: 0;
321 | }
322 | .Select--multi.has-value .Select-input {
323 | margin-left: 5px;
324 | }
325 | .Select--multi .Select-value {
326 | background-color: rgba(0, 126, 255, 0.08);
327 | border-radius: 2px;
328 | border: 1px solid rgba(0, 126, 255, 0.24);
329 | color: #007eff;
330 | display: inline-block;
331 | font-size: 0.9em;
332 | line-height: 1.4;
333 | margin-left: 5px;
334 | margin-top: 5px;
335 | vertical-align: top;
336 | }
337 | .Select--multi .Select-value-icon,
338 | .Select--multi .Select-value-label {
339 | display: inline-block;
340 | vertical-align: middle;
341 | }
342 | .Select--multi .Select-value-label {
343 | border-bottom-right-radius: 2px;
344 | border-top-right-radius: 2px;
345 | cursor: default;
346 | padding: 2px 5px;
347 | }
348 | .Select--multi a.Select-value-label {
349 | color: #007eff;
350 | cursor: pointer;
351 | text-decoration: none;
352 | }
353 | .Select--multi a.Select-value-label:hover {
354 | text-decoration: underline;
355 | }
356 | .Select--multi .Select-value-icon {
357 | cursor: pointer;
358 | border-bottom-left-radius: 2px;
359 | border-top-left-radius: 2px;
360 | border-right: 1px solid rgba(0, 126, 255, 0.24);
361 | padding: 1px 5px 3px;
362 | }
363 | .Select--multi .Select-value-icon:hover,
364 | .Select--multi .Select-value-icon:focus {
365 | background-color: rgba(0, 113, 230, 0.08);
366 | color: #0071e6;
367 | }
368 | .Select--multi .Select-value-icon:active {
369 | background-color: rgba(0, 126, 255, 0.24);
370 | }
371 | .Select--multi.is-disabled .Select-value {
372 | background-color: #fcfcfc;
373 | border: 1px solid #e3e3e3;
374 | color: #333;
375 | }
376 | .Select--multi.is-disabled .Select-value-icon {
377 | cursor: not-allowed;
378 | border-right: 1px solid #e3e3e3;
379 | }
380 | .Select--multi.is-disabled .Select-value-icon:hover,
381 | .Select--multi.is-disabled .Select-value-icon:focus,
382 | .Select--multi.is-disabled .Select-value-icon:active {
383 | background-color: #fcfcfc;
384 | }
385 | @keyframes Select-animation-spin {
386 | to {
387 | transform: rotate(1turn);
388 | }
389 | }
390 | @-webkit-keyframes Select-animation-spin {
391 | to {
392 | -webkit-transform: rotate(1turn);
393 | }
394 | }
395 |
396 | /* end cf-component-select */
397 |
--------------------------------------------------------------------------------
/view/adminhtml/web/fonts/cloudflare-font.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/view/adminhtml/web/lang/en.js:
--------------------------------------------------------------------------------
1 | {
2 | "component.clientLogin.form.email": "Email",
3 | "component.clientLogin.form.apiKeyHelp": "Already have an account? Get your API Key from",
4 | "component.clientLogin.form.apiKey": "API Key",
5 | "component.clientLogin.form.button": "Save API Credentials",
6 | "component.clientLogin.form.signUp": "Sign up",
7 | "component.clientLogin.form.title": "Enter Cloudflare API Credentials",
8 | "component.clientLogin.cloudflare.description": "New to Cloudflare? Sign up at",
9 | "component.customcardcontrol.upgrade": "Upgrade to",
10 | "component.login.form.email": "Email",
11 | "component.login.form.forgotPassword": "Forgot your password?",
12 | "component.login.form.password": "Password",
13 | "component.login.form.button": "Log in",
14 | "component.login.form.signUp": "Sign up",
15 | "component.login.form.title": "Log in to Cloudflare",
16 | "component.login.cloudflare.description": "Cloudflare makes more than 2,000,000 web properties faster and safer. Join today!",
17 | "component.marketingFeature.cdn.title": "CDN",
18 | "component.marketingFeature.cdn.description": "Distribute your content around the world so it’s closer to your visitors (speeding up your site).",
19 | "component.marketingFeature.optimization.title": "Optimization",
20 | "component.marketingFeature.optimization.description": "Web pages with ad servers and third party widgets load snappy on both mobile and computers.",
21 | "component.marketingFeature.security.title": "Security",
22 | "component.marketingFeature.security.description": "Protect your website from online threats with our enterprise-grade Website Application Firewall (WAF).",
23 | "component.marketingFeature.ddos.title": "DDoS Protection",
24 | "component.marketingFeature.ddos.description": "Ensure your website is protected against DDoS attacks using our advanced service.",
25 | "container.activeZoneSelector.activeZone": "Active Zone",
26 | "container.activationCheckCard.button": "Recheck Nameservers",
27 | "container.activationCheckCard.description": "Allow up to 24 hours for this change to be processed. There will be no downtime when you switch your name servers. Traffic will gracefully roll from your old name servers to the new name servers without interruption. Your site will remain available throughout the switch",
28 | "container.activationCheckCard.nameServers": "Please ensure your website is using the nameservers provided:",
29 | "container.activationCheckCard.title": "Activation Check",
30 | "container.activationCheckCard.status": "Status: {status}",
31 | "container.activationCheckCard.success": "Your domain is now queued up to be rescanned. Please check back in a few hours.",
32 | "container.advanceddos.title": "Advance DDoS",
33 | "container.advanceddos.description": "Cloudflare will stand in front of your website regardless of attack size or duration.",
34 | "container.advanceddos.value": "Visit Cloudflare.com",
35 | "container.alwaysOnlineCard.title": "Always Online™",
36 | "container.alwaysOnlineCard.description": "If your server goes down, Cloudflare will serve your website's static pages from our cache.",
37 | "containers.analyticsPage.cached": "Cached",
38 | "containers.analyticsPage.uncached": "Uncached",
39 | "containers.analyticsPage.threats": "Threats",
40 | "containers.analyticsPage.uniques": "Unique Visitors",
41 | "container.analyticsPage.tabs.requests": "Requests",
42 | "container.analyticsPage.tabs.requests.title": "Request Through Cloudflare",
43 | "container.analyticsPage.tabs.requests.total": "Total Requests",
44 | "container.analyticsPage.tabs.requests.cached": "Total Requests",
45 | "container.analyticsPage.tabs.requests.uncached": "Total Requests",
46 | "container.analyticsPage.tabs.bandwidth": "Bandwidth",
47 | "container.analyticsPage.tabs.bandwidth.title": "Bandwidth",
48 | "container.analyticsPage.tabs.bandwidth.total": "Total Bandwidth",
49 | "container.analyticsPage.tabs.bandwidth.cached": "Cached Bandwidth",
50 | "container.analyticsPage.tabs.bandwidth.uncached": "Uncached Bandwidth",
51 | "container.analyticsPage.tabs.uniques": "Unique Visitors",
52 | "container.analyticsPage.tabs.uniques.title": "Unique Visitors",
53 | "container.analyticsPage.tabs.uniques.total": "Total Unique Visitors",
54 | "container.analyticsPage.tabs.uniques.maximum": "Maximum Unique Visitors",
55 | "container.analyticsPage.tabs.uniques.minimum": "Minimum Unique Visitors",
56 | "container.analyticsPage.tabs.threats": "Threats",
57 | "container.analyticsPage.tabs.threats.title": "Threats",
58 | "container.analyticsPage.tabs.threats.total": "Total Threats",
59 | "container.analyticsPage.tabs.threats.country": "Top Country",
60 | "container.analyticsPage.tabs.threats.type": "Top Threat Type",
61 | "container.analyticsPage.title": "Analytics",
62 | "container.analyticCard.duration": "Last Month",
63 | "container.analyticCard.bandwidth.title": "Bandwidth Saved",
64 | "container.analyticCard.bandwidth.datatype": "Bandwidth",
65 | "container.analyticCard.bandwidth.firstText": "saved",
66 | "container.analyticCard.bandwidth.secondText": "total bandwidth",
67 | "container.analyticCard.ssl.title": "Traffic Served Over SSL",
68 | "container.analyticCard.ssl.datatype": "SSL",
69 | "container.analyticCard.ssl.firstText": "SSL secured request",
70 | "container.analyticCard.ssl.secondText": "unsecured requests",
71 | "container.App.version": "Version: {version}",
72 | "container.applydefaultsettingscard.title": "Apply Default Settings",
73 | "container.applydefaultsettingscard.description": "Apply Cloudflare recommended settings to ensure optimal site performance.",
74 | "container.applydefaultsettingscard.button": "Apply",
75 | "container.applydefaultsettingscard.success": "Your default settings have been successfully set.",
76 | "container.appNavigation.home": "Home",
77 | "container.appNavigation.moresettings": "Settings",
78 | "container.appNavigation.domainsOverview": "Domains",
79 | "container.appNavigation.analytics": "Analytics",
80 | "container.appNavigation.performance": "Performance",
81 | "container.appNavigation.security": "Security",
82 | "container.appNavigation.support": "Support",
83 | "container.browserCacheTTLCard.description": "Determine the length of time Cloudflare instructs a visitor's browser to cache files. During this period, the browser loads the files from its local cache, speeding up page loads.",
84 | "container.browserCacheTTLCard.title": "Browser Cache Expiration",
85 | "container.browserIntegrityCheckCard.description": "Evaluate HTTP headers from your visitors browser for threats. If a threat is found a block page will be delivered.",
86 | "container.browserIntegrityCheckCard.title": "Browser Integrity Check",
87 | "container.browserIntegrityCheckCard.twoHours": "2 hours",
88 | "container.browserIntegrityCheckCard.threeHours": "3 hours",
89 | "container.browserIntegrityCheckCard.fourHours": "4 hours",
90 | "container.browserIntegrityCheckCard.fiveHours": "5 hours",
91 | "container.browserIntegrityCheckCard.eightHours": "8 hours",
92 | "container.browserIntegrityCheckCard.twelveHours": "12 hours",
93 | "container.browserIntegrityCheckCard.sixteenHours": "16 hours",
94 | "container.browserIntegrityCheckCard.twentyHours": "20 hours",
95 | "container.browserIntegrityCheckCard.oneDay": "1 day",
96 | "container.browserIntegrityCheckCard.twoDays": "2 days",
97 | "container.browserIntegrityCheckCard.threeDays": "3 days",
98 | "container.browserIntegrityCheckCard.fourDays": "4 days",
99 | "container.browserIntegrityCheckCard.fiveDays": "5 days",
100 | "container.browserIntegrityCheckCard.eightDays": "8 days",
101 | "container.browserIntegrityCheckCard.sixteenDays": "16 days",
102 | "container.browserIntegrityCheckCard.twentyFourDays": "24 days",
103 | "container.browserIntegrityCheckCard.oneMonth": "1 month",
104 | "container.browserIntegrityCheckCard.twoMonths": "2 months",
105 | "container.browserIntegrityCheckCard.sixMonths": "6 months",
106 | "container.browserIntegrityCheckCard.oneYear": "1 year",
107 | "container.bypassCacheByCookieCard.title": "Cache HTML at CDN",
108 | "container.bypassCacheByCookieCard.description": "Bypass Cache By Cookie allows caching static content such as HTML improving performance of the website.",
109 | "container.bypassCacheByCookieCard.button": "Learn More",
110 | "container.cacheLevelCard.title": "Caching Level",
111 | "container.cacheLevelCard.description": "Determine how much of your website's static content you want Cloudflare to cache. Increased caching can speed up page load time.",
112 | "container.cacheLevelCard.simplified": "No Query String",
113 | "container.cacheLevelCard.basic": "Ignore Query String",
114 | "container.cacheLevelCard.aggressive": "Standard",
115 | "container.challengePassageCard.description": "Specify how long a visitor is allowed access to your website after completing a challenge.",
116 | "container.challengePassageCard.select.fiveMinutes": "5 Minutes",
117 | "container.challengePassageCard.select.fifteenMinutes": "15 Minutes",
118 | "container.challengePassageCard.select.thirtyMinutes": "30 Minutes",
119 | "container.challengePassageCard.select.fortyFiveMinutes": "45 Minutes",
120 | "container.challengePassageCard.select.oneHour": "1 Hour",
121 | "container.challengePassageCard.select.twoHours": "2 Hours",
122 | "container.challengePassageCard.select.threeHours": "3 Hours",
123 | "container.challengePassageCard.select.fourHours": "4 Hours",
124 | "container.challengePassageCard.select.eightHours": "8 Hours",
125 | "container.challengePassageCard.select.sixteenHours": "16 Hours",
126 | "container.challengePassageCard.select.oneDay": "1 Day",
127 | "container.challengePassageCard.select.oneWeek": "1 Week",
128 | "container.challengePassageCard.select.oneMonth": "1 Month",
129 | "container.challengePassageCard.select.oneYear": "1 Year",
130 | "container.challengePassageCard.title": "Challenge Passage",
131 | "container.developmentModeCard.title": "Development Mode",
132 | "container.developmentModeCard.description": "Temporarily bypass our cache allowing you to see changes to your origin server in realtime.",
133 | "container.dnsManagementPage.thead.domain": "Domain",
134 | "container.dnsManagementPage.thead.cloudflarePlan": "Cloudflare Plan",
135 | "container.dnsManagementPage.thead.zoneType": "Zone Type",
136 | "container.dnsManagementPage.thead.status": "Use Cloudflare",
137 | "container.dnsManagementPage.title": "Domain Overview",
138 | "container.dnsRecordEditor.thead.type": "Type",
139 | "container.dnsRecordEditor.thead.name": "Name",
140 | "container.dnsRecordEditor.thead.value": "Value",
141 | "container.dnsRecordEditor.thead.ttl": "TTL",
142 | "container.dnsRecordEditor.thead.status": "Use Cloudflare",
143 | "container.dnsManagementPage.thead.changePlan": "Change",
144 | "container.ipv6Card.title": "IPv6 Compatibility",
145 | "container.ipv6Card.description": "Enable IPv6 support and gateway.",
146 | "container.homePage.title": "Home",
147 | "container.minifyCard.title": "Auto Minify",
148 | "container.minifyCard.description": "Reduce the file size of source code on your website.",
149 | "container.minifyCard.css": "CSS",
150 | "container.minifyCard.html": "HTML",
151 | "container.minifyCard.javascript": "JavaScript",
152 | "container.moresettings.performance": "Performance",
153 | "container.moresettings.speed": "Speed",
154 | "container.moresettings.security": "Security",
155 | "container.pluginSpecificCacheCard.title": "Automatic Cache Management",
156 | "container.pluginSpecificCacheCard.description": "Purge Cloudflare cache automatically when you update the appearance of your site.",
157 | "container.pluginSpecificCacheCard.modal.title": "Confirm Enabling Automatic Cache",
158 | "container.pluginSpecificCacheCard.modal.description": "Enabling this feature will automatically trigger a full cache purge when you update the appearance of your site.",
159 | "container.pluginSpecificCacheCard.modal.button": "I'm sure",
160 | "container.pluginSpecificCacheCard.modal.buttonCancel": "Cancel",
161 | "container.pluginSpecificCacheTagCard.title": "Automatically Purge Cache When Site Content is Updated",
162 | "container.pluginSpecificCacheTagCard.description": "Enable to automatically purge the cache when your site content changes.",
163 | "container.automatichttprewrites.title": "Automatic HTTPS Rewrites",
164 | "container.automatichttprewrites.description": "Automatic HTTPS Rewrites helps fix mixed content by changing \"http\" to \"https\" for all resources or links on your web site that can be served with HTTPS.",
165 | "container.purgeCacheCard.dropdown": "Purge Cache",
166 | "container.purgeCacheCard.button": "Purge Everything",
167 | "container.purgeCacheCard.title": "Purge Cache",
168 | "container.purgeCacheCard.description": "Clear cached files to force Cloudflare to fetch a fresh version of those files from your web server.",
169 | "container.purgeCacheCard.success": "Cache was successfully purged.",
170 | "container.purgeCacheCard.modal.title" : "Confirm Purge All",
171 | "container.purgeCacheCard.modal.description": "Note: Purging your cache may slow your website temporarily.",
172 | "container.purgeCacheCard.modal.buttonCancel": "Cancel",
173 | "container.purgeCacheByURLCard.button": "Purge Individual Files",
174 | "container.purgeCacheByURLCard.success": "Successfully purged all assets. Please allow up to 30 seconds for changes to take effect.",
175 | "container.purgeCacheByURLCard.modal.title" : "Confirm Individual Files",
176 | "container.purgeCacheByURLCard.modal.description": "You can purge up to 30 files at a time. Note: Wildcards are not supported with single file purge at this time. You will need to specify the full path to the file. Separate URL(s) with spaces, or list one per line",
177 | "container.purgeCacheByURLCard.modal.buttonCancel": "Cancel",
178 | "container.railgunCard.title":"Railgun™",
179 | "container.railgunCard.description":"Accelerate delivery of dynamic content. Note: Requires software installation at your host.",
180 | "container.railgunCard.table.name":"Name",
181 | "container.railgunCard.table.railgunState":"Railgun State",
182 | "container.railgunCard.table.connectedToWebsite":"Connected to Website",
183 | "container.railgunCard.table.active": "Active",
184 | "container.railgunCard.table.inactive": "Inactive",
185 | "container.railgunCard.noRailgunsAvailable": "No Railguns are currently configured from your hosting provider for {zoneName}.",
186 | "container.signup.error.emailBlank": "Your Email address cannot be blank.",
187 | "container.signup.error.passwordBlank": "Your password can not be blank.",
188 | "container.signup.error.passwordsDontMatch": "The passwords you entered do not match.",
189 | "container.signup.error.termsOfService": "Please agree to the Terms of Service and Privacy Policy before proceeding.",
190 | "container.signup.form.title": "Sign Up for Cloudflare",
191 | "container.signup.form.email": "Email",
192 | "container.signup.form.password": "Password",
193 | "container.signup.form.passwordAgain": "Password (again)",
194 | "container.signup.form.button": "Sign Up for Cloudflare",
195 | "container.signup.form.termsAndConditions.iAgreeTo": "I agree to ",
196 | "container.signup.form.termsAndConditions.cloudFlaresTermsAndConditions": " Cloudflare's terms and conditions",
197 | "container.signup.form.termsAndConditions.and": "and",
198 | "container.signup.form.termsAndConditions.privacyPolicy": "privacy policy",
199 | "container.signup.form.termsAndConditions.period": ".",
200 | "container.securityLevelCard.description": "Adjust your website's Security Level to determine which visitors will receive a challenge page.",
201 | "container.securityLevelCard.select.essentiallyOff": "Essentially Off",
202 | "container.securityLevelCard.select.low": "Low",
203 | "container.securityLevelCard.select.medium": "Medium",
204 | "container.securityLevelCard.select.high": "High",
205 | "container.securityLevelCard.select.underAttack": "Under Attack",
206 | "container.securityLevelCard.title": "Security Level",
207 | "container.sslCard.description": "Encrypt communication to and from your website using SSL.",
208 | "container.sslCard.select.off": "Off",
209 | "container.sslCard.select.flexible": "Flexible",
210 | "container.sslCard.select.full": "Full",
211 | "container.sslCard.select.full_strict": "Full Strict",
212 | "container.sslCard.title": "SSL",
213 | "container.underAttackButton.description": "Is your website currently being attacked?",
214 | "container.underAttackButton.turnOff": "Enable \"I'm Under Attack\" Mode",
215 | "container.underAttackButton.turnOn": "Disable \"I'm Under Attack\" Mode",
216 | "container.zoneProvision.button.full": "Provision Domain with Full Zone Setup",
217 | "container.zoneProvision.button.cname": "Provision Domain with CNAME Setup",
218 | "container.zoneProvision.button.deprovision": "Remove domain from Cloudflare",
219 | "container.zoneProvision.provisionDifference": "What is the difference between Full and Cname provisioning?",
220 | "container.zoneProvision.title": "Provision Domain",
221 | "container.zoneProvision.modal.title": "Delete Website",
222 | "container.zoneProvision.modal.description": "Are you sure you want to delete {zoneName}? To temporarily disable Cloudflare service and save your website settings, pause your website instead.",
223 | "container.zoneProvision.modal.buttonCancel": "Cancel",
224 | "container.ipRewrite.title": "IP Rewrite",
225 | "container.ipRewrite.description": "Rewrite Cloudflare IP Addresses for actual end-user IP Addresses at the application layer.",
226 | "container.imageOptimization.title": "Image Optimization",
227 | "container.imageOptimization.description": "Improve image load time and for pages that include images on mobile devices with slow network connections",
228 | "container.waf.title": "Web Application Firewall",
229 | "container.waf.description": "Set rules to protect your website from web vulnerabilities.",
230 | "constants.plans.pro": "Pro plan",
231 | "constants.plans.biz": "Business plan",
232 | "constants.plans.ent": "Enterprise plan",
233 | "errors.noActiveZoneSelected": "Please select a domain that is provisioned with Cloudflare.",
234 | "warning.usingSubdomain": "You are using a subdomain for your site, but any Cloudflare settings applied via this plugin will be applied to your original domain as well.",
235 | "warning.developmentmode": "Development mode enabled, all traffic will bypass the Cloudflare cache.",
236 | "utils.utils.lastmodifieddate": "This settings was last changed {date}"
237 | }
238 |
--------------------------------------------------------------------------------