diff --git a/src/nginxconfig/generators/conf/wordpress.conf.js b/src/nginxconfig/generators/conf/wordpress.conf.js index bed25c2d..e7ee830d 100644 --- a/src/nginxconfig/generators/conf/wordpress.conf.js +++ b/src/nginxconfig/generators/conf/wordpress.conf.js @@ -29,6 +29,16 @@ import phpUpstream from '../../util/php_upstream.js'; export default (global, domain) => { const config = {}; + const denyGeneralPaths = [ + 'wp-links-opml\\.php', + 'wp-config\\.php', + 'wp-config-sample\\.php', + 'readme\\.html', + 'license\\.txt', + ]; + + if (domain.php.allowWordPressXmlrpc?.computed !== true) + denyGeneralPaths.unshift('xmlrpc\\.php'); config['# WordPress: allow TinyMCE'] = ''; config['location = /wp-includes/js/tinymce/wp-tinymce.php'] = { @@ -55,9 +65,7 @@ export default (global, domain) => { }; config['# WordPress: deny general stuff'] = ''; - config[ - 'location ~* ^/(?:xmlrpc\\.php|wp-links-opml\\.php|wp-config\\.php|wp-config-sample\\.php|readme\\.html|license\\.txt)$' - ] = { + config[`location ~* ^/(?:${denyGeneralPaths.join('|')})$`] = { deny: 'all', }; diff --git a/src/nginxconfig/i18n/de/templates/domain_sections/php.js b/src/nginxconfig/i18n/de/templates/domain_sections/php.js index d95d1f33..d0f74cef 100644 --- a/src/nginxconfig/i18n/de/templates/domain_sections/php.js +++ b/src/nginxconfig/i18n/de/templates/domain_sections/php.js @@ -33,6 +33,7 @@ export default { enablePhp: `${common.enable} ${common.php}`, wordPressRules: `${common.wordPress} Regeln`, enableWordPressRules: `${common.enable} ${common.wordPress}-spezifische Regeln`, + allowWordPressXmlrpc: 'XML-RPC-Zugriff erlauben', drupalRules: `${common.drupal} Regeln`, enableDrupalRules: `${common.enable} ${common.drupal}-spezifische Regeln`, magentoRules: `${common.magento} Regeln`, diff --git a/src/nginxconfig/i18n/en/templates/domain_sections/php.js b/src/nginxconfig/i18n/en/templates/domain_sections/php.js index 03e30e38..eab83e1e 100644 --- a/src/nginxconfig/i18n/en/templates/domain_sections/php.js +++ b/src/nginxconfig/i18n/en/templates/domain_sections/php.js @@ -33,6 +33,7 @@ export default { enablePhp: `${common.enable} ${common.php}`, wordPressRules: `${common.wordPress} rules`, enableWordPressRules: `${common.enable} ${common.wordPress}-specific rules`, + allowWordPressXmlrpc: 'Allow XML-RPC access', drupalRules: `${common.drupal} rules`, enableDrupalRules: `${common.enable} ${common.drupal}-specific rules`, magentoRules: `${common.magento} rules`, diff --git a/src/nginxconfig/i18n/es/templates/domain_sections/php.js b/src/nginxconfig/i18n/es/templates/domain_sections/php.js index 75f10daa..65b2bca0 100644 --- a/src/nginxconfig/i18n/es/templates/domain_sections/php.js +++ b/src/nginxconfig/i18n/es/templates/domain_sections/php.js @@ -33,6 +33,7 @@ export default { enablePhp: `${common.enable} ${common.php}`, wordPressRules: `Reglas de ${common.wordPress}`, enableWordPressRules: `${common.enable} reglas especificas de ${common.wordPress}`, + allowWordPressXmlrpc: 'Permitir acceso XML-RPC', drupalRules: `Reglas de ${common.drupal}`, enableDrupalRules: `${common.enable} reglas especificas de ${common.drupal}`, magentoRules: `Reglas de ${common.magento}`, diff --git a/src/nginxconfig/i18n/fa/templates/domain_sections/php.js b/src/nginxconfig/i18n/fa/templates/domain_sections/php.js index 275cc864..ddd2ae22 100644 --- a/src/nginxconfig/i18n/fa/templates/domain_sections/php.js +++ b/src/nginxconfig/i18n/fa/templates/domain_sections/php.js @@ -33,6 +33,7 @@ export default { enablePhp: `${common.enable} ${common.php}`, wordPressRules: `قوانین ${common.wordPress}`, enableWordPressRules: `${common.enable} قوانین خاص ${common.wordPress}`, + allowWordPressXmlrpc: 'اجازه دسترسی XML-RPC', drupalRules: `قوانین ${common.drupal}`, enableDrupalRules: `${common.enable} قوانین خاص ${common.drupal}`, magentoRules: `قوانین ${common.magento}`, diff --git a/src/nginxconfig/i18n/fr/templates/domain_sections/php.js b/src/nginxconfig/i18n/fr/templates/domain_sections/php.js index e843de3c..812d1330 100644 --- a/src/nginxconfig/i18n/fr/templates/domain_sections/php.js +++ b/src/nginxconfig/i18n/fr/templates/domain_sections/php.js @@ -33,6 +33,7 @@ export default { enablePhp: `${common.enable} ${common.php}`, wordPressRules: `Règles ${common.wordPress}`, enableWordPressRules: `${common.enable} les règles spécifiques à ${common.wordPress}`, + allowWordPressXmlrpc: "Autoriser l'accès XML-RPC", drupalRules: `Règles ${common.drupal}`, enableDrupalRules: `${common.enable} les règles spécifiques à ${common.drupal}`, magentoRules: `Règles ${common.magento}`, diff --git a/src/nginxconfig/i18n/ja/templates/domain_sections/php.js b/src/nginxconfig/i18n/ja/templates/domain_sections/php.js index 974dd8e0..4f8171b0 100644 --- a/src/nginxconfig/i18n/ja/templates/domain_sections/php.js +++ b/src/nginxconfig/i18n/ja/templates/domain_sections/php.js @@ -33,6 +33,7 @@ export default { enablePhp: `${common.php} を${common.enable}`, wordPressRules: `${common.wordPress} ルール`, enableWordPressRules: `${common.wordPress} 用ルールを${common.enable}`, + allowWordPressXmlrpc: 'XML-RPC アクセスを許可', drupalRules: `${common.drupal} ルール`, enableDrupalRules: `${common.drupal} 用ルールを${common.enable}`, magentoRules: `${common.magento} ルール`, diff --git a/src/nginxconfig/i18n/pl/templates/domain_sections/php.js b/src/nginxconfig/i18n/pl/templates/domain_sections/php.js index 714a6521..53c79661 100644 --- a/src/nginxconfig/i18n/pl/templates/domain_sections/php.js +++ b/src/nginxconfig/i18n/pl/templates/domain_sections/php.js @@ -33,6 +33,7 @@ export default { enablePhp: `${common.enable} ${common.php}`, wordPressRules: `reguły ${common.wordPress}`, enableWordPressRules: `${common.enable} reguły specyficzne dla ${common.wordPress}`, + allowWordPressXmlrpc: 'Zezwalaj na dostęp XML-RPC', drupalRules: `reguły ${common.drupal}`, enableDrupalRules: `${common.enable} reguły specyficzne dla ${common.drupal}`, magentoRules: `reguły ${common.magento}`, diff --git a/src/nginxconfig/i18n/pt-br/templates/domain_sections/php.js b/src/nginxconfig/i18n/pt-br/templates/domain_sections/php.js index 11ce6b4e..616b842b 100644 --- a/src/nginxconfig/i18n/pt-br/templates/domain_sections/php.js +++ b/src/nginxconfig/i18n/pt-br/templates/domain_sections/php.js @@ -33,6 +33,7 @@ export default { enablePhp: `${common.enable} ${common.php}`, wordPressRules: `Regras do ${common.wordPress}`, enableWordPressRules: `${common.enable} regras específicas do ${common.wordPress}`, + allowWordPressXmlrpc: 'Permitir acesso XML-RPC', drupalRules: `Regras do ${common.drupal}`, enableDrupalRules: `${common.enable} regras específicas do ${common.drupal}`, magentoRules: `Regras do ${common.magento}`, diff --git a/src/nginxconfig/i18n/ru/templates/domain_sections/php.js b/src/nginxconfig/i18n/ru/templates/domain_sections/php.js index cfdab3b8..3f1b6192 100644 --- a/src/nginxconfig/i18n/ru/templates/domain_sections/php.js +++ b/src/nginxconfig/i18n/ru/templates/domain_sections/php.js @@ -33,6 +33,7 @@ export default { enablePhp: `${common.enable} ${common.php}`, wordPressRules: `${common.wordPress} правила`, enableWordPressRules: `${common.enable} ${common.wordPress}-специфичные правила`, + allowWordPressXmlrpc: 'Разрешить доступ по XML-RPC', drupalRules: `${common.drupal} правила`, enableDrupalRules: `${common.enable} ${common.drupal}-специфичные правила`, magentoRules: `${common.magento} правила`, diff --git a/src/nginxconfig/i18n/zh-cn/templates/domain_sections/php.js b/src/nginxconfig/i18n/zh-cn/templates/domain_sections/php.js index 81c48df5..447f53e8 100644 --- a/src/nginxconfig/i18n/zh-cn/templates/domain_sections/php.js +++ b/src/nginxconfig/i18n/zh-cn/templates/domain_sections/php.js @@ -33,6 +33,7 @@ export default { enablePhp: `${common.enable} ${common.php}`, wordPressRules: `${common.wordPress} 规则`, enableWordPressRules: `${common.enable} ${common.wordPress}专属规则`, + allowWordPressXmlrpc: '允许 XML-RPC 访问', drupalRules: `${common.drupal} 规则`, enableDrupalRules: `${common.enable} ${common.drupal}专属规则`, magentoRules: `${common.magento} 规则`, diff --git a/src/nginxconfig/i18n/zh-tw/templates/domain_sections/php.js b/src/nginxconfig/i18n/zh-tw/templates/domain_sections/php.js index 660f4733..a8ebb3fd 100644 --- a/src/nginxconfig/i18n/zh-tw/templates/domain_sections/php.js +++ b/src/nginxconfig/i18n/zh-tw/templates/domain_sections/php.js @@ -33,6 +33,7 @@ export default { enablePhp: `${common.enable} ${common.php}`, wordPressRules: `${common.wordPress} 規則`, enableWordPressRules: `${common.enable} ${common.wordPress} 專屬規則`, + allowWordPressXmlrpc: '允許 XML-RPC 存取', drupalRules: `${common.drupal} 規則`, enableDrupalRules: `${common.enable} ${common.drupal} 專屬規則`, magentoRules: `${common.magento} 規則`, diff --git a/src/nginxconfig/templates/domain_sections/php.vue b/src/nginxconfig/templates/domain_sections/php.vue index 340ad003..8b31f3f2 100644 --- a/src/nginxconfig/templates/domain_sections/php.vue +++ b/src/nginxconfig/templates/domain_sections/php.vue @@ -170,6 +170,20 @@ THE SOFTWARE. + +
+
+ + {{ $t('templates.domainSections.php.allowWordPressXmlrpc') }} + +
+
@@ -297,6 +311,10 @@ THE SOFTWARE. default: false, enabled: true, }, + allowWordPressXmlrpc: { + default: false, + enabled: false, + }, drupalRules: { default: false, enabled: true, @@ -363,6 +381,12 @@ THE SOFTWARE. this.$props.data.wordPressRules.enabled = true; this.$props.data.wordPressRules.computed = this.$props.data.wordPressRules.value; + this.$props.data.allowWordPressXmlrpc.enabled = + this.$props.data.wordPressRules.value; + this.$props.data.allowWordPressXmlrpc.computed = this.$props.data + .wordPressRules.value + ? this.$props.data.allowWordPressXmlrpc.value + : false; this.$props.data.drupalRules.enabled = true; this.$props.data.drupalRules.computed = this.$props.data.drupalRules.value; this.$props.data.magentoRules.enabled = true; @@ -377,6 +401,8 @@ THE SOFTWARE. this.$props.data.phpBackupServer.computed = ''; this.$props.data.wordPressRules.enabled = false; this.$props.data.wordPressRules.computed = false; + this.$props.data.allowWordPressXmlrpc.enabled = false; + this.$props.data.allowWordPressXmlrpc.computed = false; this.$props.data.drupalRules.enabled = false; this.$props.data.drupalRules.computed = false; this.$props.data.magentoRules.enabled = false; @@ -387,6 +413,16 @@ THE SOFTWARE. }, deep: true, }, + '$props.data.wordPressRules': { + handler(data) { + this.$props.data.allowWordPressXmlrpc.enabled = data.enabled && data.computed; + this.$props.data.allowWordPressXmlrpc.computed = + data.enabled && data.computed + ? this.$props.data.allowWordPressXmlrpc.value + : false; + }, + deep: true, + }, // Check server selection is valid '$props.data.phpServer': { handler(data) { diff --git a/test/testWordPressXmlrpc.js b/test/testWordPressXmlrpc.js new file mode 100644 index 00000000..1d4c78cc --- /dev/null +++ b/test/testWordPressXmlrpc.js @@ -0,0 +1,66 @@ +/* +Copyright 2024 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 wordPressConf from '../src/nginxconfig/generators/conf/wordpress.conf.js'; + +const createGlobal = () => ({ + security: { + limitReq: { + computed: false, + }, + }, +}); + +const createDomain = (allowWordPressXmlrpc = false) => ({ + php: { + allowWordPressXmlrpc: { + computed: allowWordPressXmlrpc, + }, + wordPressRules: { + computed: true, + }, + }, +}); + +const getDenyGeneralRule = (config) => + Object.keys(config).find((key) => key.includes('wp-links-opml\\.php')); + +describe('wordPressConf', () => { + test('denies xmlrpc.php by default', () => { + const denyGeneralRule = getDenyGeneralRule(wordPressConf(createGlobal(), createDomain())); + + expect(denyGeneralRule).toContain('xmlrpc\\.php'); + }); + + test('keeps xmlrpc.php accessible when the toggle is enabled', () => { + const denyGeneralRule = getDenyGeneralRule( + wordPressConf(createGlobal(), createDomain(true)), + ); + + expect(denyGeneralRule).toContain('wp-links-opml\\.php'); + expect(denyGeneralRule).not.toContain('xmlrpc\\.php'); + }); +});