<?php
/**
 * Fastly CDN for Magento
 *
 * NOTICE OF LICENSE
 *
 * This source file is subject to the Fastly CDN for Magento End User License Agreement
 * that is bundled with this package in the file LICENSE_FASTLY_CDN.txt.
 *
 * DISCLAIMER
 *
 * Do not edit or add to this file if you wish to upgrade Fastly CDN to newer
 * versions in the future. If you wish to customize this module for your
 * needs please refer to http://www.magento.com for more information.
 *
 * @category    Fastly
 * @package     Fastly_Cdn
 * @copyright   Copyright (c) 2016 Fastly, Inc. (http://www.fastly.com)
 * @license     BSD, see LICENSE_FASTLY_CDN.txt
 */
namespace Fastly\Cdn\Setup;

use Fastly\Cdn\Helper\Data;
use Magento\Framework\App\Cache\Manager;
use Magento\Framework\App\Config\ScopeConfigInterface;
use Magento\Framework\App\Config\Storage\WriterInterface;
use Magento\Framework\App\ProductMetadataInterface;
use Magento\Framework\Exception\LocalizedException;
use Magento\Framework\Setup\UpgradeDataInterface;
use Magento\Framework\Setup\ModuleContextInterface;
use Magento\Framework\Setup\ModuleDataSetupInterface;
use Fastly\Cdn\Model\Statistic;
use Magento\Framework\Stdlib\DateTime\DateTime;

/**
 * Class UpgradeData
 *
 * @package Fastly\Cdn\Setup
 */
class UpgradeData implements UpgradeDataInterface
{

    /**
     * @var DateTime
     */
    private $date;
    /**
     * @var ScopeConfigInterface
     */
    private $scopeConfig;
    /**
     * @var WriterInterface
     */
    private $configWriter;
    /**
     * @var Statistic
     */
    private $statistic;
    /**
     * @var Manager
     */
    private $cacheManager;
    /**
     * @var Data
     */
    private $helper;
    /**
     * @var ProductMetadataInterface
     */
    private $productMetadata;

    /**
     * UpgradeData constructor.
     * @param ScopeConfigInterface $scopeConfig
     * @param WriterInterface $configWriter
     * @param Statistic $statistic
     * @param DateTime $date
     * @param Manager $cacheManager
     * @param Data $helper
     * @param ProductMetadataInterface $productMetadata
     */
    public function __construct(
        ScopeConfigInterface $scopeConfig,
        WriterInterface $configWriter,
        Statistic $statistic,
        DateTime $date,
        Manager $cacheManager,
        Data $helper,
        ProductMetadataInterface $productMetadata
    ) {
        $this->date = $date;
        $this->scopeConfig = $scopeConfig;
        $this->configWriter = $configWriter;
        $this->statistic = $statistic;
        $this->helper = $helper;
        $this->productMetadata = $productMetadata;
        $this->cacheManager = $cacheManager;
    }

    /**
     * If old configuration values exist, they're fetched and saved to new config paths.
     * This script will only execute on module version <= 1.0.8
     *
     *
     * @param ModuleDataSetupInterface $setup
     * @param ModuleContextInterface $context*
     */
    public function upgrade(ModuleDataSetupInterface $setup, ModuleContextInterface $context)
    {
        $version = $context->getVersion();

        if (!$version) {
            return;
        }

        $oldConfigPaths = [
            'stale_ttl'                 => 'system/full_page_cache/fastly/stale_ttl',
            'stale_error_ttl'           => 'system/full_page_cache/fastly/stale_error_ttl',
            'purge_catalog_category'    => 'system/full_page_cache/fastly/purge_catalog_category',
            'purge_catalog_product'     => 'system/full_page_cache/fastly/purge_catalog_product',
            'purge_cms_page'            => 'system/full_page_cache/fastly/purge_cms_page',
            'soft_purge'                => 'system/full_page_cache/fastly/soft_purge',
            'enable_geoip'              => 'system/full_page_cache/fastly/enable_geoip',
            'geoip_action'              => 'system/full_page_cache/fastly/geoip_action',
            'geoip_country_mapping'     => 'system/full_page_cache/fastly/geoip_country_mapping',
        ];

        $newConfigPaths = [
            'stale_ttl'
                => 'system/full_page_cache/fastly/fastly_advanced_configuration/stale_ttl',
            'stale_error_ttl'
                => 'system/full_page_cache/fastly/fastly_advanced_configuration/stale_error_ttl',
            'purge_catalog_category'
                => 'system/full_page_cache/fastly/fastly_advanced_configuration/purge_catalog_category',
            'purge_catalog_product'
                => 'system/full_page_cache/fastly/fastly_advanced_configuration/purge_catalog_product',
            'purge_cms_page'
                => 'system/full_page_cache/fastly/fastly_advanced_configuration/purge_cms_page',
            'soft_purge'
                => 'system/full_page_cache/fastly/fastly_advanced_configuration/soft_purge',
            'enable_geoip'
                => 'system/full_page_cache/fastly/fastly_advanced_configuration/enable_geoip',
            'geoip_action'
                => 'system/full_page_cache/fastly/fastly_advanced_configuration/geoip_action',
            'geoip_country_mapping'
                => 'system/full_page_cache/fastly/fastly_advanced_configuration/geoip_country_mapping'
        ];

        $setup->startSetup();

        if (version_compare($version, '1.0.8', '<=')) {
            $this->upgrade108($oldConfigPaths, $newConfigPaths);
        }

        if (version_compare($version, '1.0.9', '<=')) {
            $this->upgrade109($setup);
        }

        // If Magento is upgraded later,
        // use bin/magento fastly:format:serializetojson OR /bin/magento fastly:format:jsontoserialize to adjust format
        $magVer = $this->productMetadata->getVersion();
        if (version_compare($version, '1.0.10', '<=') && version_compare($magVer, '2.2', '>=')) {
            $this->upgrade1010($newConfigPaths);
            $setup->endSetup();
        } elseif (version_compare($magVer, '2.2', '<')) {
            $setup->endSetup();
        }
    }

    /**
     * Config path changes
     * @param $oldConfigPaths
     * @param $newConfigPaths
     */
    private function upgrade108($oldConfigPaths, $newConfigPaths)
    {
        foreach ($oldConfigPaths as $key => $value) {
            $oldValue = $this->scopeConfig->getValue($value);
            if ($oldValue != null) {
                $this->configWriter->save($newConfigPaths[$key], $oldValue); // @codingStandardsIgnoreLine - currently best way to resolve this
            }
        }
    }

    /**
     * GA changes
     * @param ModuleDataSetupInterface $setup
     */
    private function upgrade109(ModuleDataSetupInterface $setup)
    {
        $tableName = $setup->getTable('fastly_statistics');
        if ($setup->getConnection()->isTableExists($tableName) == true) {
            $data = [
                'action' => Statistic::FASTLY_INSTALLED_FLAG,
                'created_at' => $this->date->date()
            ];

            $setup->getConnection()->insert($tableName, $data); // @codingStandardsIgnoreLine - currently best way to resolve this
        }

        // Save current Fastly module version
        $this->configWriter->save(
            'system/full_page_cache/fastly/current_version',
            $this->helper->getModuleVersion()
        );

        // Generate GA cid and store it for further use
        $this->configWriter->save(
            'system/full_page_cache/fastly/fastly_ga_cid',
            $this->statistic->generateCid()
        );
        $this->cacheManager->clean([\Magento\Framework\App\Cache\Type\Config::TYPE_IDENTIFIER]);
        $setup->endSetup();
    }

    /**
     * Convert serialized data to magento supported serialized data
     * @param $newConfigPaths
     */
    private function upgrade1010($newConfigPaths)
    {
        $oldData = $this->scopeConfig->getValue($newConfigPaths['geoip_country_mapping']);
        try {
            $oldData = unserialize($oldData); // @codingStandardsIgnoreLine - used for conversion of old Magento format to json_decode
        } catch (\Exception $e) {
            $oldData = [];
        }
        $oldData = (is_array($oldData)) ? $oldData : [];
        $newData = json_encode($oldData);
        if (false === $newData) {
            throw new \InvalidArgumentException('Unable to encode data.');
        }
        $this->configWriter->save($newConfigPaths['geoip_country_mapping'], $newData);
        $this->cacheManager->clean([\Magento\Framework\App\Cache\Type\Config::TYPE_IDENTIFIER]);
    }
}


<?php

namespace Fastly\Cdn\Controller\Adminhtml\FastlyCdn\Manifest;

use Magento\Backend\App\Action;
use Magento\Backend\App\Action\Context;
use Magento\Framework\App\Request\Http;
use Magento\Framework\App\ResponseInterface;
use Magento\Framework\Controller\Result\JsonFactory;
use Magento\Framework\Controller\ResultInterface;
use Fastly\Cdn\Model\Modly\Manifest;

/**
 * Class GetCustomSnippets
 *
 * @package Fastly\Cdn\Controller\Adminhtml\FastlyCdn\Vcl
 */
class GetAllModules extends Action
{
    /**
     * @var Http
     */
    private $request;

    /**
     * @var JsonFactory
     */
    private $resultJson;

    /**
     * @var Manifest
     */
    private $manifest;

    /**
     * GetAllModules constructor.
     *
     * @param Context $context
     * @param Http $request
     * @param JsonFactory $resultJsonFactory
     * @param Manifest $manifest
     */
    public function __construct(
        Context $context,
        Http $request,
        JsonFactory $resultJsonFactory,
        Manifest $manifest
    ) {
        $this->request = $request;
        $this->resultJson = $resultJsonFactory;
        $this->manifest = $manifest;
        parent::__construct($context);
    }

    /**
     * Get a list of all modules
     *
     * @return $this|ResponseInterface|ResultInterface
     */
    public function execute()
    {
        $result = $this->resultJson->create();
        try {
            $modules = $this->manifest->getAllModlyManifests();

            if (!$modules) {
                return $result->setData([
                    'status'    => false,
                    'modules'   => '',
                    'msg'       => 'Use the Refresh button to get the latest modules.'
                ]);
            }

            return $result->setData([
                'status'    => true,
                'modules'  => $modules
            ]);
        } catch (\Exception $e) {
            return $result->setData([
                'status'    => false,
                'msg'       => $e->getMessage()
            ]);
        }
    }
}


<?php
/**
 * Fastly CDN for Magento
 *
 * NOTICE OF LICENSE
 *
 * This source file is subject to the Fastly CDN for Magento End User License Agreement
 * that is bundled with this package in the file LICENSE_FASTLY_CDN.txt.
 *
 * DISCLAIMER
 *
 * Do not edit or add to this file if you wish to upgrade Fastly CDN to newer
 * versions in the future. If you wish to customize this module for your
 * needs please refer to http://www.magento.com for more information.
 *
 * @category    Fastly
 * @package     Fastly_Cdn
 * @copyright   Copyright (c) 2016 Fastly, Inc. (http://www.fastly.com)
 * @license     BSD, see LICENSE_FASTLY_CDN.txt
 */
namespace Fastly\Cdn\Model\Config\Backend;

use Magento\Config\Model\Config\Backend\File;
use Magento\Framework\App\Filesystem\DirectoryList;

class CustomSnippetUpload extends File
{
    /**
     * @return string[]
     */
    public function getAllowedExtensions()
    {
        return ['vcl'];
    }

    /**
     * Save uploaded file before saving config value
     *
     * @return $this
     * @throws \Magento\Framework\Exception\LocalizedException
     */
    public function beforeSave()
    {
        $value = $this->getValue();
        $file = $this->getFileData();
        if (!empty($file)) {
            $uploadDir = $this->_getUploadDir();
            try {
                $uploader = $this->_uploaderFactory->create(['fileId' => $file]);
                $uploader->setAllowedExtensions($this->getAllowedExtensions());
                $uploader->setAllowRenameFiles(true);
                $uploader->addValidateCallback('size', $this, 'validateMaxSize');
                $result = $uploader->save($uploadDir);
            } catch (\Exception $e) {
                throw new \Magento\Framework\Exception\LocalizedException(__('%1', $e->getMessage()));
            }

            $filename = $result['file'];
            if ($filename) {
                if ($this->_addWhetherScopeInfo()) {
                    $filename = $this->_prependScopeInfo($filename);
                }
                $this->setValue($filename);
            }
        } else {
            if (is_array($value) && !empty($value['delete'])) {
                $this->setValue('');
            } elseif (is_array($value) && !empty($value['value'])) {
                $this->setValue($value['value']);
            } else {
                $this->unsValue();
            }
        }

        return $this;
    }

    public function _getUploadDir()
    {
        $fieldConfig = $this->getFieldConfig();

        if (!array_key_exists('upload_dir', $fieldConfig)) {
            throw new \Magento\Framework\Exception\LocalizedException(
                __('The base directory to upload file is not specified.')
            );
        }

        if (is_array($fieldConfig['upload_dir'])) {
            $uploadDir = $fieldConfig['upload_dir']['value'];
            if (array_key_exists('scope_info', $fieldConfig['upload_dir'])
                && $fieldConfig['upload_dir']['scope_info']
            ) {
                $uploadDir = $this->_appendScopeInfo($uploadDir);
            }

            if (array_key_exists('config', $fieldConfig['upload_dir'])) {
                $uploadDir = $this->getUploadDirPath($uploadDir);
            }
        } else {
            $uploadDir = (string)$fieldConfig['upload_dir'];
        }

        return $uploadDir;
    }

    public function getUploadDirPath($uploadDir)
    {
        $varDirectory = $this->_filesystem->getDirectoryWrite(DirectoryList::VAR_DIR);
        return $varDirectory->getAbsolutePath($uploadDir);
    }
}


<?php
/**
 * Fastly CDN for Magento
 *
 * NOTICE OF LICENSE
 *
 * This source file is subject to the Fastly CDN for Magento End User License Agreement
 * that is bundled with this package in the file LICENSE_FASTLY_CDN.txt.
 *
 * DISCLAIMER
 *
 * Do not edit or add to this file if you wish to upgrade Fastly CDN to newer
 * versions in the future. If you wish to customize this module for your
 * needs please refer to http://www.magento.com for more information.
 *
 * @category    Fastly
 * @package     Fastly_Cdn
 * @copyright   Copyright (c) 2016 Fastly, Inc. (http://www.fastly.com)
 * @license     BSD, see LICENSE_FASTLY_CDN.txt
 */
namespace Fastly\Cdn\Block\Cache;

use Fastly\Cdn\Model\Config;
use Magento\Backend\Block\Template;
use Magento\Backend\Block\Template\Context;

/**
 * Class Additional
 *
 * @package Fastly\Cdn\Block\Cache
 */
class Additional extends Template
{
    const CONTENT_TYPE_HTML    = 'text';
    const CONTENT_TYPE_CSS     = 'css';
    const CONTENT_TYPE_JS      = 'script';
    const CONTENT_TYPE_IMAGE   = 'image';

    /**
     * @var Config
     */
    private $config;

    /**
     * Additional constructor.
     *
     * @param \Magento\Backend\Block\Template\Context $context
     * @param Config $config
     * @param array $data
     */
    public function __construct(
        Context $context,
        Config $config,
        array $data = []
    ) {
        $this->config = $config;

        parent::__construct($context, $data);
    }

    /**
     * Check if block can be displayed
     *
     * @return bool
     */
    public function canShowBlock()
    {
        if ($this->config->getType() == Config::FASTLY && $this->config->isEnabled()) {
            return true;
        }
        return false;
    }

    /**
     * Get clean by content type url
     *
     * @return string
     */
    public function getCleanByContentTypeUrl()
    {
        return $this->getUrl('*/fastlyCdn_purge/contentType');
    }

    /**
     * Get quick purge url
     *
     * @return string
     */
    public function getQuickPurgeUrl()
    {
        return $this->getUrl('*/fastlyCdn_purge/quick');
    }

    /**
     * Get purge all url
     *
     * @return string
     */
    public function getPurgeAllUrl()
    {
        return $this->getUrl('*/fastlyCdn_purge/all');
    }

    /**
     * Get clean by source url
     *
     * @return string
     */
    public function getCleanByStoreUrl()
    {
        return $this->getUrl('*/fastlyCdn_purge/store');
    }

    /**
     * Get store options
     *
     * @return array
     */
    public function getStoreOptions()
    {
        return $this->_storeManager->getStores();
    }

    /**
     * Get content types as option array
     *
     * @return array
     */
    public function getContentTypeOptions()
    {
        $contentTypes = [
            self::CONTENT_TYPE_HTML  => __('HTML'),
            self::CONTENT_TYPE_CSS   => __('CSS'),
            self::CONTENT_TYPE_JS    => __('JavaScript'),
            self::CONTENT_TYPE_IMAGE => __('Images')
        ];
        return $contentTypes;
    }
}


<?php
/**
 * Fastly CDN for Magento
 *
 * NOTICE OF LICENSE
 *
 * This source file is subject to the Fastly CDN for Magento End User License Agreement
 * that is bundled with this package in the file LICENSE_FASTLY_CDN.txt.
 *
 * DISCLAIMER
 *
 * Do not edit or add to this file if you wish to upgrade Fastly CDN to newer
 * versions in the future. If you wish to customize this module for your
 * needs please refer to http://www.magento.com for more information.
 *
 * @category    Fastly
 * @package     Fastly_Cdn
 * @copyright   Copyright (c) 2016 Fastly, Inc. (http://www.fastly.com)
 * @license     BSD, see LICENSE_FASTLY_CDN.txt
 */
namespace Fastly\Cdn\Controller\Adminhtml\FastlyCdn\Edge\Acl;

use Magento\Backend\App\Action;
use Magento\Backend\App\Action\Context;
use Magento\Framework\App\Request\Http;
use Magento\Framework\Controller\Result\JsonFactory;
use Fastly\Cdn\Model\Config;
use Fastly\Cdn\Model\Api;
use Fastly\Cdn\Helper\Vcl;

/**
 * Class Create
 *
 * @package Fastly\Cdn\Controller\Adminhtml\FastlyCdn\Edge\Acl
 */
class Create extends Action
{
    /**
     * @var Http
     */
    private $request;
    /**
     * @var JsonFactory
     */
    private $resultJson;
    /**
     * @var Config
     */
    private $config;
    /**
     * @var Api
     */
    private $api;
    /**
     * @var Vcl
     */
    private $vcl;

    /**
     * ForceTls constructor.
     *
     * @param Context $context
     * @param Http $request
     * @param JsonFactory $resultJsonFactory
     * @param Config $config
     * @param Api $api
     * @param Vcl $vcl
     */
    public function __construct(
        Context $context,
        Http $request,
        JsonFactory $resultJsonFactory,
        Config $config,
        Api $api,
        Vcl $vcl
    ) {
        $this->request = $request;
        $this->resultJson = $resultJsonFactory;
        $this->config = $config;
        $this->api = $api;
        $this->vcl = $vcl;

        parent::__construct($context);
    }

    /**
     * Create ACL
     *
     * @return $this|\Magento\Framework\App\ResponseInterface|\Magento\Framework\Controller\ResultInterface
     */
    public function execute()
    {
        $result = $this->resultJson->create();

        try {
            $activeVersion = $this->getRequest()->getParam('active_version');
            $activateVcl = $this->getRequest()->getParam('activate_flag');
            $aclName = $this->getRequest()->getParam('acl_name');
            $service = $this->api->checkServiceDetails();
            $this->vcl->checkCurrentVersionActive($service->versions, $activeVersion);
            $currActiveVersion = $this->vcl->getCurrentVersion($service->versions);
            $clone = $this->api->cloneVersion($currActiveVersion);

            $params = ['name' => $aclName];
            $createAcl = $this->api->createAcl($clone->number, $params);

            if (!$createAcl) {
                return $result->setData([
                    'status'    => false,
                    'msg'       => 'Failed to create Acl container.'
                ]);
            }

            $this->api->validateServiceVersion($clone->number);

            if ($activateVcl === 'true') {
                $this->api->activateVersion($clone->number);
            }

            $comment = ['comment' => 'Magento Module created the "'.$aclName.'" ACL'];
            $this->api->addComment($clone->number, $comment);

            return $result->setData([
                'status'            => true,
                'active_version'    => $clone->number
            ]);
        } catch (\Exception $e) {
            return $result->setData([
                'status'    => false,
                'msg'       => $e->getMessage()
            ]);
        }
    }
}


<?php
/**
 * Fastly CDN for Magento
 *
 * NOTICE OF LICENSE
 *
 * This source file is subject to the Fastly CDN for Magento End User License Agreement
 * that is bundled with this package in the file LICENSE_FASTLY_CDN.txt.
 *
 * DISCLAIMER
 *
 * Do not edit or add to this file if you wish to upgrade Fastly CDN to newer
 * versions in the future. If you wish to customize this module for your
 * needs please refer to http://www.magento.com for more information.
 *
 * @category    Fastly
 * @package     Fastly_Cdn
 * @copyright   Copyright (c) 2016 Fastly, Inc. (http://www.fastly.com)
 * @license     BSD, see LICENSE_FASTLY_CDN.txt
 */
namespace Fastly\Cdn\Controller\Adminhtml\FastlyCdn\BasicAuthentication;

use Fastly\Cdn\Model\Config;
use Fastly\Cdn\Model\Api;
use Magento\Backend\App\Action;
use Magento\Backend\App\Action\Context;
use Magento\Framework\Controller\Result\JsonFactory;

/**
 * Class CheckAuthSetting
 *
 * @package Fastly\Cdn\Controller\Adminhtml\FastlyCdn\BasicAuthentication
 */
class CheckAuthSetting extends Action
{
    /**
     * @var Api
     */
    private $api;
    /**
     * @var Config
     */
    private $config;
    /**
     * @var JsonFactory
     */
    private $resultJsonFactory;

    /**
     * CheckTlsSetting constructor.
     *
     * @param Context $context
     * @param Config $config
     * @param Api $api
     * @param JsonFactory $resultJsonFactory
     */
    public function __construct(
        Context $context,
        Config $config,
        Api $api,
        JsonFactory $resultJsonFactory
    ) {
        $this->api = $api;
        $this->config = $config;
        $this->resultJsonFactory = $resultJsonFactory;

        parent::__construct($context);
    }

    /**
     * Verifies weather or not auth settings snippet exists on specified Fastly version
     *
     * @return \Magento\Framework\Controller\Result\Json
     */
    public function execute()
    {
        $result = $this->resultJsonFactory->create();
        try {
            $activeVersion = $this->getRequest()->getParam('active_version');
            $snippets = $this->config->getVclSnippets(Config::VCL_AUTH_SNIPPET_PATH);

            foreach ($snippets as $key => $value) {
                $name = Config::FASTLY_MAGENTO_MODULE . '_basic_auth_' . $key;
                $status = $this->api->hasSnippet($activeVersion, $name);

                if ($status == false) {
                    return $result->setData([
                        'status' => false
                    ]);
                }
            }

            return $result->setData([
                'status' => true
            ]);
        } catch (\Exception $e) {
            return $result->setData([
                'status'    => false,
                'msg'       => $e->getMessage()
            ]);
        }
    }
}


<?php

namespace Fastly\Cdn\Helper;

use Magento\Framework\App\Helper\AbstractHelper;
use Magento\Framework\App\Helper\Context;
use Fastly\Cdn\Model\ManifestFactory;
use Fastly\Cdn\Model\ResourceModel\Manifest as ManifestResource;
use Fastly\Cdn\Model\ResourceModel\Manifest\Collection;
use Fastly\Cdn\Model\ResourceModel\Manifest\CollectionFactory;

/**
 * Class Manifest
 *
 * @package Fastly\Cdn\Helper
 */
class Manifest extends AbstractHelper
{
    /**
     * @var ManifestFactory
     */
    private $manifestFactory;

    /**
     * @var ManifestResource
     */
    private $manifestResource;

    /**
     * @var Collection
     */
    private $collection;
    /**
     * @var CollectionFactory
     */
    private $collectionFactory;

    /**
     * Manifest constructor.
     *
     * @param Context $context
     * @param ManifestFactory $manifestFactory
     * @param ManifestResource $manifestResource
     * @param Collection $collection
     * @param CollectionFactory $collectionFactory
     */
    public function __construct(
        Context $context,
        ManifestFactory $manifestFactory,
        ManifestResource $manifestResource,
        Collection $collection,
        Collectionfactory $collectionFactory
    ) {
        $this->manifestFactory = $manifestFactory;
        $this->manifestResource = $manifestResource;
        $this->collection = $collection;
        $this->collectionFactory = $collectionFactory;
        parent::__construct($context);
    }

    /**
     * Returns all module data from database
     *
     * @return array
     */
    public function getAllModules()
    {
        $modules = [];
        $moduleCollection = $this->collectionFactory->create()->getData();
        foreach ($moduleCollection as $module) {
            $modules[] = $module;
        }
        return $modules;
    }

    /**
     * Returns active module data from database
     *
     * @return array
     */
    public function getActiveModules()
    {
        $modules = [];
        $moduleCollection = $this->collectionFactory->create()->getData();

        foreach ($moduleCollection as $module) {
            if ($module['manifest_status'] == '1') {
                $modules[] = $module;
            }
        }
        return $modules;
    }

    public function getModuleData($id)
    {
        $moduleData = $this->collectionFactory->create()->getItemById($id);
        return $moduleData;
    }
}


<?php
/**
 * Fastly CDN for Magento
 *
 * NOTICE OF LICENSE
 *
 * This source file is subject to the Fastly CDN for Magento End User License Agreement
 * that is bundled with this package in the file LICENSE_FASTLY_CDN.txt.
 *
 * DISCLAIMER
 *
 * Do not edit or add to this file if you wish to upgrade Fastly CDN to newer
 * versions in the future. If you wish to customize this module for your
 * needs please refer to http://www.magento.com for more information.
 *
 * @category    Fastly
 * @package     Fastly_Cdn
 * @copyright   Copyright (c) 2016 Fastly, Inc. (http://www.fastly.com)
 * @license     BSD, see LICENSE_FASTLY_CDN.txt
 */
namespace Fastly\Cdn\Controller\Adminhtml\FastlyCdn\SyntheticPages;

use Fastly\Cdn\Model\Config;
use Magento\Backend\App\Action;
use Magento\Backend\App\Action\Context;
use Magento\Framework\App\Request\Http;
use Magento\Framework\Controller\Result\JsonFactory;
use Fastly\Cdn\Model\Api;

/**
 * Class GetWafPageRespObj
 *
 * @package Fastly\Cdn\Controller\Adminhtml\FastlyCdn\SyntheticPages
 */
class GetWafPageRespObj extends Action
{
    /**
     * @var Http
     */
    private $request;
    /**
     * @var JsonFactory
     */
    private $resultJson;
    /**
     * @var Api
     */
    private $api;

    /**
     * GetWafPageRespObj constructor.
     * @param Context $context
     * @param Http $request
     * @param JsonFactory $resultJsonFactory
     * @param Api $api
     */
    public function __construct(
        Context $context,
        Http $request,
        JsonFactory $resultJsonFactory,
        Api $api
    ) {
        $this->request = $request;
        $this->resultJson = $resultJsonFactory;
        $this->api = $api;

        parent::__construct($context);
    }

    /**
     * Get the WAF page content
     *
     * @return $this|\Magento\Framework\App\ResponseInterface|\Magento\Framework\Controller\ResultInterface
     */
    public function execute()
    {
        $result = $this->resultJson->create();
        try {
            $activeVersion = $this->getRequest()->getParam('active_version');
            $response = $this->api->getResponse($activeVersion, Config::WAF_PAGE_RESPONSE_OBJECT);

            if (!$response) {
                return $result->setData([
                    'status'    => false,
                    'msg'       => 'Failed to fetch WAF page Response object.'
                ]);
            }

            return $result->setData([
                'status'        => true,
                'wafPageResp'   => $response
            ]);
        } catch (\Exception $e) {
            return $result->setData([
                'status'    => false,
                'msg'       => $e->getMessage()
            ]);
        }
    }
}


<?php
/**
 * Fastly CDN for Magento
 *
 * NOTICE OF LICENSE
 *
 * This source file is subject to the Fastly CDN for Magento End User License Agreement
 * that is bundled with this package in the file LICENSE_FASTLY_CDN.txt.
 *
 * DISCLAIMER
 *
 * Do not edit or add to this file if you wish to upgrade Fastly CDN to newer
 * versions in the future. If you wish to customize this module for your
 * needs please refer to http://www.magento.com for more information.
 *
 * @category    Fastly
 * @package     Fastly_Cdn
 * @copyright   Copyright (c) 2016 Fastly, Inc. (http://www.fastly.com)
 * @license     BSD, see LICENSE_FASTLY_CDN.txt
 */
namespace Fastly\Cdn\Model\Config;

use Fastly\Cdn\Model\Api;
use Magento\Framework\App\Config\ScopeConfigInterface;

/**
 * Used for sending purge after disabling Fastly as caching service
 *
 * @author Inchoo
 */
class ConfigRewrite
{
    private $purge = false;
    /**
     * @var ScopeConfigInterface
     */
    private $scopeConfig = null;
    /**
     * @var Api
     */
    private $api;

    /**
     * ConfigRewrite constructor.
     *
     * @param ScopeConfigInterface $scopeConfig
     * @param Api $api
     */
    public function __construct(
        ScopeConfigInterface $scopeConfig,
        Api $api
    ) {
        $this->scopeConfig = $scopeConfig;
        $this->api = $api;
    }

    /**
     * Trigger purge if set
     *
     * @param \Magento\Config\Model\Config $subject
     * @throws \Zend_Uri_Exception
     */
    public function afterSave(\Magento\Config\Model\Config $subject) // @codingStandardsIgnoreLine - unused parameter
    {
        if ($this->purge) {
            $this->api->cleanBySurrogateKey(['text']);
        }
    }

    /**
     * Set flag for purging if Fastly is switched off
     * @param \Magento\Config\Model\Config $subject
     */
    public function beforeSave(\Magento\Config\Model\Config $subject)
    {
        $data = $subject->getData();
        if (!empty($data['groups']['full_page_cache']['fields']['caching_application']['value'])) {
            $currentCacheConfig = $data['groups']['full_page_cache']['fields']['caching_application']['value'];
            $oldCacheConfig = $this->scopeConfig->getValue(\Magento\PageCache\Model\Config::XML_PAGECACHE_TYPE);

            if ($oldCacheConfig == \Fastly\Cdn\Model\Config::FASTLY && $currentCacheConfig != $oldCacheConfig) {
                $this->purge = true;
            }
        }
    }
}


<?php
/**
 * Fastly CDN for Magento
 *
 * NOTICE OF LICENSE
 *
 * This source file is subject to the Fastly CDN for Magento End User License Agreement
 * that is bundled with this package in the file LICENSE_FASTLY_CDN.txt.
 *
 * DISCLAIMER
 *
 * Do not edit or add to this file if you wish to upgrade Fastly CDN to newer
 * versions in the future. If you wish to customize this module for your
 * needs please refer to http://www.magento.com for more information.
 *
 * @category    Fastly
 * @package     Fastly_Cdn
 * @copyright   Copyright (c) 2016 Fastly, Inc. (http://www.fastly.com)
 * @license     BSD, see LICENSE_FASTLY_CDN.txt
 */
namespace Fastly\Cdn\Controller\Adminhtml\FastlyCdn\Domains;

use Magento\Backend\App\Action;
use Magento\Backend\App\Action\Context;
use Magento\Framework\App\Request\Http;
use Magento\Framework\App\ResponseInterface;
use Magento\Framework\Controller\Result\JsonFactory;
use Fastly\Cdn\Model\Api;
use Magento\Framework\Controller\ResultInterface;
use Magento\Store\Model\StoreManagerInterface;

/**
 * Class GetDomains
 *
 * @package Fastly\Cdn\Controller\Adminhtml\FastlyCdn\Domains
 */
class GetDomains extends Action
{
    /**
     * @var Http
     */
    private $request;
    /**
     * @var JsonFactory
     */
    private $resultJson;
    /**
     * @var Api
     */
    private $api;
    /**
     * @var StoreManagerInterface
     */
    private $storeManager;

    /**
     * GetDomains constructor.
     *
     * @param Context $context
     * @param Http $request
     * @param JsonFactory $resultJsonFactory
     * @param StoreManagerInterface $storeManager
     * @param Api $api
     */
    public function __construct(
        Context $context,
        Http $request,
        JsonFactory $resultJsonFactory,
        StoreManagerInterface $storeManager,
        Api $api
    ) {
        $this->request = $request;
        $this->resultJson = $resultJsonFactory;
        $this->storeManager = $storeManager;
        $this->api = $api;
        parent::__construct($context);
    }

    /**
     * Get all domains for active version
     *
     * @return $this|ResponseInterface|ResultInterface
     */
    public function execute()
    {
        $result = $this->resultJson->create();
        try {
            $activeVersion = $this->getRequest()->getParam('active_version');
            $domains = $this->api->getAllDomains($activeVersion);
            $storeBaseUrl = $this->storeManager->getStore()->getBaseUrl();

            if (!$domains) {
                return $result->setData([
                    'status'    => false,
                    'msg'       => 'Failed to check Domain details.'
                ]);
            }

            return $result->setData([
                'status'    => true,
                'domains'   => $domains,
                'store'     => $storeBaseUrl
            ]);
        } catch (\Exception $e) {
            return $result->setData([
                'status'    => false,
                'msg'       => $e->getMessage()
            ]);
        }
    }
}


<?php
/**
 * Fastly CDN for Magento
 *
 * NOTICE OF LICENSE
 *
 * This source file is subject to the Fastly CDN for Magento End User License Agreement
 * that is bundled with this package in the file LICENSE_FASTLY_CDN.txt.
 *
 * DISCLAIMER
 *
 * Do not edit or add to this file if you wish to upgrade Fastly CDN to newer
 * versions in the future. If you wish to customize this module for your
 * needs please refer to http://www.magento.com for more information.
 *
 * @category    Fastly
 * @package     Fastly_Cdn
 * @copyright   Copyright (c) 2016 Fastly, Inc. (http://www.fastly.com)
 * @license     BSD, see LICENSE_FASTLY_CDN.txt
 */
namespace Fastly\Cdn\Controller\Adminhtml\FastlyCdn\BasicAuthentication;

use Fastly\Cdn\Model\Config;
use Fastly\Cdn\Model\Api;
use Magento\Backend\App\Action;
use Magento\Backend\App\Action\Context;
use Magento\Framework\Controller\Result\JsonFactory;

/**
 * Class CheckAuthUsersAvailable
 *
 * @package Fastly\Cdn\Controller\Adminhtml\FastlyCdn\BasicAuthentication
 */
class CheckAuthUsersAvailable extends Action
{
    /**
     * @var Api
     */
    private $api;
    /**
     * @var Config
     */
    private $config;
    /**
     * @var JsonFactory
     */
    private $resultJsonFactory;

    /**
     * CheckTlsSetting constructor.
     *
     * @param Context $context
     * @param Config $config
     * @param Api $api
     * @param JsonFactory $resultJsonFactory
     */
    public function __construct(
        Context $context,
        Config $config,
        Api $api,
        JsonFactory $resultJsonFactory
    ) {
        $this->api = $api;
        $this->config = $config;
        $this->resultJsonFactory = $resultJsonFactory;

        parent::__construct($context);
    }

    /**
     * Check if authentication users are available
     *
     * @return \Magento\Framework\Controller\Result\Json
     */
    public function execute()
    {
        $result = $this->resultJsonFactory->create();
        try {
            $activeVersion = $this->getRequest()->getParam('active_version');
            $dictionaryName = Config::AUTH_DICTIONARY_NAME;
            $dictionary = $this->api->getSingleDictionary($activeVersion, $dictionaryName);

            if ((is_array($dictionary) && empty($dictionary)) || $dictionary == false || !isset($dictionary->id)) {
                return $result->setData([
                    'status'    => 'empty',
                    'msg'       => 'Basic Authentication cannot be enabled because there are no users assigned to it.'
                ]);
            } else {
                $authItems = $this->api->dictionaryItemsList($dictionary->id);

                if (is_array($authItems) && empty($authItems)) {
                    return $result->setData([
                        'status' => 'empty',
                        'msg'    => 'Basic Authentication cannot be enabled because there are no users assigned to it.'
                    ]);
                }

                return $result->setData(['status' => true]);
            }
        } catch (\Exception $e) {
            return $result->setData([
                'status'    => false,
                'msg'       => $e->getMessage()
            ]);
        }
    }
}


<?php
/**
 * Fastly CDN for Magento
 *
 * NOTICE OF LICENSE
 *
 * This source file is subject to the Fastly CDN for Magento End User License Agreement
 * that is bundled with this package in the file LICENSE_FASTLY_CDN.txt.
 *
 * DISCLAIMER
 *
 * Do not edit or add to this file if you wish to upgrade Fastly CDN to newer
 * versions in the future. If you wish to customize this module for your
 * needs please refer to http://www.magento.com for more information.
 *
 * @category    Fastly
 * @package     Fastly_Cdn
 * @copyright   Copyright (c) 2016 Fastly, Inc. (http://www.fastly.com)
 * @license     BSD, see LICENSE_FASTLY_CDN.txt
 */
namespace Fastly\Cdn\Block\System\Config\Form\Field;

use Magento\Config\Block\System\Config\Form\Field;
use Magento\Framework\Data\Form\Element\AbstractElement;
use Magento\Backend\Block\Template\Context;
use Fastly\Cdn\Model\Config;
use Fastly\Cdn\Model\Config\Backend\PixelRatios;

/**
 * Class Checkbox
 *
 * @package Fastly\Cdn\Block\System\Config\Form\Field
 */
class Checkbox extends Field
{
    public $values = null;
    public $pixelRatios;
    public $config;

    public function __construct(
        Context $context,
        PixelRatios $pixelRatios,
        Config $config
    ) {
        $this->pixelRatios = $pixelRatios;
        $this->config = $config;
        parent::__construct($context);
    }

    public function _construct()
    {
        $this->_template = 'Fastly_Cdn::system/config/form/field/checkbox.phtml';

        parent::_construct();
    }

    /**
     * Retrieve element HTML markup.
     *
     * @param \Magento\Framework\Data\Form\Element\AbstractElement $element
     * @return string
     */
    public function _getElementHtml(AbstractElement $element)
    {
        $this->setNamePrefix($element->getName())
            ->setHtmlId($element->getHtmlId());

        return $this->_toHtml();
    }

    /**
     * Get pixel ratio values
     *
     * @return array
     */
    public function getValues()
    {
        $values = [];
        $ratios = $this->pixelRatios->toOptionArray();
        foreach ($ratios as $value) {
            $values[$value['value']] = $value['label'];
        }
        return $values;
    }
    /**
     * Get is checked values
     *
     * @param  $name
     * @return boolean
     */
    public function getIsChecked($name)
    {
        return in_array($name, $this->getCheckedValues());
    }

    /**
     * Get checked values
     *
     * @return array|null
     */
    public function getCheckedValues()
    {
        if ($this->values === null) {
            $data = $this->config->getImageOptimizationRatios();
            if (!isset($data)) {
                $data = '';
            }
            $this->values = explode(',', $data);
        }
        return $this->values;
    }
}


<?php

namespace Fastly\Cdn\Model\Modly;

class Node
{
    const BASE_CONFIG_PATH = 'system/full_page_cache/fastly_edge_modules';

    /**
     * @var string
     */
    private $id;

    /**
     * @var string
     */
    private $label;

    /**
     * @var string
     */
    private $comment;

    /**
     * @var array child nodes
     */
    private $children = [];

    /**
     * Node constructor.
     *
     * @param string $id
     * @param string $label
     * @param string $comment
     */
    public function __construct(
        $id,
        $label,
        $comment
    ) {
        $this->id       = $id;
        $this->label    = $label;
        $this->comment  = $comment;
    }

    /**
     * Returns identifier
     *
     * @return string
     */
    public function getId()
    {
        return $this->id;
    }

    /**
     * Returns Modly node config
     *
     * @return array
     */
    public function render()
    {
        return [
            'id'            => $this->getId(),
            'translate'     => 'label comment',
            'showInDefault' => 1,
            'showInWebsite' => 0,
            'showInStore'   => 0,
            'sortOrder'     => 1,
            'label'         => $this->label,
            'comment'       => $this->comment,
            '_elementType'  => 'group',
            'path'          => self::BASE_CONFIG_PATH,
            'children'      => $this->children
        ];
    }

    /**
     * Insert text input for Modly config
     *
     * @param $id
     * @param $label
     * @param $comment
     */
    public function addTextInput($id, $label, $comment, $required = true)
    {
        $this->children[$id] = [
            'id'            => $id,
            'type'          => 'text',
            'translate'     => 'label comment',
            'showInDefault' => 1,
            'showInWebsite' => 0,
            'showInStore'   => 0,
            'sortOrder'     => count($this->children),
            'label'         => $label,
            'comment'       => $comment,
            'validate'      => ($required == true) ? 'required-entry' : '',
            '_elementType'  => 'field',
            'path'          => self::BASE_CONFIG_PATH . '/' . $this->id
        ];
    }

    public function addOptionInput($id, $label, $comment, $optionsData, $required = true)
    {
        $options['option'] = [];
        foreach ($optionsData as $optionValue => $optionLabel) {
            $options['option'][] = [
                'name' => strtolower(str_replace(' ', '_', trim($optionValue))),
                'value' => $optionValue,
                'label' => $optionLabel
            ];
        }

        $this->children[$id] = [
            'id'            => $id,
            'type'          => 'select',
            'translate'     => 'label comment',
            'showInDefault' => 1,
            'showInWebsite' => 0,
            'showInStore'   => 0,
            'sortOrder'     => count($this->children),
            'label'         => $label,
            'comment'       => $comment,
            'validate'      => ($required == true) ? 'required-entry' : '',
            '_elementType'  => 'field',
            'options'       => $options,
            'path'          => self::BASE_CONFIG_PATH . '/' . $this->id
        ];
    }
}


<?php
/**
 * Fastly CDN for Magento
 *
 * NOTICE OF LICENSE
 *
 * This source file is subject to the Fastly CDN for Magento End User License Agreement
 * that is bundled with this package in the file LICENSE_FASTLY_CDN.txt.
 *
 * DISCLAIMER
 *
 * Do not edit or add to this file if you wish to upgrade Fastly CDN to newer
 * versions in the future. If you wish to customize this module for your
 * needs please refer to http://www.magento.com for more information.
 *
 * @category    Fastly
 * @package     Fastly_Cdn
 * @copyright   Copyright (c) 2016 Fastly, Inc. (http://www.fastly.com)
 * @license     BSD, see LICENSE_FASTLY_CDN.txt
 */
namespace Fastly\Cdn\Block\System\Config\Form\Field;

use Fastly\Cdn\Model\Config;
use Magento\Backend\Block\Template\Context;
use Magento\Config\Block\System\Config\Form\Field;
use Magento\Framework\Data\Form\Element\AbstractElement;

/**
 * Class WafBtn
 *
 * @package Fastly\Cdn\Block\System\Config\Form\Field
 */
class WafBtn extends Field
{
    protected function _construct() // @codingStandardsIgnoreLine - required by parent class
    {
        $this->_template = 'Fastly_Cdn::system/config/form/field/wafBtn.phtml';

        parent::_construct();
    }

    /**
     * Remove scope label
     *
     * @param  AbstractElement $element
     * @return string
     */
    public function render(AbstractElement $element)
    {
        $element->unsScope()->unsCanUseWebsiteValue()->unsCanUseDefaultValue();
        return parent::render($element);
    }

    /**
     * Return element html
     *
     * @param  AbstractElement $element
     * @return string
     */
    protected function _getElementHtml(AbstractElement $element) // @codingStandardsIgnoreLine - required by parent class
    {
        return $this->_toHtml();
    }

    /**
     * Return ajax url for collect button
     *
     * @return string
     */
    public function getAjaxUrl()
    {
        return $this->getUrl('adminhtml/fastlyCdn/vcl/serviceinfo');
    }

    /**
     * @return string
     * @throws \Magento\Framework\Exception\LocalizedException
     */
    public function getButtonHtml()
    {
        $button = $this->getLayout()->createBlock(
            'Magento\Backend\Block\Widget\Button'
        )->setData([
            'id'    => 'toggle_waf',
            'label' => __('Enable/Disable')
        ]);

        return $button->toHtml();
    }
}


<?php
/**
 * Fastly CDN for Magento
 *
 * NOTICE OF LICENSE
 *
 * This source file is subject to the Fastly CDN for Magento End User License Agreement
 * that is bundled with this package in the file LICENSE_FASTLY_CDN.txt.
 *
 * DISCLAIMER
 *
 * Do not edit or add to this file if you wish to upgrade Fastly CDN to newer
 * versions in the future. If you wish to customize this module for your
 * needs please refer to http://www.magento.com for more information.
 *
 * @category    Fastly
 * @package     Fastly_Cdn
 * @copyright   Copyright (c) 2016 Fastly, Inc. (http://www.fastly.com)
 * @license     BSD, see LICENSE_FASTLY_CDN.txt
 */
namespace Fastly\Cdn\Controller\Adminhtml\FastlyCdn\CustomSnippet;

use Fastly\Cdn\Model\Config;
use Magento\Framework\App\Action\Action;
use Magento\Framework\App\Action\Context;
use Magento\Framework\Controller\Result\RawFactory;
use Magento\Framework\App\Response\Http\FileFactory;
use Magento\Framework\App\Filesystem\DirectoryList;
use Magento\Framework\Filesystem\Directory\WriteFactory;
use Magento\Framework\Controller\Result\JsonFactory;
use Magento\Framework\Filesystem;
use Magento\Framework\Exception\LocalizedException;

/**
 * Class GetCustomSnippet
 *
 * @package Fastly\Cdn\Controller\Adminhtml\FastlyCdn\CustomSnippet
 */
class GetCustomSnippet extends Action
{
    /**
     * @var RawFactory
     */
    private $resultRawFactory;
    /**
     * @var FileFactory
     */
    private $fileFactory;
    /**
     * @var DirectoryList
     */
    private $directoryList;
    /**
     * @var WriteFactory
     */
    private $writeFactory;
    /**
     * @var JsonFactory
     */
    private $resultJson;
    /**
     * @var Filesystem
     */
    private $filesystem;

    /**
     * DeleteCustomSnippet constructor.
     *
     * @param Context $context
     * @param RawFactory $resultRawFactory
     * @param FileFactory $fileFactory
     * @param DirectoryList $directoryList
     * @param WriteFactory $writeFactory
     * @param JsonFactory $resultJsonFactory
     * @param Filesystem $filesystem
     */
    public function __construct(
        Context $context,
        RawFactory $resultRawFactory,
        FileFactory $fileFactory,
        DirectoryList $directoryList,
        WriteFactory $writeFactory,
        JsonFactory $resultJsonFactory,
        Filesystem $filesystem
    ) {
        $this->resultRawFactory = $resultRawFactory;
        $this->fileFactory = $fileFactory;
        $this->directoryList = $directoryList;
        $this->writeFactory = $writeFactory;
        $this->resultJson = $resultJsonFactory;
        $this->filesystem = $filesystem;

        parent::__construct($context);
    }

    /**
     * Get custom snippet
     *
     * @return $this|\Magento\Framework\App\ResponseInterface|\Magento\Framework\Controller\ResultInterface
     */
    public function execute()
    {
        $result = $this->resultJson->create();

        try {
            $snippet = $this->getRequest()->getParam('snippet_id');

            $read = $this->filesystem->getDirectoryRead(DirectoryList::VAR_DIR);
            $snippetPath = $read->getRelativePath(Config::CUSTOM_SNIPPET_PATH . $snippet);

            if ($read->isExist($snippetPath)) {
                $explodeId = explode('.', $snippet, -1);
                $snippetParts = explode('_', $explodeId[0], 3);
                $type = $snippetParts[0];
                $priority = $snippetParts[1];
                $name = $snippetParts[2];
                $content = $read->readFile($snippetPath);
            } else {
                throw new LocalizedException(__('Custom snippet not found.'));
            }

            return $result->setData([
                'status'    => true,
                'type'      => $type,
                'priority'  => $priority,
                'name'      => $name,
                'content'   => $content,
                'original'  => $snippet
            ]);
        } catch (\Exception $e) {
            return $result->setData([
                'status'    => false,
                'msg'       => $e->getMessage()
            ]);
        }
    }
}


<?php
/**
 * Fastly CDN for Magento
 *
 * NOTICE OF LICENSE
 *
 * This source file is subject to the Fastly CDN for Magento End User License Agreement
 * that is bundled with this package in the file LICENSE_FASTLY_CDN.txt.
 *
 * DISCLAIMER
 *
 * Do not edit or add to this file if you wish to upgrade Fastly CDN to newer
 * versions in the future. If you wish to customize this module for your
 * needs please refer to http://www.magento.com for more information.
 *
 * @category    Fastly
 * @package     Fastly_Cdn
 * @copyright   Copyright (c) 2016 Fastly, Inc. (http://www.fastly.com)
 * @license     BSD, see LICENSE_FASTLY_CDN.txt
 */
namespace Fastly\Cdn\Controller\Adminhtml\FastlyCdn\Purge;

use Fastly\Cdn\Model\Config;
use Fastly\Cdn\Model\PurgeCache;
use Magento\Backend\App\Action;
use Magento\Backend\App\Action\Context;
use Magento\Framework\Exception\LocalizedException;
use Magento\Framework\UrlInterface;
use Magento\Store\Model\StoreManagerInterface;

/**
 * Class Quick
 *
 * @package Fastly\Cdn\Controller\Adminhtml\FastlyCdn\Purge
 */
class Quick extends Action
{
    /**
     * @var PurgeCache
     */
    private $purgeCache;
    /**
     * @var StoreManagerInterface
     */
    private $storeManager;
    /**
     * @var Config
     */
    private $config;

    /**
     * Quick constructor.
     *
     * @param Context $context
     * @param PurgeCache $purgeCache
     * @param StoreManagerInterface $storeManager
     * @param Config $config
     */
    public function __construct(
        Context $context,
        PurgeCache $purgeCache,
        StoreManagerInterface $storeManager,
        Config $config
    ) {
        $this->purgeCache = $purgeCache;
        $this->storeManager = $storeManager;
        $this->config = $config;

        parent::__construct($context);
    }

    /**
     * Purge by content type
     *
     * @return \Magento\Framework\App\ResponseInterface
     * @throws \Exception
     */
    public function execute()
    {
        try {
            if ($this->config->getType() == Config::FASTLY && $this->config->isEnabled()) {
                // check if url is given
                $url = $this->getRequest()->getParam('quick_purge_url', false);

                $zendUri = \Zend_Uri::factory($url);
                $host = $zendUri->getHost();
                $scheme = $zendUri->getScheme();
                $path = $zendUri->getPath();

                // check if host is one of magento's
                if (!$this->isHostInDomainList($host)) {
                    throw new LocalizedException(__('Invalid domain "'.$host.'".'));
                }

                // build uri to purge
                $uri = $scheme . '://' . $host;

                if (isset($path)) {
                    $uri .= $path;
                }

                // purge uri
                $result = $this->purgeCache->sendPurgeRequest($uri);
                if ($result['status']) {
                    $this->messageManager->addSuccessMessage(__('The URL\'s "' . $url . '" cache has been cleaned.'));
                } else {
                    $this->getMessageManager()->addErrorMessage(
                        __('The purge request was not processed successfully. [' . $result['msg'] . ']')
                    );
                }
            }
        } catch (\Exception $e) {
            $this->getMessageManager()->addErrorMessage(
                __('An error occurred while clearing the Fastly CDN: ') . $e->getMessage()
            );
        }
        return $this->_redirect('*/cache/index');
    }

    /**
     * Checks if host is one of Magento's configured domains.
     *
     * @param $host
     * @return bool
     * @throws \Zend_Uri_Exception
     */
    private function isHostInDomainList($host)
    {
        $urlTypes = [
            UrlInterface::URL_TYPE_LINK,
            UrlInterface::URL_TYPE_DIRECT_LINK,
            UrlInterface::URL_TYPE_WEB,
            UrlInterface::URL_TYPE_MEDIA,
            UrlInterface::URL_TYPE_STATIC
        ];
        $secureScheme = [true, false];

        foreach ($this->storeManager->getStores() as $store) {
            /** @var \Magento\Store\Model\Store $store */
            foreach ($urlTypes as $urlType) {
                foreach ($secureScheme as $scheme) {
                    $shopHost = \Zend_Uri::factory($store->getBaseUrl($urlType, $scheme))->getHost();
                    if ($host === $shopHost) {
                        return true;
                    }
                }
            }
        }
        return false;
    }
}


<?php
/**
 * Fastly CDN for Magento
 *
 * NOTICE OF LICENSE
 *
 * This source file is subject to the Fastly CDN for Magento End User License Agreement
 * that is bundled with this package in the file LICENSE_FASTLY_CDN.txt.
 *
 * DISCLAIMER
 *
 * Do not edit or add to this file if you wish to upgrade Fastly CDN to newer
 * versions in the future. If you wish to customize this module for your
 * needs please refer to http://www.magento.com for more information.
 *
 * @category    Fastly
 * @package     Fastly_Cdn
 * @copyright   Copyright (c) 2016 Fastly, Inc. (http://www.fastly.com)
 * @license     BSD, see LICENSE_FASTLY_CDN.txt
 */
namespace Fastly\Cdn\Controller\GeoIP;

use Fastly\Cdn\Model\Config;
use Magento\Framework\App\Action\Context;
use Magento\Framework\App\ResponseInterface;
use Magento\Framework\Controller\ResultInterface;
use Magento\Framework\Locale\ResolverInterface as LocaleResolverInterface;
use Magento\Framework\UrlInterface;
use Magento\Framework\View\Result\Layout;
use Magento\Framework\View\Result\LayoutFactory;
use Magento\Store\Api\StoreRepositoryInterface;
use Magento\Store\Model\StoreManagerInterface;
use Magento\Store\Model\StoreResolver;
use Magento\Store\Api\Data\StoreInterface;
use Psr\Log\LoggerInterface;
use Magento\Framework\App\Action\Action;

/**
 * Class GetAction
 *
 * @package Fastly\Cdn\Controller\GeoIP
 */
class GetAction extends Action
{
    const REQUEST_PARAM_COUNTRY = 'country_code';
    /**
     * @var Config
     */
    private $config;
    /**
     * @var UrlInterface
     */
    private $url;
    /**
     * @var StoreRepositoryInterface
     */
    private $storeRepository;
    /**
     * @var StoreManagerInterface
     */
    private $storeManager;
    /**
     * @var LayoutFactory
     */
    private $resultLayoutFactory;
    /**
     * @var LocaleResolverInterface
     */
    private $localeResolver;
    /**
     * @var LoggerInterface
     */
    private $logger;

    /**
     * GetAction constructor.
     *
     * @param Context $context
     * @param Config $config
     * @param StoreRepositoryInterface $storeRepository
     * @param StoreManagerInterface $storeManager
     * @param LayoutFactory $resultLayoutFactory
     * @param LocaleResolverInterface $localeResolver
     * @param LoggerInterface $logger
     */
    public function __construct(
        Context $context,
        Config $config,
        StoreRepositoryInterface $storeRepository,
        StoreManagerInterface $storeManager,
        LayoutFactory $resultLayoutFactory,
        LocaleResolverInterface $localeResolver,
        LoggerInterface $logger
    ) {
        parent::__construct($context);
        $this->config               = $config;
        $this->storeRepository      = $storeRepository;
        $this->storeManager         = $storeManager;
        $this->resultLayoutFactory  = $resultLayoutFactory;
        $this->localeResolver       = $localeResolver;
        $this->logger               = $logger;

        $this->url  = $context->getUrl();
    }

    /**
     * Get GeoIP action
     *
     * @return ResponseInterface|ResultInterface|Layout|null
     */
    public function execute()
    {
        $resultLayout = null;

        try {
            $resultLayout = $this->resultLayoutFactory->create();
            $resultLayout->addDefaultHandle();

            // get target store from country code
            $countryCode = $this->getRequest()->getParam(self::REQUEST_PARAM_COUNTRY);
            $storeId = $this->config->getGeoIpMappingForCountry($countryCode);

            if ($storeId !== null) {
                // get redirect URL
                $redirectUrl = null;
                $targetStore = $this->storeRepository->getActiveStoreById($storeId);
                $currentStore = $this->storeManager->getStore();
                // only generate a redirect URL if current and new store are different
                if ($currentStore->getId() != $targetStore->getId()) {
                    $this->url->setScope($targetStore->getId());
                    $this->url->addQueryParams([
                        '___store'      => $targetStore->getCode(),
                        '___from_store' => $currentStore->getCode()
                    ]);
                    $redirectUrl = $this->url->getUrl('stores/store/switch');
                }

                // generate output only if redirect should be performed
                if ($redirectUrl) {
                    switch ($this->config->getGeoIpAction()) {
                        case Config::GEOIP_ACTION_DIALOG:
                            $resultLayout->getLayout()->getUpdate()->load(['geoip_getaction_dialog']);
                            $resultLayout->getLayout()->getBlock('geoip_getaction')->setMessage(
                                $this->getMessageInStoreLocale($targetStore)
                            );
                            break;
                        case Config::GEOIP_ACTION_REDIRECT:
                            $resultLayout->getLayout()->getUpdate()->load(['geoip_getaction_redirect']);
                            break;
                    }

                    $resultLayout->getLayout()->getBlock('geoip_getaction')->setRedirectUrl($redirectUrl);
                }
            }
        } catch (\Exception $e) {
            $this->logger->critical($e->getMessage());
            // do not generate output on errors. this is similar to an empty GeoIP mapping for the country.
        }

        $resultLayout->setHeader("x-esi", "1");
        return $resultLayout;
    }

    /**
     * Gets the dialog message in the locale of the target store.
     * @param StoreInterface $emulatedStore
     * @return string
     * @throws \Magento\Framework\Exception\NoSuchEntityException
     */
    private function getMessageInStoreLocale(StoreInterface $emulatedStore)
    {
        $currentStore = $this->storeManager->getStore();

        // emulate locale and store of new store to fetch message translation
        $this->localeResolver->emulate($emulatedStore->getId());
        $this->storeManager->setCurrentStore($emulatedStore->getId());

        $message = __(
            'You are in the wrong store. Click OK to visit the %1 store.',
            [$emulatedStore->getName()]
        )->__toString();

        // revert locale and store emulation
        $this->localeResolver->revert();
        $this->storeManager->setCurrentStore($currentStore->getId());

        return $message;
    }
}


<?php
/**
 * Fastly CDN for Magento
 *
 * NOTICE OF LICENSE
 *
 * This source file is subject to the Fastly CDN for Magento End User License Agreement
 * that is bundled with this package in the file LICENSE_FASTLY_CDN.txt.
 *
 * DISCLAIMER
 *
 * Do not edit or add to this file if you wish to upgrade Fastly CDN to newer
 * versions in the future. If you wish to customize this module for your
 * needs please refer to http://www.magento.com for more information.
 *
 * @category    Fastly
 * @package     Fastly_Cdn
 * @copyright   Copyright (c) 2016 Fastly, Inc. (http://www.fastly.com)
 * @license     BSD, see LICENSE_FASTLY_CDN.txt
 */
namespace Fastly\Cdn\Controller\Adminhtml\FastlyCdn\Configuration;

use Fastly\Cdn\Model\Config;
use Fastly\Cdn\Model\Api;
use Magento\Backend\App\Action;
use Magento\Backend\App\Action\Context;
use Fastly\Cdn\Helper\Vcl;
use Magento\Framework\Controller\Result\JsonFactory;

/**
 * Class ServiceInfo
 *
 * @package Fastly\Cdn\Controller\Adminhtml\FastlyCdn\Configuration
 */
class ServiceInfo extends Action
{
    /**
     * @var Api
     */
    private $api;
    /**
     * @var Config
     */
    private $config;
    /**
     * @var Vcl
     */
    private $vcl;
    /**
     * @var JsonFactory
     */
    private $resultJsonFactory;

    /**
     * ServiceInfo constructor.
     *
     * @param Context $context
     * @param Config $config
     * @param Api $api
     * @param JsonFactory $resultJsonFactory
     * @param Vcl $vcl
     */
    public function __construct(
        Context $context,
        Config $config,
        Api $api,
        JsonFactory $resultJsonFactory,
        Vcl $vcl
    ) {
        $this->api = $api;
        $this->config = $config;
        $this->resultJsonFactory = $resultJsonFactory;
        $this->vcl = $vcl;

        parent::__construct($context);
    }

    /**
     * Checking service details
     *
     * @return \Magento\Framework\Controller\Result\Json
     */
    public function execute()
    {
        $result = $this->resultJsonFactory->create();
        try {
            $service = $this->api->checkServiceDetails();
            return $result->setData([
                'status'            => true,
                'service'           => $service,
                'active_version'    => $this->vcl->getCurrentVersion($service->versions),
                'next_version'      => $this->vcl->getNextVersion($service->versions),
            ]);
        } catch (\Exception $e) {
            return $result->setData([
                'status'    => false,
                'msg'       => $e->getMessage()
            ]);
        }
    }
}


<?php
/**
 * Fastly CDN for Magento
 *
 * NOTICE OF LICENSE
 *
 * This source file is subject to the Fastly CDN for Magento End User License Agreement
 * that is bundled with this package in the file LICENSE_FASTLY_CDN.txt.
 *
 * DISCLAIMER
 *
 * Do not edit or add to this file if you wish to upgrade Fastly CDN to newer
 * versions in the future. If you wish to customize this module for your
 * needs please refer to http://www.magento.com for more information.
 *
 * @category    Fastly
 * @package     Fastly_Cdn
 * @copyright   Copyright (c) 2016 Fastly, Inc. (http://www.fastly.com)
 * @license     BSD, see LICENSE_FASTLY_CDN.txt
 */
namespace Fastly\Cdn\Model\PageCache;

use Fastly\Cdn\Model\Config;
use Magento\CacheInvalidate\Model\PurgeCache;

/**
 * Class PurgeCachePlugin
 *
 * @package Fastly\Cdn\Model\PageCache
 */
class PurgeCachePlugin
{
    /**
     * @var Config
     */
    private $config;

    /**
     * PurgeCachePlugin constructor.
     *
     * @param Config $config
     */
    public function __construct(
        Config $config
    ) {
        $this->config = $config;
    }

    /**
     * Prevent Magento from executing purge requests on Varnish when Fastly is enabled
     *
     * @param PurgeCache $subject
     * @param callable $proceed
     * @param array ...$args
     */
    public function aroundSendPurgeRequest(PurgeCache $subject, callable $proceed, ...$args) // @codingStandardsIgnoreLine - unused parameter
    {
        if ($this->config->isFastlyEnabled() !== true) {
            $proceed(...$args);
        }
    }
}


<?php
/**
 * Fastly CDN for Magento
 *
 * NOTICE OF LICENSE
 *
 * This source file is subject to the Fastly CDN for Magento End User License Agreement
 * that is bundled with this package in the file LICENSE_FASTLY_CDN.txt.
 *
 * DISCLAIMER
 *
 * Do not edit or add to this file if you wish to upgrade Fastly CDN to newer
 * versions in the future. If you wish to customize this module for your
 * needs please refer to http://www.magento.com for more information.
 *
 * @category    Fastly
 * @package     Fastly_Cdn
 * @copyright   Copyright (c) 2016 Fastly, Inc. (http://www.fastly.com)
 * @license     BSD, see LICENSE_FASTLY_CDN.txt
 */
namespace Fastly\Cdn\Observer;

use Magento\Framework\Event\ObserverInterface;
use Magento\Framework\View\Element\AbstractBlock;
use Magento\Framework\Event\Observer;
use Magento\Framework\App\ResponseInterface as Response;
use Magento\PageCache\Model\Config;
use Fastly\Cdn\Model\Config as FastlyConfig;

/**
 * Class MarkEsiPage
 *
 * @package Fastly\Cdn\Observer
 */
class MarkEsiPage implements ObserverInterface
{
    /**
     * Application config object
     *
     * @var \Magento\PageCache\Model\Config
     */
    private $config;
    /**
     * @var FastlyConfig
     */
    private $fastlyConfig;
    /**
     * @var Response
     */
    private $response;

    /**
     * MarkEsiPage constructor.
     * @param Config $config
     * @param Response $response
     * @param FastlyConfig $fastlyConfig
     */
    public function __construct(
        Config $config,
        Response $response,
        FastlyConfig $fastlyConfig
    ) {
        $this->config = $config;
        $this->fastlyConfig = $fastlyConfig;
        $this->response = $response;
    }

    /**
     * Set x-esi header if block contains ttl attribute
     *
     * @param Observer $observer
     */
    public function execute(Observer $observer)
    {
        if ($this->fastlyConfig->isFastlyEnabled() != true) {
            return;
        }

        $event = $observer->getEvent();
        $name = $event->getElementName();

        /** @var \Magento\Framework\View\Layout $layout */
        $layout = $event->getLayout();

        /** @var AbstractBlock $block */
        $block = $layout->getBlock($name);

        if ($block instanceof AbstractBlock) {
            $blockTtl = $block->getTtl();
            if (isset($blockTtl)) {
                // This page potentially has ESIs so as a first cut let's mark it as such
                $this->response->setHeader("x-esi", "1");
            }
        }
    }
}


<?php
/**
 * Fastly CDN for Magento
 *
 * NOTICE OF LICENSE
 *
 * This source file is subject to the Fastly CDN for Magento End User License Agreement
 * that is bundled with this package in the file LICENSE_FASTLY_CDN.txt.
 *
 * DISCLAIMER
 *
 * Do not edit or add to this file if you wish to upgrade Fastly CDN to newer
 * versions in the future. If you wish to customize this module for your
 * needs please refer to http://www.magento.com for more information.
 *
 * @category    Fastly
 * @package     Fastly_Cdn
 * @copyright   Copyright (c) 2016 Fastly, Inc. (http://www.fastly.com)
 * @license     BSD, see LICENSE_FASTLY_CDN.txt
 */
namespace Fastly\Cdn\Observer;

use Fastly\Cdn\Helper\CacheTags;
use Fastly\Cdn\Model\Config;
use Fastly\Cdn\Model\PurgeCache;
use Magento\Framework\Event\ObserverInterface;

/**
 * Class InvalidateVarnishObserver
 *
 * @package Fastly\Cdn\Observer
 */
class InvalidateVarnishObserver implements ObserverInterface
{
    /**
     * @var Config
     */
    private $config;
    /**
     * @var PurgeCache
     */
    private $purgeCache;
    /**
     * @var CacheTags
     */
    private $cacheTags;
    /**
     * @var array
     */
    private $alreadyPurged = [];

    /**
     * @param Config $config
     * @param PurgeCache $purgeCache
     * @param CacheTags $cacheTags
     */
    public function __construct(
        Config $config,
        PurgeCache $purgeCache,
        CacheTags $cacheTags
    ) {
        $this->config = $config;
        $this->purgeCache = $purgeCache;
        $this->cacheTags = $cacheTags;
    }

    /**
     * If Fastly CDN is enabled it sends one purge request per tag
     *
     * @param \Magento\Framework\Event\Observer $observer
     * @throws \Zend_Uri_Exception
     */
    public function execute(\Magento\Framework\Event\Observer $observer)
    {
        if ($this->config->getType() == Config::FASTLY && $this->config->isEnabled()) {
            $object = $observer->getEvent()->getObject();

            if ($object instanceof \Magento\Framework\DataObject\IdentityInterface && $this->canPurgeObject($object)) {
                $tags = [];
                foreach ($object->getIdentities() as $tag) {
                    $tag = $this->cacheTags->convertCacheTags($tag);
                    if (!in_array($tag, $this->alreadyPurged)) {
                        $tags[] = $tag;
                        $this->alreadyPurged[] = $tag;
                    }
                }

                if (!empty($tags)) {
                    $this->purgeCache->sendPurgeRequest(array_unique($tags));
                }
            }
        }
    }

    /**
     * Return false if purging is not allowed for object instance.
     *
     * @param \Magento\Framework\DataObject\IdentityInterface $object
     * @return bool
     */
    private function canPurgeObject(\Magento\Framework\DataObject\IdentityInterface $object)
    {
        if ($object instanceof \Magento\Catalog\Model\Category && !$this->config->canPurgeCatalogCategory()) {
            return false;
        }
        if ($object instanceof \Magento\Catalog\Model\Product && !$this->config->canPurgeCatalogProduct()) {
            return false;
        }
        if ($object instanceof \Magento\Cms\Model\Page && !$this->config->canPurgeCmsPage()) {
            return false;
        }
        return true;
    }
}


<?php
/**
 * Fastly CDN for Magento
 *
 * NOTICE OF LICENSE
 *
 * This source file is subject to the Fastly CDN for Magento End User License Agreement
 * that is bundled with this package in the file LICENSE_FASTLY_CDN.txt.
 *
 * DISCLAIMER
 *
 * Do not edit or add to this file if you wish to upgrade Fastly CDN to newer
 * versions in the future. If you wish to customize this module for your
 * needs please refer to http://www.magento.com for more information.
 *
 * @category    Fastly
 * @package     Fastly_Cdn
 * @copyright   Copyright (c) 2016 Fastly, Inc. (http://www.fastly.com)
 * @license     BSD, see LICENSE_FASTLY_CDN.txt
 */
namespace Fastly\Cdn\Controller\Adminhtml\FastlyCdn\BasicAuthentication\Item;

use Fastly\Cdn\Model\Api;
use Magento\Backend\App\Action;
use Magento\Backend\App\Action\Context;
use Magento\Framework\App\Request\Http;
use Magento\Framework\Controller\Result\JsonFactory;
use Fastly\Cdn\Model\Config;
use Fastly\Cdn\Helper\Vcl;

/**
 * Class ListAll
 *
 * @package Fastly\Cdn\Controller\Adminhtml\FastlyCdn\BasicAuthentication\Item
 */
class ListAll extends Action
{
    /**
     * @var Http
     */
    private $request;
    /**
     * @var JsonFactory
     */
    private $resultJson;
    /**
     * @var Api
     */
    private $api;
    /**
     * @var Config
     */
    private $config;
    /**
     * @var Vcl
     */
    private $vcl;

    /**
     * ListAll constructor.
     *
     * @param Context $context
     * @param Http $request
     * @param JsonFactory $resultJsonFactory
     * @param Config $config
     * @param Api $api
     * @param Vcl $vcl
     */
    public function __construct(
        Context $context,
        Http $request,
        JsonFactory $resultJsonFactory,
        Config $config,
        Api $api,
        Vcl $vcl
    ) {
        $this->request = $request;
        $this->resultJson = $resultJsonFactory;
        $this->config = $config;
        $this->api = $api;
        $this->vcl = $vcl;

        parent::__construct($context);
    }

    /**
     * Get all Auth items for active version
     *
     * @return $this|\Magento\Framework\App\ResponseInterface|\Magento\Framework\Controller\ResultInterface
     */
    public function execute()
    {
        $result = $this->resultJson->create();

        try {
            $activeVersion = $this->getRequest()->getParam('active_version');
            $dictionary = $this->api->getSingleDictionary($activeVersion, 'magentomodule_basic_auth');

            // Fetch Authentication items
            if (!$dictionary || (is_array($dictionary) && empty($dictionary))) {
                return $result->setData([
                    'status'    => 'none',
                    'msg'       => 'Authentication dictionary does not exist.'
                ]);
            }

            $authItems = false;

            if (isset($dictionary->id)) {
                $authItems = $this->api->dictionaryItemsList($dictionary->id);
            }

            if (is_array($authItems) && empty($authItems)) {
                return $result->setData([
                    'status'    => 'empty',
                    'msg'       => 'There are no dictionary items.'
                ]);
            }

            if (!$authItems) {
                return $result->setData([
                    'status'    => false,
                    'msg'       => 'Failed to fetch dictionary items.'
                ]);
            }

            foreach ($authItems as $key => $item) {
                $userData = explode(':', base64_decode($item->item_key)); // @codingStandardsIgnoreLine - used for authentication
                $username = $userData[0];
                $item->item_key_id = $item->item_key;
                $item->item_key = $username;
                $authItems[$key] = $item;
            }

            return $result->setData([
                'status'    => true,
                'auths'     => $authItems
            ]);
        } catch (\Exception $e) {
            return $result->setData([
                'status'    => false,
                'msg'       => $e->getMessage()
            ]);
        }
    }
}


<?php
/**
 * Fastly CDN for Magento
 *
 * NOTICE OF LICENSE
 *
 * This source file is subject to the Fastly CDN for Magento End User License Agreement
 * that is bundled with this package in the file LICENSE_FASTLY_CDN.txt.
 *
 * DISCLAIMER
 *
 * Do not edit or add to this file if you wish to upgrade Fastly CDN to newer
 * versions in the future. If you wish to customize this module for your
 * needs please refer to http://www.magento.com for more information.
 *
 * @category    Fastly
 * @package     Fastly_Cdn
 * @copyright   Copyright (c) 2016 Fastly, Inc. (http://www.fastly.com)
 * @license     BSD, see LICENSE_FASTLY_CDN.txt
 */
namespace Fastly\Cdn\Setup;

use Magento\Framework\Setup\InstallSchemaInterface;
use Magento\Framework\Setup\ModuleContextInterface;
use Magento\Framework\Setup\SchemaSetupInterface;

/**
 * Class InstallSchema
 *
 * @codeCoverageIgnore
 * @package Fastly\Cdn\Setup
 */
class InstallSchema implements InstallSchemaInterface // @codingStandardsIgnoreLine - currently best way to resolve this
{
    /**
     * {@inheritdoc}
     * @SuppressWarnings(PHPMD.ExcessiveMethodLength)
     */
    public function install(SchemaSetupInterface $setup, ModuleContextInterface $context) // @codingStandardsIgnoreLine - unused parameter
    {
        $installer = $setup;

        /** @var \Magento\Framework\DB\Adapter\AdapterInterface $connection */
        $connection = $installer->getConnection();

        $installer->startSetup();

        /**
         * Create table 'fastly_statistics'
         */
        $table = $connection->newTable(
            $installer->getTable('fastly_statistics')
        )->addColumn(
            'stat_id',
            \Magento\Framework\DB\Ddl\Table::TYPE_INTEGER,
            null,
            ['identity' => true, 'unsigned' => true, 'nullable' => false, 'primary' => true],
            'Stat id'
        )->addColumn(
            'action',
            \Magento\Framework\DB\Ddl\Table::TYPE_TEXT,
            30,
            ['nullable' => false],
            'Fastly action'
        )->addColumn(
            'sent',
            \Magento\Framework\DB\Ddl\Table::TYPE_BOOLEAN,
            null,
            ['nullable' => false, 'default' => 0],
            '1 = Curl req. sent | 0 = Curl req. not sent'
        )->addColumn(
            'state',
            \Magento\Framework\DB\Ddl\Table::TYPE_BOOLEAN,
            null,
            ['nullable' => false, 'default' => 0],
            '1 = configured | 0 = not_configured'
        )->addColumn(
            'created_at',
            \Magento\Framework\DB\Ddl\Table::TYPE_DATETIME,
            null,
            [],
            'Action date'
        );
        $connection->createTable($table);
        $installer->endSetup();
    }
}


<?php
/**
 * Fastly CDN for Magento
 *
 * NOTICE OF LICENSE
 *
 * This source file is subject to the Fastly CDN for Magento End User License Agreement
 * that is bundled with this package in the file LICENSE_FASTLY_CDN.txt.
 *
 * DISCLAIMER
 *
 * Do not edit or add to this file if you wish to upgrade Fastly CDN to newer
 * versions in the future. If you wish to customize this module for your
 * needs please refer to http://www.magento.com for more information.
 *
 * @category    Fastly
 * @package     Fastly_Cdn
 * @copyright   Copyright (c) 2016 Fastly, Inc. (http://www.fastly.com)
 * @license     BSD, see LICENSE_FASTLY_CDN.txt
 */
namespace Fastly\Cdn\Controller\Adminhtml\FastlyCdn\Waf;

use Magento\Backend\App\Action;
use Magento\Backend\App\Action\Context;
use Magento\Framework\App\Request\Http;
use Magento\Framework\Controller\Result\JsonFactory;
use Fastly\Cdn\Model\Config;
use Fastly\Cdn\Model\Api;
use Fastly\Cdn\Helper\Vcl;
use Magento\Framework\App\Config\Storage\WriterInterface as ConfigWriter;
use Magento\Framework\App\Cache\TypeListInterface as CacheTypeList;
use Magento\Config\App\Config\Type\System as SystemConfig;

/**
 * Class UpdateWafAllowlist
 *
 * @package Fastly\Cdn\Controller\Adminhtml\FastlyCdn\Waf
 */
class UpdateWafAllowlist extends Action
{
    /**
     * @var Http
     */
    private $request;
    /**
     * @var JsonFactory
     */
    private $resultJson;
    /**
     * @var Config
     */
    private $config;
    /**
     * @var Api
     */
    private $api;
    /**
     * @var Vcl
     */
    private $vcl;
    /**
     * @var ConfigWriter
     */
    private $configWriter;
    /**
     * @var CacheTypeList
     */
    private $cacheTypeList;
    /**
     * @var SystemConfig
     */
    private $systemConfig;

    /**
     * UpdateWafAllowlist constructor.
     *
     * @param Context $context
     * @param Http $request
     * @param JsonFactory $resultJsonFactory
     * @param Config $config
     * @param Api $api
     * @param Vcl $vcl
     * @param ConfigWriter $configWriter
     * @param CacheTypeList $cacheTypeList
     * @param SystemConfig $systemConfig
     */
    public function __construct(
        Context $context,
        Http $request,
        JsonFactory $resultJsonFactory,
        Config $config,
        Api $api,
        Vcl $vcl,
        ConfigWriter $configWriter,
        CacheTypeList $cacheTypeList,
        SystemConfig $systemConfig
    ) {
        $this->request = $request;
        $this->resultJson = $resultJsonFactory;
        $this->config = $config;
        $this->api = $api;
        $this->vcl = $vcl;
        $this->configWriter = $configWriter;
        $this->cacheTypeList = $cacheTypeList;
        $this->systemConfig = $systemConfig;
        parent::__construct($context);
    }

    /**
     * Upload WAF Bypass snippets
     *
     * @return $this|\Magento\Framework\App\ResponseInterface|\Magento\Framework\Controller\ResultInterface
     */
    public function execute()
    {
        $result = $this->resultJson->create();
        try {
            $service = $this->api->checkServiceDetails();
            $currActiveVersion = $this->vcl->determineVersions($service->versions);

            $snippet = $this->config->getVclSnippets(
                Config::VCL_WAF_PATH,
                Config::VCL_WAF_ALLOWLIST_SNIPPET
            );

            $acls = $this->prepareAcls($this->request->getParam('acls'));

            $allowedItems = $acls;
            $strippedAllowedItems = substr($allowedItems, 0, strrpos($allowedItems, '||', -1));

            // Add WAF bypass snippet
            foreach ($snippet as $key => $value) {
                if ($strippedAllowedItems === '') {
                    $value = '';
                } else {
                    $value = str_replace('####WAF_ALLOWLIST####', $strippedAllowedItems, $value);
                }

                $snippetName = Config::FASTLY_MAGENTO_MODULE . '_waf_' . $key;
                $snippetId = $this->api->getSnippet($currActiveVersion['active_version'], $snippetName)->id;
                $params = [
                    'name'      => $snippetId,
                    'content'   => $value
                ];

                $this->api->updateSnippet($params);
            }

            $this->cacheTypeList->cleanType('config');
            $this->systemConfig->clean();

            return $result->setData([
                'status' => true
            ]);
        } catch (\Exception $e) {
            return $result->setData([
                'status'    => false,
                'msg'       => $e->getMessage()
            ]);
        }
    }

    /**
     * Prepares ACL VCL snippets
     *
     * @param $allowedAcls
     * @return string
     */
    private function prepareAcls($allowedAcls)
    {
        $result = '';
        $aclsArray = [];
        $acls = '';

        if ($allowedAcls != null) {
            foreach ($allowedAcls as $key => $value) {
                $aclsArray[] = $value['value'];
            }
            $acls = implode(',', $aclsArray);
        }

        $this->configWriter->save(
            Config::XML_FASTLY_WAF_ALLOW_BY_ACL,
            $acls,
            'default',
            '0'
        );

        if ($acls != '') {
            $allowedAclsPieces = explode(",", $acls);
            foreach ($allowedAclsPieces as $acl) {
                $result .= ' req.http.Fastly-Client-Ip ~ ' . $acl . ' ||';
            }
        }

        return $result;
    }
}


<?php
/**
 * Fastly CDN for Magento
 *
 * NOTICE OF LICENSE
 *
 * This source file is subject to the Fastly CDN for Magento End User License Agreement
 * that is bundled with this package in the file LICENSE_FASTLY_CDN.txt.
 *
 * DISCLAIMER
 *
 * Do not edit or add to this file if you wish to upgrade Fastly CDN to newer
 * versions in the future. If you wish to customize this module for your
 * needs please refer to http://www.magento.com for more information.
 *
 * @category    Fastly
 * @package     Fastly_Cdn
 * @copyright   Copyright (c) 2016 Fastly, Inc. (http://www.fastly.com)
 * @license     BSD, see LICENSE_FASTLY_CDN.txt
 */
namespace Fastly\Cdn\Controller\Adminhtml\FastlyCdn\CustomSnippet;

use Magento\Framework\App\Action\Action;
use Magento\Framework\App\Action\Context;
use Magento\Framework\Controller\Result\RawFactory;
use Magento\Framework\App\Response\Http\FileFactory;
use Magento\Framework\App\Filesystem\DirectoryList;
use Magento\Framework\Exception\LocalizedException;
use Magento\Framework\Filesystem\Directory\WriteFactory;
use Magento\Framework\Controller\Result\JsonFactory;
use Magento\Framework\Filesystem;
use Fastly\Cdn\Model\Config;

/**
 * Class EditCustomSnippet
 *
 * @package Fastly\Cdn\Controller\Adminhtml\FastlyCdn\CustomSnippet
 */
class EditCustomSnippet extends Action
{
    /**
     * @var RawFactory
     */
    private $resultRawFactory;
    /**
     * @var FileFactory
     */
    private $fileFactory;
    /**
     * @var DirectoryList
     */
    private $directoryList;
    /**
     * @var WriteFactory
     */
    private $writeFactory;
    /**
     * @var JsonFactory
     */
    private $resultJson;
    /**
     * @var Filesystem
     */
    private $filesystem;
    /**
     * @var Config
     */
    private $config;

    /**
     * EditCustomSnippet constructor.
     *
     * @param Context $context
     * @param RawFactory $resultRawFactory
     * @param FileFactory $fileFactory
     * @param DirectoryList $directoryList
     * @param WriteFactory $writeFactory
     * @param JsonFactory $resultJsonFactory
     * @param Filesystem $filesystem
     * @param Config $config
     */
    public function __construct(
        Context $context,
        RawFactory $resultRawFactory,
        FileFactory $fileFactory,
        DirectoryList $directoryList,
        WriteFactory $writeFactory,
        JsonFactory $resultJsonFactory,
        Filesystem $filesystem,
        Config $config
    ) {
        $this->resultRawFactory = $resultRawFactory;
        $this->fileFactory = $fileFactory;
        $this->directoryList = $directoryList;
        $this->writeFactory = $writeFactory;
        $this->resultJson = $resultJsonFactory;
        $this->filesystem = $filesystem;
        $this->config = $config;

        parent::__construct($context);
    }

    /**
     * Edit custom snippet
     *
     * @return $this|\Magento\Framework\App\ResponseInterface|\Magento\Framework\Controller\ResultInterface
     */
    public function execute()
    {
        $result = $this->resultJson->create();
        try {
            $name = $this->getRequest()->getParam('name');
            $type = $this->getRequest()->getParam('type');
            $priority = $this->getRequest()->getParam('priority');
            $vcl = $this->getRequest()->getParam('vcl');

            $validation = $this->config->validateCustomSnippet($name, $type, $priority);
            $error = $validation['error'];
            if ($error != null) {
                throw new LocalizedException(__($error));
            }
            $snippetName = $validation['snippet_name'];
            $fileName = $type . '_' . $priority . '_' . $snippetName . '.vcl';

            $write = $this->filesystem->getDirectoryWrite(DirectoryList::VAR_DIR);
            $snippetPath = $write->getRelativePath(Config::CUSTOM_SNIPPET_PATH . $fileName);

            $write->writeFile($snippetPath, $vcl);

            return $result->setData([
                'status'    => true
            ]);
        } catch (\Exception $e) {
            return $result->setData([
                'status'    => false,
                'msg'       => $e->getMessage()
            ]);
        }
    }
}


<?php
/**
 * Fastly CDN for Magento
 *
 * NOTICE OF LICENSE
 *
 * This source file is subject to the Fastly CDN for Magento End User License Agreement
 * that is bundled with this package in the file LICENSE_FASTLY_CDN.txt.
 *
 * DISCLAIMER
 *
 * Do not edit or add to this file if you wish to upgrade Fastly CDN to newer
 * versions in the future. If you wish to customize this module for your
 * needs please refer to http://www.magento.com for more information.
 *
 * @category    Fastly
 * @package     Fastly_Cdn
 * @copyright   Copyright (c) 2016 Fastly, Inc. (http://www.fastly.com)
 * @license     BSD, see LICENSE_FASTLY_CDN.txt
 */
namespace Fastly\Cdn\Controller\Adminhtml\FastlyCdn\Edge\Dictionary\Item;

use Fastly\Cdn\Model\Api;
use Magento\Backend\App\Action;
use Magento\Backend\App\Action\Context;
use Magento\Framework\App\Request\Http;
use Magento\Framework\Controller\Result\JsonFactory;

/**
 * Class ListAll
 *
 * @package Fastly\Cdn\Controller\Adminhtml\FastlyCdn\Edge\Dictionary\Item
 */
class ListAll extends Action
{
    /**
     * @var Http
     */
    private $request;
    /**
     * @var JsonFactory
     */
    private $resultJson;
    /**
     * @var Api
     */
    private $api;

    /**
     * ListAll constructor
     *
     * @param Context $context
     * @param Http $request
     * @param JsonFactory $resultJsonFactory
     * @param Api $api
     */
    public function __construct(
        Context $context,
        Http $request,
        JsonFactory $resultJsonFactory,
        Api $api
    ) {
        $this->request = $request;
        $this->resultJson = $resultJsonFactory;
        $this->api = $api;

        parent::__construct($context);
    }

    /**
     * Get all dictionaries for active version
     *
     * @return $this|\Magento\Framework\App\ResponseInterface|\Magento\Framework\Controller\ResultInterface
     */
    public function execute()
    {
        $result = $this->resultJson->create();

        try {
            $dictionaryId = $this->getRequest()->getParam('dictionary_id');
            $dictionaryItems = $this->api->dictionaryItemsList($dictionaryId);

            if (is_array($dictionaryItems) && empty($dictionaryItems)) {
                return $result->setData([
                    'status'            => 'empty',
                    'dictionaryItems'   => []
                ]);
            }

            if (!$dictionaryItems) {
                return $result->setData([
                    'status'    => false,
                    'msg'       => 'Failed to fetch dictionary items.'
                ]);
            }

            return $result->setData([
                'status'            => true,
                'dictionaryItems'   => $dictionaryItems
            ]);
        } catch (\Exception $e) {
            return $result->setData([
                'status'    => false,
                'msg'       => $e->getMessage()
            ]);
        }
    }
}


<?php
/**
 * Fastly CDN for Magento
 *
 * NOTICE OF LICENSE
 *
 * This source file is subject to the Fastly CDN for Magento End User License Agreement
 * that is bundled with this package in the file LICENSE_FASTLY_CDN.txt.
 *
 * DISCLAIMER
 *
 * Do not edit or add to this file if you wish to upgrade Fastly CDN to newer
 * versions in the future. If you wish to customize this module for your
 * needs please refer to http://www.magento.com for more information.
 *
 * @category    Fastly
 * @package     Fastly_Cdn
 * @copyright   Copyright (c) 2016 Fastly, Inc. (http://www.fastly.com)
 * @license     BSD, see LICENSE_FASTLY_CDN.txt
 */
namespace Fastly\Cdn\Plugin;

use Fastly\Cdn\Model\Config;
use Magento\Catalog\Block\Product\Image;

/**
 * Class AdaptivePixelRationPlugin
 *
 * @package Fastly\Cdn\Plugin
 */
class AdaptivePixelRationPlugin
{
    /**
     * @var Config
     */
    public $config;

    /**
     * AdaptivePixelRationPlugin constructor.
     *
     * @param Config $config
     */
    public function __construct(Config $config)
    {
        $this->config = $config;
    }

    /**
     * Adjust srcset if required
     *
     * @param Image $subject
     */
    public function beforeToHtml(Image $subject)
    {
        if ($this->config->isImageOptimizationPixelRatioEnabled() !== true) {
            return;
        }

        $srcSet = [];
        $imageUrl = $subject->getData('image_url');
        $pixelRatios = $this->config->getImageOptimizationRatios();
        $pixelRatiosArray = explode(',', $pixelRatios);
        $glue = (strpos($imageUrl, '?') !== false) ? '&' : '?';

        # Pixel ratios defaults are based on the table from https://mydevice.io/devices/
        # Bulk of devices are 2x however many new devices like Samsung S8, iPhone X etc are 3x and 4x
        foreach ($pixelRatiosArray as $pr) {
            $ratio = 'dpr=' . $pr . ' ' . $pr . 'x';
            $srcSet[] = $imageUrl . $glue . $ratio;
        }

        $subject->setData('custom_attributes', 'srcset="' . implode(',', $srcSet) . '"');
    }
}


<?php
/**
 * Fastly CDN for Magento
 *
 * NOTICE OF LICENSE
 *
 * This source file is subject to the Fastly CDN for Magento End User License Agreement
 * that is bundled with this package in the file LICENSE_FASTLY_CDN.txt.
 *
 * DISCLAIMER
 *
 * Do not edit or add to this file if you wish to upgrade Fastly CDN to newer
 * versions in the future. If you wish to customize this module for your
 * needs please refer to http://www.magento.com for more information.
 *
 * @category    Fastly
 * @package     Fastly_Cdn
 * @copyright   Copyright (c) 2016 Fastly, Inc. (http://www.fastly.com)
 * @license     BSD, see LICENSE_FASTLY_CDN.txt
 */
namespace Fastly\Cdn\Controller\Adminhtml\FastlyCdn\BasicAuthentication\Item;

use Fastly\Cdn\Model\Api;
use Magento\Backend\App\Action;
use Magento\Backend\App\Action\Context;
use Magento\Framework\App\Request\Http;
use Magento\Framework\Controller\Result\JsonFactory;
use Fastly\Cdn\Model\Config;
use Fastly\Cdn\Helper\Vcl;

/**
 * Class Delete
 *
 * @package Fastly\Cdn\Controller\Adminhtml\FastlyCdn\BasicAuthentication\Item
 */
class Delete extends Action
{
    /**
     * @var Http
     */
    private $request;
    /**
     * @var JsonFactory
     */
    private $resultJson;
    /**
     * @var Config
     */
    private $config;
    /**
     * @var Api
     */
    private $api;
    /**
     * @var Vcl
     */
    private $vcl;

    /**
     * ForceTls constructor.
     *
     * @param Context $context
     * @param Http $request
     * @param JsonFactory $resultJsonFactory
     * @param Config $config
     * @param Api $api
     * @param Vcl $vcl
     */
    public function __construct(
        Context $context,
        Http $request,
        JsonFactory $resultJsonFactory,
        Config $config,
        Api $api,
        Vcl $vcl
    ) {
        $this->request = $request;
        $this->resultJson = $resultJsonFactory;
        $this->config = $config;
        $this->api = $api;
        $this->vcl = $vcl;
        parent::__construct($context);
    }

    /**
     * Delete auth item
     *
     * @return $this|\Magento\Framework\App\ResponseInterface|\Magento\Framework\Controller\ResultInterface
     */
    public function execute()
    {
        $result = $this->resultJson->create();

        try {
            $activeVersion = $this->getRequest()->getParam('active_version');
            $dictionary = $this->api->getSingleDictionary($activeVersion, Config::AUTH_DICTIONARY_NAME);
            $vclPath = Config::VCL_AUTH_SNIPPET_PATH;
            $snippets = $this->config->getVclSnippets($vclPath);

            // Check if snippets exist
            $status = true;
            foreach ($snippets as $key => $value) {
                $name = Config::FASTLY_MAGENTO_MODULE.'_basic_auth_'.$key;
                $status = $this->api->getSnippet($activeVersion, $name);

                if (!$status) {
                    break;
                }
            }

            if ((is_array($dictionary) && empty($dictionary)) || !isset($dictionary->id)) {
                return $result->setData([
                    'status'    => 'empty',
                    'msg'       => 'Authentication dictionary does not exist.'
                ]);
            }

            // Check if there are any entries left
            $authItems = $this->api->dictionaryItemsList($dictionary->id);

            if (($status == true && is_array($authItems) && count($authItems) < 2) || $authItems == false) {
                // No users left, send message
                return $result->setData([
                    'status'    => 'empty',
                    'msg'       => 'While Basic Authentication is enabled, at least one user must exist.',
                ]);
            }

            $itemKey = $this->getRequest()->getParam('item_key_id');
            $deleteItem = $this->api->deleteDictionaryItem($dictionary->id, $itemKey);

            if (!$deleteItem) {
                return $result->setData([
                    'status'    => false,
                    'msg'       => 'Failed to create Dictionary item.'
                ]);
            }

            return $result->setData(['status' => true]);
        } catch (\Exception $e) {
            return $result->setData([
                'status'    => false,
                'msg'       => $e->getMessage()
            ]);
        }
    }
}