Browse Source

Tokenized nginx config

0xJacky 2 years ago
parent
commit
7abd5ce966

+ 1 - 1
README-zh_CN.md

@@ -187,7 +187,7 @@ docker run -dit \
 
 - Make
 
-- Golang 1.17+
+- Golang 1.18+
 
 - node.js 14+
 

+ 1 - 1
README-zh_TW.md

@@ -187,7 +187,7 @@ docker run -dit \
 
 - Make
 
-- Golang 1.17+
+- Golang 1.18+
 
 - node.js 14+
 

+ 1 - 1
README.md

@@ -186,7 +186,7 @@ On platforms that do not have an official build version, they can be built manua
 
 - Make
 
-- Golang 1.17+
+- Golang 1.18+
 
 - node.js 14+
 

+ 1 - 1
frontend/package.json

@@ -51,7 +51,7 @@
         "easygettext": "^2.17.0",
         "eslint": "^6.7.2",
         "eslint-plugin-vue": "^6.2.2",
-        "yarn-audit-fix": "^9.1.2"
+        "yarn-audit-fix": "^9.3.2"
     },
     "eslintConfig": {
         "root": true,

+ 0 - 2
frontend/src/components/VueItextarea/VueItextarea.vue

@@ -1,5 +1,4 @@
 <template>
-<!--    <codemirror v-model="current_value" :options="cmOptions"/>-->
     <editor v-model="current_value" @init="editorInit" lang="nginx" theme="monokai" width="100%" height="1000"></editor>
 </template>
 <style lang="less">
@@ -8,7 +7,6 @@
 }
 </style>
 <script>
-//import {codemirror} from 'vue-codemirror'
 import 'codemirror/lib/codemirror.css'
 import 'codemirror/theme/monokai.css'
 

+ 39 - 30
frontend/src/views/domain/DomainEdit.vue

@@ -1,17 +1,31 @@
 <template>
     <div>
-        <a-collapse :bordered="false" default-active-key="1">
-            <a-collapse-panel key="1">
-                <template v-slot:header>
-                    <span style="margin-right: 10px">{{ $gettextInterpolate($gettext('Edit %{n}'), {n: name}) }}</span>
-                    <a-tag color="blue" v-if="enabled">
-                        {{ $gettext('Enabled') }}
-                    </a-tag>
-                    <a-tag color="orange" v-else>
-                        {{ $gettext('Disabled') }}
-                    </a-tag>
+        <a-card :bordered="false">
+            <template v-slot:title>
+                <span style="margin-right: 10px">{{ $gettextInterpolate($gettext('Edit %{n}'), {n: name}) }}</span>
+                <a-tag color="blue" v-if="enabled">
+                    {{ $gettext('Enabled') }}
+                </a-tag>
+                <a-tag color="orange" v-else>
+                    {{ $gettext('Disabled') }}
+                </a-tag>
+            </template>
+            <template v-slot:extra>
+                <a-switch size="small" v-model="advance_mode"/>
+                <template v-if="advance_mode">
+                    {{ $gettext('Advance') }}
                 </template>
-                <div class="domain-edit-container">
+                <template v-else>
+                    {{ $gettext('Basic') }}
+                </template>
+            </template>
+
+            <transition name="slide-fade">
+                <div v-if="advance_mode" key="advance">
+                    <vue-itextarea v-model="configText"/>
+                </div>
+
+                <div class="domain-edit-container" key="basic" v-else>
                     <a-form-item :label="$gettext('Enabled')">
                         <a-switch v-model="enabled" @change="checked=>{checked?enable():disable()}"/>
                     </a-form-item>
@@ -32,11 +46,8 @@
                         <p v-else v-translate>Make sure you have configured a reverse proxy for .well-known directory to HTTPChallengePort (default: 9180) before getting the certificate.</p>
                     </template>
                 </div>
-            </a-collapse-panel>
-        </a-collapse>
+            </transition>
 
-        <a-card :title="$gettext('Edit Configuration File')">
-            <vue-itextarea v-model="configText"/>
         </a-card>
 
         <footer-tool-bar>
@@ -84,7 +95,8 @@ export default {
             configText: '',
             ws: null,
             ok: false,
-            issuing_cert: false
+            issuing_cert: false,
+            advance_mode: false,
         }
     },
     watch: {
@@ -257,21 +269,7 @@ export default {
 </script>
 
 <style lang="less">
-.ant-collapse {
-    background: #ffffff;
-    @media (prefers-color-scheme: dark) {
-        background: #28292c;
-    }
-    margin-bottom: 20px;
-
-    .ant-collapse-item {
-        border-bottom: unset;
-    }
-}
 
-.ant-collapse-content-box {
-    padding: 24px !important;
-}
 </style>
 
 <style lang="less" scoped>
@@ -290,4 +288,15 @@ export default {
     }
 }
 
+.slide-fade-enter-active {
+    transition: all .5s ease-in-out;
+}
+.slide-fade-leave-active {
+    transition: all .5s cubic-bezier(1.0, 0.5, 0.8, 1.0);
+}
+.slide-fade-enter, .slide-fade-leave-to
+    /* .slide-fade-leave-active for below version 2.1.8 */ {
+    transform: translateX(10px);
+    opacity: 0;
+}
 </style>

+ 53 - 62
frontend/yarn.lock

@@ -1490,10 +1490,10 @@
   resolved "https://registry.npm.taobao.org/@types/range-parser/download/@types/range-parser-1.2.3.tgz?cache=0&sync_timestamp=1613379955500&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40types%2Frange-parser%2Fdownload%2F%40types%2Frange-parser-1.2.3.tgz#7ee330ba7caafb98090bece86a5ee44115904c2c"
   integrity sha1-fuMwunyq+5gJC+zoal7kQRWQTCw=
 
-"@types/semver@^7.3.9":
-  version "7.3.9"
-  resolved "https://registry.yarnpkg.com/@types/semver/-/semver-7.3.9.tgz#152c6c20a7688c30b967ec1841d31ace569863fc"
-  integrity sha512-L/TMpyURfBkf+o/526Zb6kd/tchUP3iBDEPjqjb+U2MAJhVRxxrmr2fwpe08E7QsV7YLcpq0tUaQ9O9x97ZIxQ==
+"@types/semver@^7.3.10":
+  version "7.3.10"
+  resolved "https://registry.yarnpkg.com/@types/semver/-/semver-7.3.10.tgz#5f19ee40cbeff87d916eedc8c2bfe2305d957f73"
+  integrity sha512-zsv3fsC7S84NN6nPK06u79oWgrPVd0NvOyqgghV1haPaFcVxIrP4DLomRwGAXk0ui4HZA7mOcSFL98sMVW9viw==
 
 "@types/serve-static@*":
   version "1.13.9"
@@ -2227,14 +2227,14 @@ ansi-regex@^3.0.0:
   integrity sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=
 
 ansi-regex@^4.1.0:
-  version "4.1.0"
-  resolved "https://registry.npm.taobao.org/ansi-regex/download/ansi-regex-4.1.0.tgz#8b9f8f08cf1acb843756a839ca8c7e3168c51997"
-  integrity sha1-i5+PCM8ay4Q3Vqg5yox+MWjFGZc=
+  version "4.1.1"
+  resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-4.1.1.tgz#164daac87ab2d6f6db3a29875e2d1766582dabed"
+  integrity "sha1-Fk2qyHqy1vbbOimHXi0XZlgtq+0= sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g=="
 
 ansi-regex@^5.0.0:
-  version "5.0.0"
-  resolved "https://registry.npm.taobao.org/ansi-regex/download/ansi-regex-5.0.0.tgz#388539f55179bf39339c81af30a654d69f87cb75"
-  integrity sha1-OIU59VF5vzkznIGvMKZU1p+Hy3U=
+  version "5.0.1"
+  resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304"
+  integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==
 
 ansi-styles@^2.2.1:
   version "2.2.1"
@@ -2477,9 +2477,9 @@ async-validator@^3.0.3:
   integrity sha512-DDmKA7sdSAJtTVeNZHrnr2yojfFaoeW8MfQN8CeuXg8DDQHTqKk9Fdv38dSvnesHoO8MUwMI2HphOeSyIF+wmQ==
 
 async@^2.6.2:
-  version "2.6.3"
-  resolved "https://registry.npm.taobao.org/async/download/async-2.6.3.tgz#d72625e2344a3656e3a3ad4fa749fa83299d82ff"
-  integrity sha1-1yYl4jRKNlbjo61Pp0n6gymdgv8=
+  version "2.6.4"
+  resolved "https://registry.yarnpkg.com/async/-/async-2.6.4.tgz#706b7ff6084664cd7eae713f6f965433b5504221"
+  integrity "sha1-cGt/9ghGZM1+rnE/b5ZUM7VQQiE= sha512-mzo5dfJYwAn29PeiJ0zvwTo04zj8HDJj0Mn8TD7sno7q12prdbnasKJHhkm2c1LgrhlJ0teaea8860oxi51mGA=="
   dependencies:
     lodash "^4.17.14"
 
@@ -3447,10 +3447,10 @@ commander@^7.2.0:
   resolved "https://registry.yarnpkg.com/commander/-/commander-7.2.0.tgz#a36cb57d0b501ce108e4d20559a150a391d97ab7"
   integrity sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==
 
-commander@^9.2.0:
-  version "9.2.0"
-  resolved "https://registry.yarnpkg.com/commander/-/commander-9.2.0.tgz#6e21014b2ed90d8b7c9647230d8b7a94a4a419a9"
-  integrity sha512-e2i4wANQiSXgnrBlIatyHtP1odfUp0BbV5Y5nEGbxtIrStkEOAAzCUirvLBNXHLr7kwLvJl6V+4V3XV9x7Wd9w==
+commander@^9.3.0:
+  version "9.4.0"
+  resolved "https://registry.yarnpkg.com/commander/-/commander-9.4.0.tgz#bc4a40918fefe52e22450c111ecd6b7acce6f11c"
+  integrity sha512-sRPT+umqkz90UA8M1yqYfnHlZA7fF6nSphDtxeywPZ49ysjxDQybzk13CL+mXekDRG92skbcqCLVovuCusNmFw==
 
 commander@~2.19.0:
   version "2.19.0"
@@ -4626,11 +4626,9 @@ events@^3.0.0:
   integrity sha1-Mala0Kkk4tLEGagTrrLE6HjqdAA=
 
 eventsource@^1.0.7:
-  version "1.0.7"
-  resolved "https://registry.npm.taobao.org/eventsource/download/eventsource-1.0.7.tgz#8fbc72c93fcd34088090bc0a4e64f4b5cee6d8d0"
-  integrity sha1-j7xyyT/NNAiAkLwKTmT0tc7m2NA=
-  dependencies:
-    original "^1.0.0"
+  version "1.1.2"
+  resolved "https://registry.yarnpkg.com/eventsource/-/eventsource-1.1.2.tgz#bc75ae1c60209e7cb1541231980460343eaea7c2"
+  integrity "sha1-vHWuHGAgnnyxVBIxmARgND6up8I= sha512-xAH3zWhgO2/3KIniEKYPr8plNSzlGINOUqYj0m0u7AB81iRw8b/3E73W6AuU+6klLbaSFmZnaETQ2lXPfAydrA=="
 
 evp_bytestokey@^1.0.0, evp_bytestokey@^1.0.3:
   version "1.0.3"
@@ -5019,9 +5017,9 @@ flush-write-stream@^1.0.0:
     readable-stream "^2.3.6"
 
 follow-redirects@^1.0.0:
-  version "1.13.3"
-  resolved "https://registry.npm.taobao.org/follow-redirects/download/follow-redirects-1.13.3.tgz#e5598ad50174c1bc4e872301e82ac2cd97f90267"
-  integrity sha1-5VmK1QF0wbxOhyMB6CrCzZf5Amc=
+  version "1.15.1"
+  resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.1.tgz#0ca6a452306c9b276e4d3127483e29575e207ad5"
+  integrity "sha1-DKakUjBsmyduTTEnSD4pV14getU= sha512-yLAMQs+k0b2m7cVxpS1VKJVvoz7SS9Td1zss3XRwXj+ZDH00RJgnuLx7E44wx02kQLrdM3aOOy+FpzS7+8OizA=="
 
 follow-redirects@^1.14.0:
   version "1.15.0"
@@ -5272,10 +5270,10 @@ globals@^12.1.0:
   dependencies:
     type-fest "^0.8.1"
 
-globby@^13.1.1:
-  version "13.1.1"
-  resolved "https://registry.yarnpkg.com/globby/-/globby-13.1.1.tgz#7c44a93869b0b7612e38f22ed532bfe37b25ea6f"
-  integrity sha512-XMzoDZbGZ37tufiv7g0N4F/zp3zkwdFtVbV3EHsVl1KQr4RPLfNoT068/97RPshz2J5xYNEjLKKBKaGHifBd3Q==
+globby@^13.1.2:
+  version "13.1.2"
+  resolved "https://registry.yarnpkg.com/globby/-/globby-13.1.2.tgz#29047105582427ab6eca4f905200667b056da515"
+  integrity sha512-LKSDZXToac40u8Q1PQtZihbNdTYSNMuWe+K5l+oa6KgDzSvVrHXlJy40hUP522RjAIoNLJYBJi7ow+rbFpIhHQ==
   dependencies:
     dir-glob "^3.0.1"
     fast-glob "^3.2.11"
@@ -6933,9 +6931,9 @@ minimist-options@4.1.0:
     kind-of "^6.0.3"
 
 minimist@^1.2.0, minimist@^1.2.5:
-  version "1.2.5"
-  resolved "https://registry.npm.taobao.org/minimist/download/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602"
-  integrity sha1-Z9ZgFLZqaoqqDAg8X9WN9OTpdgI=
+  version "1.2.6"
+  resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.6.tgz#8637a5b759ea0d6e98702cfb3a9283323c93af44"
+  integrity "sha1-hjelt1nqDW6YcCz7OpKDMjyTr0Q= sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q=="
 
 minipass-collect@^1.0.2:
   version "1.0.2"
@@ -7010,9 +7008,9 @@ mkdirp@^1.0.3:
   integrity sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==
 
 moment@^2.10.2, moment@^2.21.0, moment@^2.24.0:
-  version "2.29.1"
-  resolved "https://registry.yarnpkg.com/moment/-/moment-2.29.1.tgz#b2be769fa31940be9eeea6469c075e35006fa3d3"
-  integrity sha512-kHmoybcPV8Sqy59DwNDY3Jefr64lK/by/da0ViFcuA4DH0vQg5Q6Ze5VimxkfQNSC+Mls/Kx53s7TjP1RhFEDQ==
+  version "2.29.4"
+  resolved "https://registry.yarnpkg.com/moment/-/moment-2.29.4.tgz#3dbe052889fe7c1b2ed966fcb3a77328964ef108"
+  integrity "sha1-Pb4FKIn+fBsu2Wb8s6dzKJZO8Qg= sha512-5LC9SOxjSc2HF6vO2CyuTDNivEdoz2IvyJJGj6X8DJ0eFyfszE0QiEd+iXmBvUP3WHxSjFH/vIsA0EN00cgr8w=="
 
 move-concurrently@^1.0.1:
   version "1.0.1"
@@ -7546,13 +7544,6 @@ ora@^3.4.0:
     strip-ansi "^5.2.0"
     wcwidth "^1.0.1"
 
-original@^1.0.0:
-  version "1.0.2"
-  resolved "https://registry.npm.taobao.org/original/download/original-1.0.2.tgz#e442a61cffe1c5fd20a65f3261c26663b303f25f"
-  integrity sha1-5EKmHP/hxf0gpl8yYcJmY7MD8l8=
-  dependencies:
-    url-parse "^1.4.3"
-
 os-browserify@^0.3.0:
   version "0.3.0"
   resolved "https://registry.npm.taobao.org/os-browserify/download/os-browserify-0.3.0.tgz#854373c7f5c2315914fc9bfc6bd8238fdda1ec27"
@@ -9149,9 +9140,9 @@ shebang-regex@^3.0.0:
   integrity sha1-rhbxZE2HPsrYQ7AwexQzYtTEIXI=
 
 shell-quote@^1.6.1:
-  version "1.7.2"
-  resolved "https://registry.npm.taobao.org/shell-quote/download/shell-quote-1.7.2.tgz#67a7d02c76c9da24f99d20808fcaded0e0e04be2"
-  integrity sha1-Z6fQLHbJ2iT5nSCAj8re0ODgS+I=
+  version "1.7.3"
+  resolved "https://registry.yarnpkg.com/shell-quote/-/shell-quote-1.7.3.tgz#aa40edac170445b9a431e17bb62c0b881b9c4123"
+  integrity "sha1-qkDtrBcERbmkMeF7tiwLiBucQSM= sha512-Vpfqwm4EnqGdlsBFNmHhxhElJYrdfcxPThu+ryKS5J8L/fhAwLazFZtq+S+TWZ9ANj2piSQLGj6NQg+lKPmxrw=="
 
 signal-exit@^3.0.0, signal-exit@^3.0.2:
   version "3.0.3"
@@ -9397,9 +9388,9 @@ ssri@^6.0.1:
     figgy-pudding "^3.5.1"
 
 ssri@^7.0.0, ssri@^7.1.0:
-  version "7.1.0"
-  resolved "https://registry.npm.taobao.org/ssri/download/ssri-7.1.0.tgz#92c241bf6de82365b5c7fb4bd76e975522e1294d"
-  integrity sha1-ksJBv23oI2W1x/tL126XVSLhKU0=
+  version "7.1.1"
+  resolved "https://registry.yarnpkg.com/ssri/-/ssri-7.1.1.tgz#33e44f896a967158e3c63468e47ec46613b95b5f"
+  integrity sha512-w+daCzXN89PseTL99MkA+fxJEcU3wfaE/ah0i0lnOlpG1CYLJ2ZjzEry68YBKfLs4JfoTShrTEsJkAZuNZ/stw==
   dependencies:
     figgy-pudding "^3.5.1"
     minipass "^3.1.1"
@@ -9788,9 +9779,9 @@ terser-webpack-plugin@^2.3.6:
     webpack-sources "^1.4.3"
 
 terser@^4.1.2, terser@^4.6.12:
-  version "4.8.0"
-  resolved "https://registry.npm.taobao.org/terser/download/terser-4.8.0.tgz#63056343d7c70bb29f3af665865a46fe03a0df17"
-  integrity sha1-YwVjQ9fHC7KfOvZlhlpG/gOg3xc=
+  version "4.8.1"
+  resolved "https://registry.yarnpkg.com/terser/-/terser-4.8.1.tgz#a00e5634562de2239fd404c649051bf6fc21144f"
+  integrity "sha1-oA5WNFYt4iOf1ATGSQUb9vwhFE8= sha512-4GnLC0x667eJG0ewJTa6z/yXrbLGv80D9Ru6HIpCQmO+Q4PfEtBFi0ObSckqwL6VyQv/7ENJieXHo2ANmdQwgw=="
   dependencies:
     commander "^2.20.0"
     source-map "~0.6.1"
@@ -10159,10 +10150,10 @@ url-loader@^2.2.0:
     mime "^2.4.4"
     schema-utils "^2.5.0"
 
-url-parse@^1.4.3, url-parse@^1.4.7:
-  version "1.5.3"
-  resolved "https://registry.yarnpkg.com/url-parse/-/url-parse-1.5.3.tgz#71c1303d38fb6639ade183c2992c8cc0686df862"
-  integrity sha512-IIORyIQD9rvj0A4CLWsHkBBJuNqWpFQe224b6j9t/ABmquIS0qDU2pY6kl6AuOrL5OkCXHMCFNe1jBcuAggjvQ==
+url-parse@^1.4.7:
+  version "1.5.10"
+  resolved "https://registry.yarnpkg.com/url-parse/-/url-parse-1.5.10.tgz#9d3c2f736c1d75dd3bd2be507dcc111f1e2ea9c1"
+  integrity sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==
   dependencies:
     querystringify "^2.1.1"
     requires-port "^1.0.0"
@@ -10809,23 +10800,23 @@ yargs@^16.0.0:
     y18n "^5.0.5"
     yargs-parser "^20.2.2"
 
-yarn-audit-fix@^9.1.2:
-  version "9.3.1"
-  resolved "https://registry.yarnpkg.com/yarn-audit-fix/-/yarn-audit-fix-9.3.1.tgz#cd2ebdbcab13e38dc067134c7c2321ba311555c0"
-  integrity sha512-JM7aIHEwL0YoXoadOOpZQOCmHIRvt7jA7OBGNnOjRXKwdyvdc4EljjaZB9EjQ6xpj3NNRWoHebApjPUOx2E0tg==
+yarn-audit-fix@^9.3.2:
+  version "9.3.2"
+  resolved "https://registry.yarnpkg.com/yarn-audit-fix/-/yarn-audit-fix-9.3.2.tgz#9268aeaf70faafd6d8b8a71d0b8c8d97d6b809ec"
+  integrity sha512-hRPu2FRTLF5kL+fgq6NZDVgvGV7zEO6ghgfXoFmseDtDzqBIfKbGVNL+XqJ1fIil70x6XyrQwyARyyrMZtxpaw==
   dependencies:
     "@types/find-cache-dir" "^3.2.1"
     "@types/fs-extra" "^9.0.13"
     "@types/lodash-es" "^4.17.6"
-    "@types/semver" "^7.3.9"
+    "@types/semver" "^7.3.10"
     "@types/yarnpkg__lockfile" "^1.1.5"
     "@yarnpkg/lockfile" "^1.1.0"
     chalk "^5.0.1"
-    commander "^9.2.0"
+    commander "^9.3.0"
     find-cache-dir "^3.3.2"
     find-up "^6.3.0"
     fs-extra "^10.1.0"
-    globby "^13.1.1"
+    globby "^13.1.2"
     js-yaml "^4.1.0"
     lodash-es "^4.17.21"
     pkg-dir "^6.0.1"

+ 2 - 1
go.mod

@@ -1,6 +1,6 @@
 module github.com/0xJacky/Nginx-UI
 
-go 1.17
+go 1.18
 
 require (
 	github.com/dustin/go-humanize v1.0.0
@@ -28,6 +28,7 @@ require (
 	github.com/StackExchange/wmi v1.2.1 // indirect
 	github.com/cenkalti/backoff/v4 v4.1.0 // indirect
 	github.com/creack/pty v1.1.18 // indirect
+	github.com/emirpasic/gods v1.18.1 // indirect
 	github.com/gin-contrib/sse v0.1.0 // indirect
 	github.com/go-ole/go-ole v1.2.5 // indirect
 	github.com/golang/protobuf v1.3.4 // indirect

+ 2 - 0
go.sum

@@ -97,6 +97,8 @@ github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25Kn
 github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs=
 github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU=
 github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I=
+github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc=
+github.com/emirpasic/gods v1.18.1/go.mod h1:8tpGGwCnJ5H4r6BWwaV6OrWmMoPhUl5jm/FMNAnJvWQ=
 github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
 github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
 github.com/exoscale/egoscale v0.46.0/go.mod h1:mpEXBpROAa/2i5GC0r33rfxG+TxSEka11g1PIXt9+zc=

+ 0 - 4
server/template/http-conf

@@ -4,10 +4,6 @@ server {
 
     server_name {{ server_name }};
 
-    root ;
-
-    index ;
-
     location /.well-known {
         proxy_set_header Host $host;
         proxy_set_header X-Real_IP $remote_addr;

+ 0 - 4
server/template/https-conf

@@ -16,10 +16,6 @@ server {
     ssl_certificate {{ ssl_certificate }};
     ssl_certificate_key {{ ssl_certificate_key }};
 
-    root ;
-
-    index ;
-
     location /.well-known {
         proxy_set_header Host $host;
         proxy_set_header X-Real_IP $remote_addr;

+ 78 - 0
server/test/nextcloud_ngx.conf

@@ -0,0 +1,78 @@
+# this is a comments
+upstream my-api {
+    server 127.0.0.1:9001;
+    server 127.0.0.1:9002;
+}
+
+# this is a comments
+server {
+# this is a comments
+    listen	8443 ssl http2;
+    listen	[::]:8443 ssl http2;
+
+    server_name	cloud.jackyu.cn;
+# this is a comments
+    ssl_certificate	/etc/nginx/ssl/jackyu.cn/alpha/jackyu.cn_server_cert.pem;
+    ssl_certificate_key	/etc/nginx/ssl/jackyu.cn/alpha/jackyu.cn_key.pem;
+
+    fastcgi_hide_header X-Powered-By;  # Remove X-Powered-By, which is an information leak
+
+    location = /robots.txt {
+        allow all;
+        log_not_found off;
+        access_log off;
+    }
+
+    # Make a regex exception for `/.well-known` so that clients can still
+    # access it despite the existence of the regex rule
+    # `location ~ /(\.|autotest|...)` which would otherwise handle requests
+    # for `/.well-known`.
+    location = /.well-known/carddav { return 301 /remote.php/dav/; }
+
+    location ^~ /.well-known
+
+    {
+        # The rules in this block are an adaptation of the rules
+        # in `.htaccess` that concern `/.well-known`.
+
+        location = /.well-known/carddav { return 301 /remote.php/dav/; }
+        location = /.well-known/caldav  { return 301 /remote.php/dav/; }
+
+        location /.well-known/acme-challenge    { try_files $uri $uri/ =404; }
+
+        location /.well-known/pki-validation    {
+            try_files $uri $uri/ =404;
+        }
+
+        # Let Nextcloud's API for `/.well-known` URIs handle all other
+        # requests by passing them to the front-end controller.
+        return 301 /index.php$request_uri;
+    }
+
+    # set max upload size
+    client_max_body_size 8192M;
+    fastcgi_buffers 64 4K;
+
+    # Enable gzip but do not remove ETag headers
+    gzip on; gzip_vary on; location /x/ {} gzip_comp_level 4;
+    gzip_min_length 256;gzip_proxied expired no-cache no-store private no_last_modified no_etag auth;
+    gzip_types application/atom+xml application/javascript application/json application/ld+json application/manifest+json application/rss+xml application/vnd.geo+json application/vnd.ms-fontobject application/x-font-ttf application/x-web-app-manifest+json application/xhtml+xml application/xml font/opentype image/bmp image/svg+xml image/x-icon text/cache-manifest text/css text/plain text/vcard text/vnd.rim.location.xloc text/vtt text/x-component text/x-cross-domain-policy;
+
+    # Uncomment if your server is build with the ngx_pagespeed module
+    # This module is currently not supported.
+    #pagespeed off;
+    location / {
+        if ( $http_user_agent ~ ^DavClnt ) {
+            return 302 /remote.php/webdav/$is_args$args;
+        }
+
+        proxy_set_header Host $host;
+        proxy_set_header X-Real-IP $remote_addr;
+        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
+        proxy_set_header X-Forwarded-Proto $scheme;
+        proxy_http_version 1.1;
+        proxy_intercept_errors on;
+
+        proxy_pass http://172.17.0.1:7000;
+    }
+}

+ 42 - 0
server/test/ngx_conf_parse_test.go

@@ -0,0 +1,42 @@
+package test
+
+import (
+	"fmt"
+	"github.com/0xJacky/Nginx-UI/server/tool/nginx"
+	"testing"
+)
+
+func TestNgxConfParse(t *testing.T) {
+	c, err := nginx.ParseNgxConfig("nextcloud_ngx.conf")
+
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	fmt.Println(c.FileName)
+	// directive in root
+	fmt.Println("Upstream")
+	for _, u := range c.Upstreams {
+		fmt.Println("upstream name", u.Name)
+		fmt.Printf("comments\n%v", u.Comments)
+		for _, d := range u.Directives {
+			fmt.Println("u.Directives.d", d)
+		}
+	}
+	fmt.Println("==========================")
+	fmt.Println("Servers")
+	for _, s := range c.Servers {
+		fmt.Printf("comments\n%v", s.Comments)
+		for _, d := range s.Directives {
+			fmt.Println(d)
+		}
+		// locations
+		for _, location := range s.Locations {
+			fmt.Printf("comments\n%v", location.Comments)
+			fmt.Println("path", location.Path)
+			fmt.Println("content", location.Content)
+			fmt.Println("==========================")
+		}
+	}
+
+}

+ 129 - 0
server/tool/nginx/parse.go

@@ -0,0 +1,129 @@
+package nginx
+
+import (
+	"bufio"
+	"github.com/emirpasic/gods/stacks/linkedliststack"
+	"github.com/pkg/errors"
+	"os"
+	"strings"
+	"unicode"
+)
+
+const (
+	Server       = "server"
+	Location     = "location"
+	Upstream     = "upstream"
+	CommentStart = "#"
+	Empty        = ""
+)
+
+func matchParentheses(stack *linkedliststack.Stack, v int32) {
+	if v == '{' {
+		stack.Push(v)
+	} else if v == '}' {
+		// stack is not empty and the top is == '{'
+		if top, ok := stack.Peek(); ok && top == '{' {
+			stack.Pop()
+		} else {
+			// fail
+			stack.Push(v)
+		}
+	}
+}
+
+func parseDirective(scanner *bufio.Scanner) (d NgxDirective) {
+	text := strings.TrimSpace(scanner.Text())
+	// escape empty line or comment line
+	if len(text) < 1 {
+		return
+	}
+
+	if text[0] == '#' {
+		d.Directive = "#"
+		d.Params = strings.TrimLeft(text, "#")
+		return
+	}
+
+	sep := len(text) - 1
+	for k, v := range text {
+		if unicode.IsSpace(v) {
+			sep = k
+			break
+		}
+	}
+
+	d.Directive = text[0:sep]
+	d.Params = text[sep:]
+
+	stack := linkedliststack.New()
+
+	if d.Directive == Server || d.Directive == Upstream || d.Directive == Location {
+		// { } in one line
+		// location = /.well-known/carddav { return 301 /remote.php/dav/; }
+		if strings.Contains(d.Params, "{") {
+			for _, v := range d.Params {
+				matchParentheses(stack, v)
+			}
+
+			if stack.Empty() {
+				return
+			}
+		}
+
+		// location ^~ /.well-known {
+		// location ^~ /.well-known
+		// {
+		// location ^~ /.well-known
+		//
+		//    {
+		// { } not in one line
+		for scanner.Scan() {
+			text = strings.TrimSpace(scanner.Text())
+			// escape empty line
+			if text == "" {
+				continue
+			}
+			d.Params += "\n" + scanner.Text()
+			for _, v := range text {
+				matchParentheses(stack, v)
+				if stack.Empty() {
+					break
+				}
+			}
+			if stack.Empty() {
+				break
+			}
+		}
+	}
+	d.Params = strings.TrimSpace(d.Params)
+	return
+}
+
+func ParseNgxConfig(filename string) (c *NgxConfig, err error) {
+	file, err := os.Open(filename)
+	if err != nil {
+		return nil, errors.Wrap(err, "error open file in ParseNgxConfig")
+	}
+	defer file.Close()
+
+	scanner := bufio.NewScanner(file)
+	c = NewNgxConfig(filename)
+	for scanner.Scan() {
+		d := parseDirective(scanner)
+		paramsScanner := bufio.NewScanner(strings.NewReader(d.Params))
+		switch d.Directive {
+		case Server:
+			c.parseServer(paramsScanner)
+		case Upstream:
+			c.parseUpstream(paramsScanner)
+		case CommentStart:
+			c.commentQueue.Enqueue(d.Params)
+		}
+	}
+
+	if err = scanner.Err(); err != nil {
+		return nil, errors.Wrap(err, "error scanner in ParseNgxConfig")
+	}
+
+	return c, nil
+}

+ 111 - 0
server/tool/nginx/tokenize.go

@@ -0,0 +1,111 @@
+package nginx
+
+import (
+	"bufio"
+	"regexp"
+	"strings"
+	"unicode"
+)
+
+func (c *NgxConfig) parseServer(scanner *bufio.Scanner) {
+	server := NewNgxServer()
+	server.Directives = make(NgxDirectives)
+	for scanner.Scan() {
+		d := parseDirective(scanner)
+		switch d.Directive {
+		case Location:
+			server.parseLocation(d.Params)
+		case CommentStart:
+			server.commentQueue.Enqueue(d.Params)
+		default:
+			server.parseDirective(d)
+		}
+	}
+
+	// attach comments which are over the current server
+	server.Comments = c.commentQueue.DequeueAllComments()
+
+	c.Servers = append(c.Servers, *server)
+}
+
+func (c *NgxConfig) parseUpstream(scanner *bufio.Scanner) {
+	upstream := NgxUpstream{}
+	upstream.Directives = make(NgxDirectives)
+	d := NgxDirective{}
+	for scanner.Scan() {
+		text := strings.TrimSpace(scanner.Text())
+		// escape empty line or comment line
+		if len(text) < 1 || text[0] == '#' {
+			return
+		}
+
+		sep := len(text) - 1
+		for k, v := range text {
+			if unicode.IsSpace(v) {
+				sep = k
+				break
+			}
+		}
+
+		d.Directive = text[0:sep]
+		d.Params = strings.Trim(text[sep:], ";")
+
+		if d.Directive == Server {
+			upstream.Directives[d.Directive] = append(upstream.Directives[d.Directive], d)
+		} else if upstream.Name == "" {
+			upstream.Name = d.Directive
+		}
+	}
+	// attach comments which are over the current upstream
+	upstream.Comments = c.commentQueue.DequeueAllComments()
+
+	c.Upstreams = append(c.Upstreams, upstream)
+}
+
+func (s *NgxServer) parseDirective(d NgxDirective) {
+	orig := d.Orig()
+	// handle inline comments
+	str, comments, _ := strings.Cut(orig, "#")
+
+	regExp := regexp.MustCompile("(\\S+?)\\s+{?(.+?)[;|}]")
+	matchSlice := regExp.FindAllStringSubmatch(str, -1)
+
+	for k, v := range matchSlice {
+		// [[gzip_min_length 256; gzip_min_length 256] [gzip_proxied expired no-cache no-store private no_last_modified no_etag auth; gzip_proxied expired no-cache no-store private no_last_modified no_etag auth] [gzip on; gzip on] [gzip_vary on; gzip_vary on] [location /x/ {} location /x/ {] [gzip_comp_level 4; gzip_comp_level 4]]
+		if len(v) > 0 {
+			scanner := bufio.NewScanner(strings.NewReader(v[0]))
+			if scanner.Scan() {
+				d = parseDirective(scanner)
+				// inline location
+				if d.Directive == Location {
+					s.parseLocation(d.Orig())
+				} else {
+
+					if k == 0 {
+						d.Comments = s.commentQueue.DequeueAllComments()
+					} else if k == len(matchSlice)-1 {
+						d.Comments = comments
+					}
+
+					// trim right ';'
+					d.TrimParams()
+					// map[directive]=>[]Params
+					s.Directives[d.Directive] = append(s.Directives[d.Directive], d)
+				}
+
+			}
+		}
+	}
+}
+
+func (s *NgxServer) parseLocation(str string) {
+	path, content, _ := strings.Cut(str, "{")
+	content = strings.TrimSpace(content)
+	content = strings.Trim(content, "}")
+	location := NgxLocation{
+		Path:    path,
+		Content: content,
+	}
+	location.Comments = s.commentQueue.DequeueAllComments()
+	s.Locations = append(s.Locations, location)
+}

+ 74 - 0
server/tool/nginx/type.go

@@ -0,0 +1,74 @@
+package nginx
+
+import (
+    "github.com/emirpasic/gods/queues/linkedlistqueue"
+    "strings"
+)
+
+type CommentQueue struct {
+    *linkedlistqueue.Queue
+}
+
+type NgxConfig struct {
+    FileName     string        `json:"file_name"`
+    Upstreams    []NgxUpstream `json:"upstreams"`
+    Servers      []NgxServer   `json:"ngx_server"`
+    commentQueue *CommentQueue
+}
+
+type NgxServer struct {
+    ServerName   string        `json:"server_name"`
+    Directives   NgxDirectives `json:"directives"`
+    Locations    []NgxLocation `json:"locations"`
+    Comments     string        `json:"comments"`
+    commentQueue *CommentQueue
+}
+
+type NgxUpstream struct {
+    Name       string        `json:"name"`
+    Directives NgxDirectives `json:"directives"`
+    Comments   string        `json:"comments"`
+}
+
+type NgxDirective struct {
+    Directive string `json:"directive"`
+    Params    string `json:"params"`
+    Comments  string `json:"comments"`
+}
+
+type NgxDirectives map[string][]NgxDirective
+
+type NgxLocation struct {
+    Path     string `json:"path"`
+    Content  string `json:"content"`
+    Comments string `json:"comments"`
+}
+
+func (c *CommentQueue) DequeueAllComments() (comments string) {
+    for !c.Empty() {
+        comment, ok := c.Dequeue()
+
+        if ok {
+            comments += strings.TrimSpace(comment.(string)) + "\n"
+        }
+    }
+
+    return
+}
+
+func (d *NgxDirective) Orig() string {
+    return d.Directive + " " + d.Params
+}
+
+func (d *NgxDirective) TrimParams() {
+    d.Params = strings.TrimRight(strings.TrimSpace(d.Params), ";")
+    return
+}
+
+func NewNgxServer() *NgxServer {
+    return &NgxServer{commentQueue: &CommentQueue{linkedlistqueue.New()}}
+}
+
+func NewNgxConfig(filename string) *NgxConfig {
+    return &NgxConfig{FileName: filename, commentQueue: &CommentQueue{linkedlistqueue.New()}}
+}