text: /*
  Copyright 2020 DigitalOcean
  
  This code is licensed under the MIT License.
  You may obtain a copy of the License at
  https://github.com/digitalocean/nginxconfig.io/blob/master/LICENSE or https://mit-license.org/
  
  Permission is hereby granted, free of charge, to any person obtaining a copy
  of this software and associated documentation files (the "Software"), to deal
  in the Software without restriction, including without limitation the rights
  to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
  copies of the Software, and to permit persons to whom the Software is
  furnished to do so, subject to the following conditions :
  
  The above copyright notice and this permission notice shall be included in
  all copies or substantial portions of the Software.
  
  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  THE SOFTWARE.
  */
  
  import { getSslCertificate, getSslCertificateKey } from '../../util/get_ssl_certificate';
  import { getAccessLogDomainPath, getErrorLogDomainPath } from '../../util/get_log_paths';
  import { extensions, gzipTypes } from '../../util/types_extensions';
  import commonHsts from '../../util/common_hsts';
  import securityConf from './security.conf';
  import pythonConf from './python_uwsgi.conf';
  import proxyConf from './proxy.conf';
  import phpConf from './php_fastcgi.conf';
  import generalConf from './general.conf';
  import wordPressConf from './wordpress.conf';
  import drupalConf from './drupal.conf';
  import magentoConf from './magento.conf';
  import letsEncryptConf from './letsencrypt.conf';
  
  const sslConfig = (domain, global) => {
      const config = [];
      if (domain.https.https.computed) {
          config.push(['# SSL', '']);
          config.push(['ssl_certificate', getSslCertificate(domain, global)]);
          config.push(['ssl_certificate_key', getSslCertificateKey(domain, global)]);
  
          // Let's encrypt
          if (domain.https.certType.computed === 'letsEncrypt')
              config.push(['ssl_trusted_certificate',
                  `${global.https.letsEncryptCertRoot.computed.replace(/\/+$/, '')}/${domain.server.domain.computed}/chain.pem`]);
      }
      return config;
  };
  
  const httpsListen = domain => {
      const config = [];
  
      // HTTPS
      config.push(['listen', `${domain.server.listenIpv4.computed === '*' ? '' : `${domain.server.listenIpv4.computed}:`}443 ssl${domain.https.http2.computed ? ' http2' : ''}`]);
  
      // v6
      if (domain.server.listenIpv6.computed)
          config.push(['listen',
              `[${domain.server.listenIpv6.computed}]:443 ssl${domain.https.http2.computed ? ' http2' : ''}`]);
  
      return config;
  };
  
  const httpListen = domain => {
      const config = [];
  
      // Not HTTPS
      config.push(['listen', `${domain.server.listenIpv4.computed === '*' ? '' : `${domain.server.listenIpv4.computed}:`}80`]);
  
      // v6
      if (domain.server.listenIpv6.computed)
          config.push(['listen', `[${domain.server.listenIpv6.computed}]:80`]);
  
      return config;
  };
  
  const listenConfig = domain => {
      if (domain.https.https.computed) return httpsListen(domain);
      return httpListen(domain);
  };
  
  export default (domain, domains, global) => {
      // Use kv so we can use the same key multiple times
      const config = [];
  
      // Build the server config on its own before adding it to the parent config
      const serverConfig = [];
  
      // Not HTTPS or not force HTTPS
      if (!domain.https.https.computed || !domain.https.forceHttps.computed) serverConfig.push(...httpListen(domain));
  
      // HTTPS
      if (domain.https.https.computed) serverConfig.push(...httpsListen(domain));
  
      serverConfig.push(['server_name',
          `${domain.server.wwwSubdomain.computed ? 'www.' : ''}${domain.server.domain.computed}`]);
  
      // PHP or Django
      if (domain.php.php.computed || (domain.python.python.computed && domain.python.djangoRules.computed)) {
          serverConfig.push(['set', `$base ${domain.server.path.computed}`]);
  
          // root
          if (domain.routing.root.computed)
              serverConfig.push(['root', `$base${domain.server.documentRoot.computed}`]);
      }
  
      // Not PHP and not Django and root
      if (!domain.php.php.computed
          && (!domain.python.python.computed || !domain.python.djangoRules.computed)
          && domain.routing.root.computed)
          serverConfig.push(['root', `${domain.server.path.computed}${domain.server.documentRoot.computed}`]);
  
      // HTTPS
      serverConfig.push(...sslConfig(domain, global));
  
      // HSTS
      if (!commonHsts(domains) && domain.https.hsts.computed) {
          serverConfig.push(['# HSTS', '']);
          serverConfig.push(['add_header Strict-Transport-Security',
              `'"max-age=31536000${domain.https.hstsSubdomains.computed ? '; includeSubDomains' : ''}${domain.https.hstsPreload.computed ? '; preload' : ''}" always'`]);
      }
  
      // Security
      if (global.tools.modularizedStructure.computed) {
          // Modularized
          serverConfig.push(['# security', '']);
          serverConfig.push(['include', 'nginxconfig.io/security.conf']);
      } else {
          // Unified
          serverConfig.push(...securityConf(domains, global));
      }
  
      // Access log or error log for domain
      if (domain.logging.accessLog.computed || domain.logging.errorLog.computed) {
          serverConfig.push(['# logging', '']);
  
          if (domain.logging.accessLog.computed)
              serverConfig.push(['access_log', getAccessLogDomainPath(domain, global)]);
  
          if (domain.logging.errorLog.computed)
              serverConfig.push(['error_log', getErrorLogDomainPath(domain, global)]);
      }
  
      // index.php
      if (domain.routing.index.computed === 'index.php') {
          serverConfig.push(['# index.php', '']);
          serverConfig.push(['index', 'index.php']);
      }
  
      // Fallback index.html or index.php
      if ((domain.routing.fallbackHtml.computed || domain.routing.fallbackPhp.computed)
          && (!domain.reverseProxy.reverseProxy.computed || domain.reverseProxy.path.computed !== '/')) {
          serverConfig.push([`# index.${domain.routing.fallbackHtml.computed ? 'html' : (domain.routing.fallbackPhp.computed ? 'php' : '')} fallback`, '']);
          serverConfig.push(['location /', {
              try_files: `$uri $uri/ /index.${domain.routing.fallbackHtml.computed ? 'html' : (domain.routing.fallbackPhp.computed ? 'php?$query_string' : '')}`,
          }]);
      }
  
      // Fallback index.html and index.php
      if (domain.routing.fallbackHtml.computed && domain.routing.fallbackPhp.computed) {
          serverConfig.push(['# index.php fallback', '']);
          serverConfig.push([`location ~ ^${domain.routing.fallbackPhpPath.computed}`, {
              try_files: '$uri $uri/ /index.php?$query_string',
          }]);
      }
  
      // Python
      if (domain.python.python.computed) {
          if (global.tools.modularizedStructure.computed) {
              // Modularized
              serverConfig.push(['location /', { include: 'nginxconfig.io/python_uwsgi.conf' }]);
          } else {
              // Unified
              serverConfig.push(['location /', pythonConf(global)]);
          }
  
          // Django
          if (domain.python.djangoRules.computed) {
              serverConfig.push(['# Django media', '']);
              serverConfig.push(['location /media/', { alias: '$base/media/' }]);
  
              serverConfig.push(['# Django static', '']);
              serverConfig.push(['location /static/', { alias: '$base/static/' }]);
          }
      }
  
      // Reverse proxy
      if (domain.reverseProxy.reverseProxy.computed) {
          const locConf = [];
          locConf.push(['proxy_pass', domain.reverseProxy.proxyPass.computed]);
  
          if (global.tools.modularizedStructure.computed) {
              // Modularized
              locConf.push(['include', 'nginxconfig.io/proxy.conf']);
          } else {
              // Unified
              locConf.push(...Object.entries(proxyConf(global)));
          }
  
          serverConfig.push(['# reverse proxy', '']);
          serverConfig.push([`location ${domain.reverseProxy.path.computed}`, locConf]);
      }
  
      // Additional config
      if (global.tools.modularizedStructure.computed) {
          // Modularized
          serverConfig.push(['# additional config', '']);
          serverConfig.push(['include', 'nginxconfig.io/general.conf']);
  
          if (!domain.https.forceHttps.computed && domain.https.certType.computed === 'letsEncrypt')
              serverConfig.push(['include', 'nginxconfig.io/letsencrypt.conf']);
  
          if (domain.php.wordPressRules.computed) serverConfig.push(['include', 'nginxconfig.io/wordpress.conf']);
          if (domain.php.drupalRules.computed) serverConfig.push(['include', 'nginxconfig.io/drupal.conf']);
          if (domain.php.magentoRules.computed) serverConfig.push(['include', 'nginxconfig.io/magento.conf']);
      } else {
          // Unified
          serverConfig.push(...Object.entries(generalConf(domains, global)));
  
          if (!domain.https.forceHttps.computed && domain.https.certType.computed === 'letsEncrypt')
              serverConfig.push(...Object.entries(letsEncryptConf(global)));
  
          if (domain.php.wordPressRules.computed) serverConfig.push(...Object.entries(wordPressConf(global)));
          if (domain.php.drupalRules.computed) serverConfig.push(...Object.entries(drupalConf(global)));
          if (domain.php.magentoRules.computed) serverConfig.push(...Object.entries(magentoConf()));
      }
  
      // PHP
      if (domain.php.php.computed) {
          serverConfig.push(['# handle .php', '']);
  
          const loc = `location ~ ${domain.routing.legacyPhpRouting.computed ? '[^/]\\.php(/|$)' : '\\.php$'}`;
          if (global.tools.modularizedStructure.computed || domain.php.wordPressRules.computed) {
              // Modularized
              serverConfig.push([loc, { include: 'nginxconfig.io/php_fastcgi.conf' }]);
          } else {
              // Unified
              serverConfig.push([loc, phpConf(domains, global)]);
          }
      }
  
      // Add the server config to the parent config now its built
      config.push(['server', serverConfig]);
  
      // CDN!
      if (domain.server.cdnSubdomain.computed) {
          // Build the server config on its own before adding it to the parent config
          const cdnConfig = [];
  
          cdnConfig.push(...listenConfig(domain));
          cdnConfig.push(['server_name', `cdn.${domain.server.domain.computed}`]);
          cdnConfig.push(['root', `${domain.server.path.computed}${domain.server.documentRoot.computed}`]);
  
          // HTTPS
          cdnConfig.push(...sslConfig(domain, global));
  
          cdnConfig.push(['# disable access_log', '']);
          cdnConfig.push(['access_log', 'off']);
  
          // Gzip
          if (global.performance.gzipCompression.computed) {
              cdnConfig.push(['# gzip', '']);
              cdnConfig.push(['gzip', 'on']);
              cdnConfig.push(['gzip_vary', 'on']);
              cdnConfig.push(['gzip_proxied', 'any']);
              cdnConfig.push(['gzip_comp_level', 6]);
              cdnConfig.push(['gzip_types', gzipTypes]);
          }
  
          cdnConfig.push(['# allow safe files', '']);
          cdnConfig.push([
              `location ~* \\.(?:${extensions.assets}|${extensions.fonts}|${extensions.svg}|${extensions.images}|${extensions.audio}|${extensions.video}|${extensions.docs})$`,
              [
                  ['add_header', 'Access-Control-Allow-Origin "*"'],
                  ['add_header', 'Cache-Control "public"'],
                  ['expires', '30d'],
              ],
          ]);
  
          cdnConfig.push(['# deny everything else', '']);
          cdnConfig.push(['location /', { deny: 'all' }]);
  
          // Add the CDN config to the parent config now its built
          config.push(['# CDN', '']);
          config.push(['server', cdnConfig]);
      }
  
      // Subdomains redirect
      if (domain.server.redirectSubdomains.computed) {
          // Build the server config on its own before adding it to the parent config
          const redirectConfig = [];
  
          redirectConfig.push(...listenConfig(domain));
          redirectConfig.push(['server_name', `${domain.server.wwwSubdomain.computed ? '' : '*'}.${domain.server.domain.computed}`]);
  
          // HTTPS
          redirectConfig.push(...sslConfig(domain, global));
  
          redirectConfig.push(['return', `301 http${domain.https.https.computed ? 's' : ''}://${domain.server.wwwSubdomain.computed ? 'www.' : ''}${domain.server.domain.computed}$request_uri`]);
  
          // Add the redirect config to the parent config now its built
          config.push([`# ${domain.server.wwwSubdomain.computed ? 'non-www, ' : ''}subdomains redirect`, '']);
          config.push(['server', redirectConfig]);
      }
  
      // HTTP redirect
      if (domain.https.forceHttps.computed) {
          // Build the server config on its own before adding it to the parent config
          const redirectConfig = [];
  
          redirectConfig.push(...httpListen(domain));
          redirectConfig.push(['server_name',
              `${domain.server.redirectSubdomains.computed ? '.' : ''}${domain.server.domain.computed}`]);
  
          if (domain.https.certType.computed === 'letsEncrypt') {
              // Let's encrypt
  
              if (global.tools.modularizedStructure.computed) {
                  // Modularized
                  redirectConfig.push(['include', 'nginxconfig.io/letsencrypt.conf']);
              } else {
                  // Unified
                  redirectConfig.push(...Object.entries(letsEncryptConf(global)));
              }
  
              redirectConfig.push(['location /', {
                  return: `301 https://${domain.server.wwwSubdomain.computed ? 'www.' : ''}${domain.server.domain.computed}$request_uri`,
              }]);
          } else {
              // Custom cert
              redirectConfig.push(['return', `301 https://${domain.server.wwwSubdomain.computed ? 'www.' : ''}${domain.server.domain.computed}$request_uri`]);
          }
  
          // Add the redirect config to the parent config now its built
          config.push(['# HTTP redirect', '']);
          config.push(['server', redirectConfig]);
      }
  
      return config;
  };
  