refactor: nginx conf parser #45

This commit is contained in:
0xJacky 2023-01-04 14:01:14 +08:00
parent b7d5590714
commit 5cc9068f5f
No known key found for this signature in database
GPG key ID: B6E4A6E4A561BAF0
27 changed files with 942 additions and 1040 deletions

View file

@ -91,12 +91,16 @@ Nginx 网络管理界面,由 [0xJacky](https://jackyu.cn/) 与 [Hintay](https
我们欢迎您将项目翻译成任何语言。 我们欢迎您将项目翻译成任何语言。
### 构建基于 ### 构建基于
- [The Go Programming Language](https://go.dev)
- [The Go Programming Language](https://go.dev/)
- [Gin Web Framework](https://gin-gonic.com) - [Gin Web Framework](https://gin-gonic.com)
- [GORM](http://gorm.io/index.html) - [GORM](http://gorm.io)
- [Vue 2](https://vuejs.org) - [Vue 3](https://v3.vuejs.org)
- [vue-gettext](https://github.com/Polyconseil/vue-gettext) - [Vite](https://vitejs.dev)
- [TypeScript](https://www.typescriptlang.org/)
- [Ant Design Vue](https://antdv.com)
- [vue3-gettext](https://github.com/jshmrtn/vue3-gettext)
- [vue3-ace-editor](https://github.com/CarterLi/vue3-ace-editor)
- [Gonginx](https://github.com/tufanbarisyildirim/gonginx)
## 入门指南 ## 入门指南

View file

@ -93,12 +93,16 @@ Nginx 網路管理介面,由 [0xJacky](https://jackyu.cn/) 與 [Hintay](https
我們歡迎您將專案翻譯成任何語言。 我們歡迎您將專案翻譯成任何語言。
### 構建基於 ### 構建基於
- [The Go Programming Language](https://go.dev)
- [The Go Programming Language](https://go.dev/)
- [Gin Web Framework](https://gin-gonic.com) - [Gin Web Framework](https://gin-gonic.com)
- [GORM](http://gorm.io/index.html) - [GORM](http://gorm.io)
- [Vue 2](https://vuejs.org) - [Vue 3](https://v3.vuejs.org)
- [vue-gettext](https://github.com/Polyconseil/vue-gettext) - [Vite](https://vitejs.dev)
- [TypeScript](https://www.typescriptlang.org/)
- [Ant Design Vue](https://antdv.com)
- [vue3-gettext](https://github.com/jshmrtn/vue3-gettext)
- [vue3-ace-editor](https://github.com/CarterLi/vue3-ace-editor)
- [Gonginx](https://github.com/tufanbarisyildirim/gonginx)
## 入門指南 ## 入門指南

View file

@ -99,6 +99,7 @@ We welcome translations into any language.
- [Ant Design Vue](https://antdv.com) - [Ant Design Vue](https://antdv.com)
- [vue3-gettext](https://github.com/jshmrtn/vue3-gettext) - [vue3-gettext](https://github.com/jshmrtn/vue3-gettext)
- [vue3-ace-editor](https://github.com/CarterLi/vue3-ace-editor) - [vue3-ace-editor](https://github.com/CarterLi/vue3-ace-editor)
- [Gonginx](https://github.com/tufanbarisyildirim/gonginx)
## Getting Started ## Getting Started

View file

@ -39,7 +39,7 @@
"less": "^4.1.3", "less": "^4.1.3",
"typescript": "^4.6.4", "typescript": "^4.6.4",
"unplugin-vue-components": "^0.22.9", "unplugin-vue-components": "^0.22.9",
"vite": "^3.2.3", "vite": "^4.0.3",
"vite-plugin-html": "^3.2.0", "vite-plugin-html": "^3.2.0",
"vue-tsc": "^1.0.9" "vue-tsc": "^1.0.9"
} }

View file

@ -74,16 +74,6 @@ export const routes = [
hideChildren: true hideChildren: true
} }
}, },
{
path: 'config/:dir*',
name: () => $gettext('Manage Configs'),
component: () => import('@/views/config/Config.vue'),
meta: {
icon: FileOutlined,
hideChildren: true,
hiddenInSidebar: true
}
},
{ {
path: 'config/:name+/edit', path: 'config/:name+/edit',
name: () => $gettext('Edit Configuration'), name: () => $gettext('Edit Configuration'),

View file

@ -18,7 +18,7 @@ const table = ref(null)
const route = useRoute() const route = useRoute()
const basePath = computed(() => { const basePath = computed(() => {
let dir = route?.params?.dir ? (route?.params?.dir as string[])?.join('/') : '' let dir = route?.query?.dir ?? ''
if (dir) dir += '/' if (dir) dir += '/'
return dir return dir
}) })
@ -54,7 +54,9 @@ watch(get_params, () => {
}) })
} else { } else {
$router.push({ $router.push({
path: '/config/' + basePath + r query: {
dir: basePath + r
}
}) })
} }
}" }"

View file

@ -30,7 +30,7 @@ const columns = [{
template.push(<Badge status="success"/>) template.push(<Badge status="success"/>)
template.push($gettext('Enabled')) template.push($gettext('Enabled'))
} else { } else {
template.push(<Badge status="error"/>) template.push(<Badge status="warning"/>)
template.push($gettext('Disabled')) template.push($gettext('Disabled'))
} }
return h('div', template) return h('div', template)

View file

@ -129,7 +129,7 @@ const issue_cert = async (server_name: string, callback: Function) => {
} }
const no_server_name = computed(() => { const no_server_name = computed(() => {
return props.directivesMap['server_name'].length === 0 return props.directivesMap['server_name']?.length === 0
}) })
const name = computed(() => { const name = computed(() => {

View file

@ -24,8 +24,8 @@ function add() {
function save() { function save() {
adding.value = false adding.value = false
if (mode.value === If) { if (mode.value === 'multi-line') {
directive.directive = If directive.directive = ''
} }
if (props.idx) { if (props.idx) {
@ -42,19 +42,19 @@ function save() {
<div> <div>
<div class="add-directive-temp" v-if="adding"> <div class="add-directive-temp" v-if="adding">
<a-form-item> <a-form-item>
<a-select v-model:value="mode" default-value="default" style="width: 150px"> <a-select v-model:value="mode" default-value="default" style="width: 180px">
<a-select-option value="default"> <a-select-option value="default">
{{ $gettext('Single Directive') }} {{ $gettext('Single Directive') }}
</a-select-option> </a-select-option>
<a-select-option value="if"> <a-select-option value="multi-line">
if {{ $gettext('Multi-line Directive') }}
</a-select-option> </a-select-option>
</a-select> </a-select>
</a-form-item> </a-form-item>
<a-form-item> <a-form-item>
<div class="input-wrapper"> <div class="input-wrapper">
<code-editor v-if="mode===If" default-height="100px" style="width: 100%;" <code-editor v-if="mode==='multi-line'" default-height="100px" style="width: 100%;"
v-model:content="directive.params"/> v-model:content="directive.params"/>
<a-input-group v-else compact> <a-input-group v-else compact>
<a-input style="width: 30%" :placeholder="$gettext('Directive')" <a-input style="width: 30%" :placeholder="$gettext('Directive')"
@ -73,7 +73,9 @@ function save() {
</div> </div>
<a-button block v-if="!adding" @click="add">{{ $gettext('Add Directive Below') }}</a-button> <a-button block v-if="!adding" @click="add">{{ $gettext('Add Directive Below') }}</a-button>
<a-button type="primary" v-else block @click="save" <a-button type="primary" v-else block @click="save"
:disabled="!directive.directive||!directive.params">{{ $gettext('Save Directive') }} :disabled="(mode==='default'&&(!directive.directive||!directive.params))
||(!directive.params&&mode==='multi-line')">
{{ $gettext('Save Directive') }}
</a-button> </a-button>
</div> </div>
</template> </template>

View file

@ -32,7 +32,7 @@ function onSave(idx: number) {
item-key="name" item-key="name"
class="list-group" class="list-group"
ghost-class="ghost" ghost-class="ghost"
handle=".ant-input-group-addon" handle=".anticon-holder"
> >
<template #item="{ element: directive, index }"> <template #item="{ element: directive, index }">
<directive-editor-item @click="current_idx=index" <directive-editor-item @click="current_idx=index"

View file

@ -42,8 +42,11 @@ function save() {
<template> <template>
<div class="dir-editor-item"> <div class="dir-editor-item">
<div class="input-wrapper"> <div class="input-wrapper">
<code-editor v-if="directive.directive === If" v-model:content="directive.params" <div class="code-editor-wrapper" v-if="directive.directive === ''">
defaultHeight="100px" style="width: 100%;"/> <HolderOutlined style="padding: 5px"/>
<code-editor v-model:content="directive.params"
defaultHeight="100px" style="width: 100%;"/>
</div>
<a-input v-else <a-input v-else
v-model:value="directive.params" @click="current_idx=index"> v-model:value="directive.params" @click="current_idx=index">
@ -91,6 +94,16 @@ function save() {
margin: 15px 0; margin: 15px 0;
} }
.code-editor-wrapper {
display: flex;
width: 100%;
align-items: center;
}
.anticon-holder {
cursor: grab;
}
.directive-editor-extra { .directive-editor-extra {
background-color: #fafafa; background-color: #fafafa;
padding: 10px 20px; padding: 10px 20px;

View file

@ -1 +1 @@
{"version":"1.7.0","build_id":63,"total_build":133} {"version":"1.7.0","build_id":0,"total_build":0}

View file

@ -361,20 +361,120 @@
resolved "https://registry.yarnpkg.com/@ctrl/tinycolor/-/tinycolor-3.4.1.tgz#75b4c27948c81e88ccd3a8902047bcd797f38d32" resolved "https://registry.yarnpkg.com/@ctrl/tinycolor/-/tinycolor-3.4.1.tgz#75b4c27948c81e88ccd3a8902047bcd797f38d32"
integrity sha512-ej5oVy6lykXsvieQtqZxCOaLT+xD4+QNarq78cIYISHmZXshCvROLudpQN3lfL8G0NL7plMSSK+zlyvCaIJ4Iw== integrity sha512-ej5oVy6lykXsvieQtqZxCOaLT+xD4+QNarq78cIYISHmZXshCvROLudpQN3lfL8G0NL7plMSSK+zlyvCaIJ4Iw==
"@esbuild/android-arm@0.15.13": "@esbuild/android-arm64@0.16.13":
version "0.15.13" version "0.16.13"
resolved "https://registry.yarnpkg.com/@esbuild/android-arm/-/android-arm-0.15.13.tgz#ce11237a13ee76d5eae3908e47ba4ddd380af86a" resolved "https://registry.npmmirror.com/@esbuild/android-arm64/-/android-arm64-0.16.13.tgz#1fc9bfbff0bac558008b2ad7242db1c8024d8cfd"
integrity sha512-RY2fVI8O0iFUNvZirXaQ1vMvK0xhCcl0gqRj74Z6yEiO1zAUa7hbsdwZM1kzqbxHK7LFyMizipfXT3JME+12Hw== integrity sha512-r4xetsd1ez1NF9/9R2f9Q6AlxqiZLwUqo7ICOcvEVwopVkXUcspIjEbJk0EVTgT6Cp5+ymzGPT6YNV0ievx4yA==
"@esbuild/android-arm@0.16.13":
version "0.16.13"
resolved "https://registry.npmmirror.com/@esbuild/android-arm/-/android-arm-0.16.13.tgz#df3317286eed68c727daf39c2d585625f9c2f170"
integrity sha512-JmtqThupn9Yf+FzANE+GG73ASUkssnPwOsndUElhp23685QzRK+MO1UompOlBaXV9D5FTuYcPnw7p4mCq2YbZQ==
"@esbuild/android-x64@0.16.13":
version "0.16.13"
resolved "https://registry.npmmirror.com/@esbuild/android-x64/-/android-x64-0.16.13.tgz#c34826c4bdc57c60cbfb8d5bbd2306a89225626a"
integrity sha512-hKt1bFht/Vtp0xJ0ZVzFMnPy1y1ycmM3KNnp3zsyZfQmw7nhs2WLO4vxdR5YG+6RsHKCb2zbZ3VwlC0Tij0qyA==
"@esbuild/darwin-arm64@0.16.13":
version "0.16.13"
resolved "https://registry.npmmirror.com/@esbuild/darwin-arm64/-/darwin-arm64-0.16.13.tgz#0b80c8580c262ccfb1203053201cf19c6f7b4cdb"
integrity sha512-ogrVuNi2URocrr3Ps20f075EMm9V7IeenOi9FRj4qdbT6mQlwLuP4l90PW2iBrKERx0oRkcZprEUNsz/3xd7ww==
"@esbuild/darwin-x64@0.16.13":
version "0.16.13"
resolved "https://registry.npmmirror.com/@esbuild/darwin-x64/-/darwin-x64-0.16.13.tgz#f1a6c9ea67d4eaaf4944e1cbceb800eabc6e7e74"
integrity sha512-Agajik9SBGiKD7FPXE+ExW6x3MgA/dUdpZnXa9y1tyfE4lKQx+eQiknSdrBnWPeqa9wL0AOvkhghmYhpVkyqkA==
"@esbuild/freebsd-arm64@0.16.13":
version "0.16.13"
resolved "https://registry.npmmirror.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.16.13.tgz#d1a45ac5c4a1be566c4eefbadbe5a967288ad338"
integrity sha512-KxMO3/XihBcHM+xQUM6nQZO1SgQuOsd1DCnKF1a4SIf/i5VD45vrqN3k8ePgFrEbMi7m5JeGmvNqwJXinF0a4Q==
"@esbuild/freebsd-x64@0.16.13":
version "0.16.13"
resolved "https://registry.npmmirror.com/@esbuild/freebsd-x64/-/freebsd-x64-0.16.13.tgz#ec64a31cabb08343bb4520a221324b40509dffc8"
integrity sha512-Ez15oqV1vwvZ30cVLeBW14BsWq/fdWNQGMOxxqaSJVQVLqHhvgfQ7gxGDiN9tpJdeQhqJO+Q0r02/Tce5+USNg==
"@esbuild/linux-arm64@0.16.13":
version "0.16.13"
resolved "https://registry.npmmirror.com/@esbuild/linux-arm64/-/linux-arm64-0.16.13.tgz#e8db3c3751b32ecf801751424eae43f6863a2ee7"
integrity sha512-qi5n7KwcGViyJeZeQnu8fB6dC3Mlm5PGaqSv2HhQDDx/MPvVfQGNMcv7zcBL4qk3FkuWhGVwXkjQ76x7R0PWlA==
"@esbuild/linux-arm@0.16.13":
version "0.16.13"
resolved "https://registry.npmmirror.com/@esbuild/linux-arm/-/linux-arm-0.16.13.tgz#ac0c8e9f3db8d418f588ae250e9c66ffdcf3cd82"
integrity sha512-18dLd2L3mda+iFj6sswyBMSh2UwniamD9M4DwPv8VM+9apRFlQ5IGKxBdumnTuOI4NvwwAernmUseWhYQ9k+rg==
"@esbuild/linux-ia32@0.16.13":
version "0.16.13"
resolved "https://registry.npmmirror.com/@esbuild/linux-ia32/-/linux-ia32-0.16.13.tgz#41ee9bd3b7161ab681fab6cb3990a3f5c08a9940"
integrity sha512-2489Xad9sr+6GD7nB913fUqpCsSwVwgskkQTq4Or2mZntSPYPebyJm8l1YruHo7oqYMTGV6RiwGE4gRo3H+EPQ==
"@esbuild/linux-loong64@0.14.53": "@esbuild/linux-loong64@0.14.53":
version "0.14.53" version "0.14.53"
resolved "https://registry.yarnpkg.com/@esbuild/linux-loong64/-/linux-loong64-0.14.53.tgz#251b4cd6760fadb4d68a05815e6dc5e432d69cd6" resolved "https://registry.yarnpkg.com/@esbuild/linux-loong64/-/linux-loong64-0.14.53.tgz#251b4cd6760fadb4d68a05815e6dc5e432d69cd6"
integrity sha512-W2dAL6Bnyn4xa/QRSU3ilIK4EzD5wgYXKXJiS1HDF5vU3675qc2bvFyLwbUcdmssDveyndy7FbitrCoiV/eMLg== integrity sha512-W2dAL6Bnyn4xa/QRSU3ilIK4EzD5wgYXKXJiS1HDF5vU3675qc2bvFyLwbUcdmssDveyndy7FbitrCoiV/eMLg==
"@esbuild/linux-loong64@0.15.13": "@esbuild/linux-loong64@0.16.13":
version "0.15.13" version "0.16.13"
resolved "https://registry.yarnpkg.com/@esbuild/linux-loong64/-/linux-loong64-0.15.13.tgz#64e8825bf0ce769dac94ee39d92ebe6272020dfc" resolved "https://registry.npmmirror.com/@esbuild/linux-loong64/-/linux-loong64-0.16.13.tgz#e4a832708e0b47078b91413edcfdb6af88c854a3"
integrity sha512-+BoyIm4I8uJmH/QDIH0fu7MG0AEx9OXEDXnqptXCwKOlOqZiS4iraH1Nr7/ObLMokW3sOCeBNyD68ATcV9b9Ag== integrity sha512-x8KplRu9Y43Px8I9YS+sPBwQ+fw44Mvp2BPVADopKDWz+h3fcj1BvRU58kxb89WObmwKX9sWdtYzepL4Fmx03A==
"@esbuild/linux-mips64el@0.16.13":
version "0.16.13"
resolved "https://registry.npmmirror.com/@esbuild/linux-mips64el/-/linux-mips64el-0.16.13.tgz#30d8571b71e0b8bf25fc5ef11422221ed23cdacc"
integrity sha512-qhhdWph9FLwD9rVVC/nUf7k2U4NZIA6/mGx0B7+O6PFV0GjmPA2E3zDQ4NUjq9P26E0DeAZy9akH9dYcUBRU7A==
"@esbuild/linux-ppc64@0.16.13":
version "0.16.13"
resolved "https://registry.npmmirror.com/@esbuild/linux-ppc64/-/linux-ppc64-0.16.13.tgz#32a3855d4b79ba1d2b63dab592cb9f0d4a9ba485"
integrity sha512-cVWAPKsrRVxI1jCeJHnYSbE3BrEU+pZTZK2gfao9HRxuc+3m4+RLfs3EVEpGLmMKEcWfVCB9wZ3yNxnknutGKQ==
"@esbuild/linux-riscv64@0.16.13":
version "0.16.13"
resolved "https://registry.npmmirror.com/@esbuild/linux-riscv64/-/linux-riscv64-0.16.13.tgz#6139202858da8202724d7079102614c269524f34"
integrity sha512-Agb7dbRyZWnmPn5Vvf0eyqaEUqSsaIUwwyInu2EoFTaIDRp093QU2M5alUyOooMLkRbD1WvqQNwx08Z/g+SAcQ==
"@esbuild/linux-s390x@0.16.13":
version "0.16.13"
resolved "https://registry.npmmirror.com/@esbuild/linux-s390x/-/linux-s390x-0.16.13.tgz#df3550a51e4155cde31486e01d8121f078e959ae"
integrity sha512-AqRBIrc/+kl08ahliNG+EyU+j41wIzQfwBTKpi80cCDiYvYFPuXjvzZsD9muiu58Isj0RVni9VgC4xK/AnSW4g==
"@esbuild/linux-x64@0.16.13":
version "0.16.13"
resolved "https://registry.npmmirror.com/@esbuild/linux-x64/-/linux-x64-0.16.13.tgz#deb7951829ea5930e0d88440aeb5df0756ebb2d0"
integrity sha512-S4wn2BimuhPcoArRtVrdHUKIymCCZcYAXQE47kUiX4yrUrEX2/ifn5eKNbZ5c1jJKUlh1gC2ESIN+iw3wQax3g==
"@esbuild/netbsd-x64@0.16.13":
version "0.16.13"
resolved "https://registry.npmmirror.com/@esbuild/netbsd-x64/-/netbsd-x64-0.16.13.tgz#8cba08074263862138cc5c63ad7f9640fe3faa69"
integrity sha512-2c8JWgfUMlQHTdaR5X3xNMwqOyad8kgeCupuVkdm3QkUOzGREjlTETQsK6oHifocYzDCo9FeKcUwsK356SdR+g==
"@esbuild/openbsd-x64@0.16.13":
version "0.16.13"
resolved "https://registry.npmmirror.com/@esbuild/openbsd-x64/-/openbsd-x64-0.16.13.tgz#4ae19ac63c665424d248ba5c577618dd7bbcebd5"
integrity sha512-Bwh+PmKD/LK+xBjqIpnYnKYj0fIyQJ0YpRxsn0F+WfzvQ2OA+GKDlf8AHosiCns26Q4Dje388jQVwfOBZ1GaFw==
"@esbuild/sunos-x64@0.16.13":
version "0.16.13"
resolved "https://registry.npmmirror.com/@esbuild/sunos-x64/-/sunos-x64-0.16.13.tgz#592caacab6b2c7669cd869b51f66dc354da03fc2"
integrity sha512-8wwk6f9XGnhrF94/DBdFM4Xm1JeCyGTCj67r516VS9yvBVQf3Rar54L+XPVDs/oZOokwH+XsktrgkuTMAmjntg==
"@esbuild/win32-arm64@0.16.13":
version "0.16.13"
resolved "https://registry.npmmirror.com/@esbuild/win32-arm64/-/win32-arm64-0.16.13.tgz#965ebbe889e4221962250c55facaa1e48130c162"
integrity sha512-Jmwbp/5ArLCiRAHC33ODfcrlIcbP/exXkOEUVkADNJC4e/so2jm+i8IQFvVX/lA2GWvK3GdgcN0VFfp9YITAbg==
"@esbuild/win32-ia32@0.16.13":
version "0.16.13"
resolved "https://registry.npmmirror.com/@esbuild/win32-ia32/-/win32-ia32-0.16.13.tgz#1b04965bcf340ba4879b452ac32df63216d4c87e"
integrity sha512-AX6WjntGjhJHzrPSVvjMD7grxt41koHfAOx6lxLorrpDwwIKKPaGDASPZgvFIZHTbwhOtILW6vAXxYPDsKpDJA==
"@esbuild/win32-x64@0.16.13":
version "0.16.13"
resolved "https://registry.npmmirror.com/@esbuild/win32-x64/-/win32-x64-0.16.13.tgz#0b0989cf0e7887cb0f3124e705cee68a694b96dd"
integrity sha512-A+U4gM6OOkPS03UgVU08GTpAAAxPsP/8Z4FmneGo4TaVSD99bK9gVJXlqUEPMO/htFXEAht2O6pX4ErtLY5tVg==
"@jridgewell/gen-mapping@^0.1.0": "@jridgewell/gen-mapping@^0.1.0":
version "0.1.1" version "0.1.1"
@ -1442,201 +1542,101 @@ esbuild-android-64@0.14.53:
resolved "https://registry.yarnpkg.com/esbuild-android-64/-/esbuild-android-64-0.14.53.tgz#259bc3ef1399a3cad8f4f67c40ee20779c4de675" resolved "https://registry.yarnpkg.com/esbuild-android-64/-/esbuild-android-64-0.14.53.tgz#259bc3ef1399a3cad8f4f67c40ee20779c4de675"
integrity sha512-fIL93sOTnEU+NrTAVMIKiAw0YH22HWCAgg4N4Z6zov2t0kY9RAJ50zY9ZMCQ+RT6bnOfDt8gCTnt/RaSNA2yRA== integrity sha512-fIL93sOTnEU+NrTAVMIKiAw0YH22HWCAgg4N4Z6zov2t0kY9RAJ50zY9ZMCQ+RT6bnOfDt8gCTnt/RaSNA2yRA==
esbuild-android-64@0.15.13:
version "0.15.13"
resolved "https://registry.yarnpkg.com/esbuild-android-64/-/esbuild-android-64-0.15.13.tgz#5f25864055dbd62e250f360b38b4c382224063af"
integrity sha512-yRorukXBlokwTip+Sy4MYskLhJsO0Kn0/Fj43s1krVblfwP+hMD37a4Wmg139GEsMLl+vh8WXp2mq/cTA9J97g==
esbuild-android-arm64@0.14.53: esbuild-android-arm64@0.14.53:
version "0.14.53" version "0.14.53"
resolved "https://registry.yarnpkg.com/esbuild-android-arm64/-/esbuild-android-arm64-0.14.53.tgz#2158253d4e8f9fdd2a081bbb4f73b8806178841e" resolved "https://registry.yarnpkg.com/esbuild-android-arm64/-/esbuild-android-arm64-0.14.53.tgz#2158253d4e8f9fdd2a081bbb4f73b8806178841e"
integrity sha512-PC7KaF1v0h/nWpvlU1UMN7dzB54cBH8qSsm7S9mkwFA1BXpaEOufCg8hdoEI1jep0KeO/rjZVWrsH8+q28T77A== integrity sha512-PC7KaF1v0h/nWpvlU1UMN7dzB54cBH8qSsm7S9mkwFA1BXpaEOufCg8hdoEI1jep0KeO/rjZVWrsH8+q28T77A==
esbuild-android-arm64@0.15.13:
version "0.15.13"
resolved "https://registry.yarnpkg.com/esbuild-android-arm64/-/esbuild-android-arm64-0.15.13.tgz#d8820f999314efbe8e0f050653a99ff2da632b0f"
integrity sha512-TKzyymLD6PiVeyYa4c5wdPw87BeAiTXNtK6amWUcXZxkV51gOk5u5qzmDaYSwiWeecSNHamFsaFjLoi32QR5/w==
esbuild-darwin-64@0.14.53: esbuild-darwin-64@0.14.53:
version "0.14.53" version "0.14.53"
resolved "https://registry.yarnpkg.com/esbuild-darwin-64/-/esbuild-darwin-64-0.14.53.tgz#b4681831fd8f8d06feb5048acbe90d742074cc2a" resolved "https://registry.yarnpkg.com/esbuild-darwin-64/-/esbuild-darwin-64-0.14.53.tgz#b4681831fd8f8d06feb5048acbe90d742074cc2a"
integrity sha512-gE7P5wlnkX4d4PKvLBUgmhZXvL7lzGRLri17/+CmmCzfncIgq8lOBvxGMiQ4xazplhxq+72TEohyFMZLFxuWvg== integrity sha512-gE7P5wlnkX4d4PKvLBUgmhZXvL7lzGRLri17/+CmmCzfncIgq8lOBvxGMiQ4xazplhxq+72TEohyFMZLFxuWvg==
esbuild-darwin-64@0.15.13:
version "0.15.13"
resolved "https://registry.yarnpkg.com/esbuild-darwin-64/-/esbuild-darwin-64-0.15.13.tgz#99ae7fdaa43947b06cd9d1a1c3c2c9f245d81fd0"
integrity sha512-WAx7c2DaOS6CrRcoYCgXgkXDliLnFv3pQLV6GeW1YcGEZq2Gnl8s9Pg7ahValZkpOa0iE/ojRVQ87sbUhF1Cbg==
esbuild-darwin-arm64@0.14.53: esbuild-darwin-arm64@0.14.53:
version "0.14.53" version "0.14.53"
resolved "https://registry.yarnpkg.com/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.14.53.tgz#d267d957852d121b261b3f76ead86e5b5463acc9" resolved "https://registry.yarnpkg.com/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.14.53.tgz#d267d957852d121b261b3f76ead86e5b5463acc9"
integrity sha512-otJwDU3hnI15Q98PX4MJbknSZ/WSR1I45il7gcxcECXzfN4Mrpft5hBDHXNRnCh+5858uPXBXA1Vaz2jVWLaIA== integrity sha512-otJwDU3hnI15Q98PX4MJbknSZ/WSR1I45il7gcxcECXzfN4Mrpft5hBDHXNRnCh+5858uPXBXA1Vaz2jVWLaIA==
esbuild-darwin-arm64@0.15.13:
version "0.15.13"
resolved "https://registry.yarnpkg.com/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.15.13.tgz#bafa1814354ad1a47adcad73de416130ef7f55e3"
integrity sha512-U6jFsPfSSxC3V1CLiQqwvDuj3GGrtQNB3P3nNC3+q99EKf94UGpsG9l4CQ83zBs1NHrk1rtCSYT0+KfK5LsD8A==
esbuild-freebsd-64@0.14.53: esbuild-freebsd-64@0.14.53:
version "0.14.53" version "0.14.53"
resolved "https://registry.yarnpkg.com/esbuild-freebsd-64/-/esbuild-freebsd-64-0.14.53.tgz#aca2af6d72b537fe66a38eb8f374fb66d4c98ca0" resolved "https://registry.yarnpkg.com/esbuild-freebsd-64/-/esbuild-freebsd-64-0.14.53.tgz#aca2af6d72b537fe66a38eb8f374fb66d4c98ca0"
integrity sha512-WkdJa8iyrGHyKiPF4lk0MiOF87Q2SkE+i+8D4Cazq3/iqmGPJ6u49je300MFi5I2eUsQCkaOWhpCVQMTKGww2w== integrity sha512-WkdJa8iyrGHyKiPF4lk0MiOF87Q2SkE+i+8D4Cazq3/iqmGPJ6u49je300MFi5I2eUsQCkaOWhpCVQMTKGww2w==
esbuild-freebsd-64@0.15.13:
version "0.15.13"
resolved "https://registry.yarnpkg.com/esbuild-freebsd-64/-/esbuild-freebsd-64-0.15.13.tgz#84ef85535c5cc38b627d1c5115623b088d1de161"
integrity sha512-whItJgDiOXaDG/idy75qqevIpZjnReZkMGCgQaBWZuKHoElDJC1rh7MpoUgupMcdfOd+PgdEwNQW9DAE6i8wyA==
esbuild-freebsd-arm64@0.14.53: esbuild-freebsd-arm64@0.14.53:
version "0.14.53" version "0.14.53"
resolved "https://registry.yarnpkg.com/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.14.53.tgz#76282e19312d914c34343c8a7da6cc5f051580b9" resolved "https://registry.yarnpkg.com/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.14.53.tgz#76282e19312d914c34343c8a7da6cc5f051580b9"
integrity sha512-9T7WwCuV30NAx0SyQpw8edbKvbKELnnm1FHg7gbSYaatH+c8WJW10g/OdM7JYnv7qkimw2ZTtSA+NokOLd2ydQ== integrity sha512-9T7WwCuV30NAx0SyQpw8edbKvbKELnnm1FHg7gbSYaatH+c8WJW10g/OdM7JYnv7qkimw2ZTtSA+NokOLd2ydQ==
esbuild-freebsd-arm64@0.15.13:
version "0.15.13"
resolved "https://registry.yarnpkg.com/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.15.13.tgz#033f21de434ec8e0c478054b119af8056763c2d8"
integrity sha512-6pCSWt8mLUbPtygv7cufV0sZLeylaMwS5Fznj6Rsx9G2AJJsAjQ9ifA+0rQEIg7DwJmi9it+WjzNTEAzzdoM3Q==
esbuild-linux-32@0.14.53: esbuild-linux-32@0.14.53:
version "0.14.53" version "0.14.53"
resolved "https://registry.yarnpkg.com/esbuild-linux-32/-/esbuild-linux-32-0.14.53.tgz#1045d34cf7c5faaf2af3b29cc1573b06580c37e5" resolved "https://registry.yarnpkg.com/esbuild-linux-32/-/esbuild-linux-32-0.14.53.tgz#1045d34cf7c5faaf2af3b29cc1573b06580c37e5"
integrity sha512-VGanLBg5en2LfGDgLEUxQko2lqsOS7MTEWUi8x91YmsHNyzJVT/WApbFFx3MQGhkf+XdimVhpyo5/G0PBY91zg== integrity sha512-VGanLBg5en2LfGDgLEUxQko2lqsOS7MTEWUi8x91YmsHNyzJVT/WApbFFx3MQGhkf+XdimVhpyo5/G0PBY91zg==
esbuild-linux-32@0.15.13:
version "0.15.13"
resolved "https://registry.yarnpkg.com/esbuild-linux-32/-/esbuild-linux-32-0.15.13.tgz#54290ea8035cba0faf1791ce9ae6693005512535"
integrity sha512-VbZdWOEdrJiYApm2kkxoTOgsoCO1krBZ3quHdYk3g3ivWaMwNIVPIfEE0f0XQQ0u5pJtBsnk2/7OPiCFIPOe/w==
esbuild-linux-64@0.14.53: esbuild-linux-64@0.14.53:
version "0.14.53" version "0.14.53"
resolved "https://registry.yarnpkg.com/esbuild-linux-64/-/esbuild-linux-64-0.14.53.tgz#ab3f2ee2ebb5a6930c72d9539cb34b428808cbe4" resolved "https://registry.yarnpkg.com/esbuild-linux-64/-/esbuild-linux-64-0.14.53.tgz#ab3f2ee2ebb5a6930c72d9539cb34b428808cbe4"
integrity sha512-pP/FA55j/fzAV7N9DF31meAyjOH6Bjuo3aSKPh26+RW85ZEtbJv9nhoxmGTd9FOqjx59Tc1ZbrJabuiXlMwuZQ== integrity sha512-pP/FA55j/fzAV7N9DF31meAyjOH6Bjuo3aSKPh26+RW85ZEtbJv9nhoxmGTd9FOqjx59Tc1ZbrJabuiXlMwuZQ==
esbuild-linux-64@0.15.13:
version "0.15.13"
resolved "https://registry.yarnpkg.com/esbuild-linux-64/-/esbuild-linux-64-0.15.13.tgz#4264249281ea388ead948614b57fb1ddf7779a2c"
integrity sha512-rXmnArVNio6yANSqDQlIO4WiP+Cv7+9EuAHNnag7rByAqFVuRusLbGi2697A5dFPNXoO//IiogVwi3AdcfPC6A==
esbuild-linux-arm64@0.14.53: esbuild-linux-arm64@0.14.53:
version "0.14.53" version "0.14.53"
resolved "https://registry.yarnpkg.com/esbuild-linux-arm64/-/esbuild-linux-arm64-0.14.53.tgz#1f5530412f6690949e78297122350488d3266cfe" resolved "https://registry.yarnpkg.com/esbuild-linux-arm64/-/esbuild-linux-arm64-0.14.53.tgz#1f5530412f6690949e78297122350488d3266cfe"
integrity sha512-GDmWITT+PMsjCA6/lByYk7NyFssW4Q6in32iPkpjZ/ytSyH+xeEx8q7HG3AhWH6heemEYEWpTll/eui3jwlSnw== integrity sha512-GDmWITT+PMsjCA6/lByYk7NyFssW4Q6in32iPkpjZ/ytSyH+xeEx8q7HG3AhWH6heemEYEWpTll/eui3jwlSnw==
esbuild-linux-arm64@0.15.13:
version "0.15.13"
resolved "https://registry.yarnpkg.com/esbuild-linux-arm64/-/esbuild-linux-arm64-0.15.13.tgz#9323c333924f97a02bdd2ae8912b36298acb312d"
integrity sha512-alEMGU4Z+d17U7KQQw2IV8tQycO6T+rOrgW8OS22Ua25x6kHxoG6Ngry6Aq6uranC+pNWNMB6aHFPh7aTQdORQ==
esbuild-linux-arm@0.14.53: esbuild-linux-arm@0.14.53:
version "0.14.53" version "0.14.53"
resolved "https://registry.yarnpkg.com/esbuild-linux-arm/-/esbuild-linux-arm-0.14.53.tgz#a44ec9b5b42007ab6c0d65a224ccc6bbd97c54cf" resolved "https://registry.yarnpkg.com/esbuild-linux-arm/-/esbuild-linux-arm-0.14.53.tgz#a44ec9b5b42007ab6c0d65a224ccc6bbd97c54cf"
integrity sha512-/u81NGAVZMopbmzd21Nu/wvnKQK3pT4CrvQ8BTje1STXcQAGnfyKgQlj3m0j2BzYbvQxSy+TMck4TNV2onvoPA== integrity sha512-/u81NGAVZMopbmzd21Nu/wvnKQK3pT4CrvQ8BTje1STXcQAGnfyKgQlj3m0j2BzYbvQxSy+TMck4TNV2onvoPA==
esbuild-linux-arm@0.15.13:
version "0.15.13"
resolved "https://registry.yarnpkg.com/esbuild-linux-arm/-/esbuild-linux-arm-0.15.13.tgz#b407f47b3ae721fe4e00e19e9f19289bef87a111"
integrity sha512-Ac6LpfmJO8WhCMQmO253xX2IU2B3wPDbl4IvR0hnqcPrdfCaUa2j/lLMGTjmQ4W5JsJIdHEdW12dG8lFS0MbxQ==
esbuild-linux-mips64le@0.14.53: esbuild-linux-mips64le@0.14.53:
version "0.14.53" version "0.14.53"
resolved "https://registry.yarnpkg.com/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.14.53.tgz#a4d0b6b17cfdeea4e41b0b085a5f73d99311be9f" resolved "https://registry.yarnpkg.com/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.14.53.tgz#a4d0b6b17cfdeea4e41b0b085a5f73d99311be9f"
integrity sha512-d6/XHIQW714gSSp6tOOX2UscedVobELvQlPMkInhx1NPz4ThZI9uNLQ4qQJHGBGKGfu+rtJsxM4NVHLhnNRdWQ== integrity sha512-d6/XHIQW714gSSp6tOOX2UscedVobELvQlPMkInhx1NPz4ThZI9uNLQ4qQJHGBGKGfu+rtJsxM4NVHLhnNRdWQ==
esbuild-linux-mips64le@0.15.13:
version "0.15.13"
resolved "https://registry.yarnpkg.com/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.15.13.tgz#bdf905aae5c0bcaa8f83567fe4c4c1bdc1f14447"
integrity sha512-47PgmyYEu+yN5rD/MbwS6DxP2FSGPo4Uxg5LwIdxTiyGC2XKwHhHyW7YYEDlSuXLQXEdTO7mYe8zQ74czP7W8A==
esbuild-linux-ppc64le@0.14.53: esbuild-linux-ppc64le@0.14.53:
version "0.14.53" version "0.14.53"
resolved "https://registry.yarnpkg.com/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.14.53.tgz#8c331822c85465434e086e3e6065863770c38139" resolved "https://registry.yarnpkg.com/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.14.53.tgz#8c331822c85465434e086e3e6065863770c38139"
integrity sha512-ndnJmniKPCB52m+r6BtHHLAOXw+xBCWIxNnedbIpuREOcbSU/AlyM/2dA3BmUQhsHdb4w3amD5U2s91TJ3MzzA== integrity sha512-ndnJmniKPCB52m+r6BtHHLAOXw+xBCWIxNnedbIpuREOcbSU/AlyM/2dA3BmUQhsHdb4w3amD5U2s91TJ3MzzA==
esbuild-linux-ppc64le@0.15.13:
version "0.15.13"
resolved "https://registry.yarnpkg.com/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.15.13.tgz#2911eae1c90ff58a3bd3259cb557235df25aa3b4"
integrity sha512-z6n28h2+PC1Ayle9DjKoBRcx/4cxHoOa2e689e2aDJSaKug3jXcQw7mM+GLg+9ydYoNzj8QxNL8ihOv/OnezhA==
esbuild-linux-riscv64@0.14.53: esbuild-linux-riscv64@0.14.53:
version "0.14.53" version "0.14.53"
resolved "https://registry.yarnpkg.com/esbuild-linux-riscv64/-/esbuild-linux-riscv64-0.14.53.tgz#36fd75543401304bea8a2d63bf8ea18aaa508e00" resolved "https://registry.yarnpkg.com/esbuild-linux-riscv64/-/esbuild-linux-riscv64-0.14.53.tgz#36fd75543401304bea8a2d63bf8ea18aaa508e00"
integrity sha512-yG2sVH+QSix6ct4lIzJj329iJF3MhloLE6/vKMQAAd26UVPVkhMFqFopY+9kCgYsdeWvXdPgmyOuKa48Y7+/EQ== integrity sha512-yG2sVH+QSix6ct4lIzJj329iJF3MhloLE6/vKMQAAd26UVPVkhMFqFopY+9kCgYsdeWvXdPgmyOuKa48Y7+/EQ==
esbuild-linux-riscv64@0.15.13:
version "0.15.13"
resolved "https://registry.yarnpkg.com/esbuild-linux-riscv64/-/esbuild-linux-riscv64-0.15.13.tgz#1837c660be12b1d20d2a29c7189ea703f93e9265"
integrity sha512-+Lu4zuuXuQhgLUGyZloWCqTslcCAjMZH1k3Xc9MSEJEpEFdpsSU0sRDXAnk18FKOfEjhu4YMGaykx9xjtpA6ow==
esbuild-linux-s390x@0.14.53: esbuild-linux-s390x@0.14.53:
version "0.14.53" version "0.14.53"
resolved "https://registry.yarnpkg.com/esbuild-linux-s390x/-/esbuild-linux-s390x-0.14.53.tgz#1622677ab6824123f48f75d3afc031cd41936129" resolved "https://registry.yarnpkg.com/esbuild-linux-s390x/-/esbuild-linux-s390x-0.14.53.tgz#1622677ab6824123f48f75d3afc031cd41936129"
integrity sha512-OCJlgdkB+XPYndHmw6uZT7jcYgzmx9K+28PVdOa/eLjdoYkeAFvH5hTwX4AXGLZLH09tpl4bVsEtvuyUldaNCg== integrity sha512-OCJlgdkB+XPYndHmw6uZT7jcYgzmx9K+28PVdOa/eLjdoYkeAFvH5hTwX4AXGLZLH09tpl4bVsEtvuyUldaNCg==
esbuild-linux-s390x@0.15.13:
version "0.15.13"
resolved "https://registry.yarnpkg.com/esbuild-linux-s390x/-/esbuild-linux-s390x-0.15.13.tgz#d52880ece229d1bd10b2d936b792914ffb07c7fc"
integrity sha512-BMeXRljruf7J0TMxD5CIXS65y7puiZkAh+s4XFV9qy16SxOuMhxhVIXYLnbdfLrsYGFzx7U9mcdpFWkkvy/Uag==
esbuild-netbsd-64@0.14.53: esbuild-netbsd-64@0.14.53:
version "0.14.53" version "0.14.53"
resolved "https://registry.yarnpkg.com/esbuild-netbsd-64/-/esbuild-netbsd-64-0.14.53.tgz#e86d0efd0116658be335492ed12e66b26b4baf52" resolved "https://registry.yarnpkg.com/esbuild-netbsd-64/-/esbuild-netbsd-64-0.14.53.tgz#e86d0efd0116658be335492ed12e66b26b4baf52"
integrity sha512-gp2SB+Efc7MhMdWV2+pmIs/Ja/Mi5rjw+wlDmmbIn68VGXBleNgiEZG+eV2SRS0kJEUyHNedDtwRIMzaohWedQ== integrity sha512-gp2SB+Efc7MhMdWV2+pmIs/Ja/Mi5rjw+wlDmmbIn68VGXBleNgiEZG+eV2SRS0kJEUyHNedDtwRIMzaohWedQ==
esbuild-netbsd-64@0.15.13:
version "0.15.13"
resolved "https://registry.yarnpkg.com/esbuild-netbsd-64/-/esbuild-netbsd-64-0.15.13.tgz#de14da46f1d20352b43e15d97a80a8788275e6ed"
integrity sha512-EHj9QZOTel581JPj7UO3xYbltFTYnHy+SIqJVq6yd3KkCrsHRbapiPb0Lx3EOOtybBEE9EyqbmfW1NlSDsSzvQ==
esbuild-openbsd-64@0.14.53: esbuild-openbsd-64@0.14.53:
version "0.14.53" version "0.14.53"
resolved "https://registry.yarnpkg.com/esbuild-openbsd-64/-/esbuild-openbsd-64-0.14.53.tgz#9bcbbe6f86304872c6e91f64c8eb73fc29c3588b" resolved "https://registry.yarnpkg.com/esbuild-openbsd-64/-/esbuild-openbsd-64-0.14.53.tgz#9bcbbe6f86304872c6e91f64c8eb73fc29c3588b"
integrity sha512-eKQ30ZWe+WTZmteDYg8S+YjHV5s4iTxeSGhJKJajFfQx9TLZJvsJX0/paqwP51GicOUruFpSUAs2NCc0a4ivQQ== integrity sha512-eKQ30ZWe+WTZmteDYg8S+YjHV5s4iTxeSGhJKJajFfQx9TLZJvsJX0/paqwP51GicOUruFpSUAs2NCc0a4ivQQ==
esbuild-openbsd-64@0.15.13:
version "0.15.13"
resolved "https://registry.yarnpkg.com/esbuild-openbsd-64/-/esbuild-openbsd-64-0.15.13.tgz#45e8a5fd74d92ad8f732c43582369c7990f5a0ac"
integrity sha512-nkuDlIjF/sfUhfx8SKq0+U+Fgx5K9JcPq1mUodnxI0x4kBdCv46rOGWbuJ6eof2n3wdoCLccOoJAbg9ba/bT2w==
esbuild-sunos-64@0.14.53: esbuild-sunos-64@0.14.53:
version "0.14.53" version "0.14.53"
resolved "https://registry.yarnpkg.com/esbuild-sunos-64/-/esbuild-sunos-64-0.14.53.tgz#f7a872f7460bfb7b131f7188a95fbce3d1c577e8" resolved "https://registry.yarnpkg.com/esbuild-sunos-64/-/esbuild-sunos-64-0.14.53.tgz#f7a872f7460bfb7b131f7188a95fbce3d1c577e8"
integrity sha512-OWLpS7a2FrIRukQqcgQqR1XKn0jSJoOdT+RlhAxUoEQM/IpytS3FXzCJM6xjUYtpO5GMY0EdZJp+ur2pYdm39g== integrity sha512-OWLpS7a2FrIRukQqcgQqR1XKn0jSJoOdT+RlhAxUoEQM/IpytS3FXzCJM6xjUYtpO5GMY0EdZJp+ur2pYdm39g==
esbuild-sunos-64@0.15.13:
version "0.15.13"
resolved "https://registry.yarnpkg.com/esbuild-sunos-64/-/esbuild-sunos-64-0.15.13.tgz#f646ac3da7aac521ee0fdbc192750c87da697806"
integrity sha512-jVeu2GfxZQ++6lRdY43CS0Tm/r4WuQQ0Pdsrxbw+aOrHQPHV0+LNOLnvbN28M7BSUGnJnHkHm2HozGgNGyeIRw==
esbuild-windows-32@0.14.53: esbuild-windows-32@0.14.53:
version "0.14.53" version "0.14.53"
resolved "https://registry.yarnpkg.com/esbuild-windows-32/-/esbuild-windows-32-0.14.53.tgz#c5e3ca50e2d1439cc2c9fe4defa63bcd474ce709" resolved "https://registry.yarnpkg.com/esbuild-windows-32/-/esbuild-windows-32-0.14.53.tgz#c5e3ca50e2d1439cc2c9fe4defa63bcd474ce709"
integrity sha512-m14XyWQP5rwGW0tbEfp95U6A0wY0DYPInWBB7D69FAXUpBpBObRoGTKRv36lf2RWOdE4YO3TNvj37zhXjVL5xg== integrity sha512-m14XyWQP5rwGW0tbEfp95U6A0wY0DYPInWBB7D69FAXUpBpBObRoGTKRv36lf2RWOdE4YO3TNvj37zhXjVL5xg==
esbuild-windows-32@0.15.13:
version "0.15.13"
resolved "https://registry.yarnpkg.com/esbuild-windows-32/-/esbuild-windows-32-0.15.13.tgz#fb4fe77c7591418880b3c9b5900adc4c094f2401"
integrity sha512-XoF2iBf0wnqo16SDq+aDGi/+QbaLFpkiRarPVssMh9KYbFNCqPLlGAWwDvxEVz+ywX6Si37J2AKm+AXq1kC0JA==
esbuild-windows-64@0.14.53: esbuild-windows-64@0.14.53:
version "0.14.53" version "0.14.53"
resolved "https://registry.yarnpkg.com/esbuild-windows-64/-/esbuild-windows-64-0.14.53.tgz#ec2ab4a60c5215f092ffe1eab6d01319e88238af" resolved "https://registry.yarnpkg.com/esbuild-windows-64/-/esbuild-windows-64-0.14.53.tgz#ec2ab4a60c5215f092ffe1eab6d01319e88238af"
integrity sha512-s9skQFF0I7zqnQ2K8S1xdLSfZFsPLuOGmSx57h2btSEswv0N0YodYvqLcJMrNMXh6EynOmWD7rz+0rWWbFpIHQ== integrity sha512-s9skQFF0I7zqnQ2K8S1xdLSfZFsPLuOGmSx57h2btSEswv0N0YodYvqLcJMrNMXh6EynOmWD7rz+0rWWbFpIHQ==
esbuild-windows-64@0.15.13:
version "0.15.13"
resolved "https://registry.yarnpkg.com/esbuild-windows-64/-/esbuild-windows-64-0.15.13.tgz#1fca8c654392c0c31bdaaed168becfea80e20660"
integrity sha512-Et6htEfGycjDrtqb2ng6nT+baesZPYQIW+HUEHK4D1ncggNrDNk3yoboYQ5KtiVrw/JaDMNttz8rrPubV/fvPQ==
esbuild-windows-arm64@0.14.53: esbuild-windows-arm64@0.14.53:
version "0.14.53" version "0.14.53"
resolved "https://registry.yarnpkg.com/esbuild-windows-arm64/-/esbuild-windows-arm64-0.14.53.tgz#f71d403806bdf9f4a1f9d097db9aec949bd675c8" resolved "https://registry.yarnpkg.com/esbuild-windows-arm64/-/esbuild-windows-arm64-0.14.53.tgz#f71d403806bdf9f4a1f9d097db9aec949bd675c8"
integrity sha512-E+5Gvb+ZWts+00T9II6wp2L3KG2r3iGxByqd/a1RmLmYWVsSVUjkvIxZuJ3hYTIbhLkH5PRwpldGTKYqVz0nzQ== integrity sha512-E+5Gvb+ZWts+00T9II6wp2L3KG2r3iGxByqd/a1RmLmYWVsSVUjkvIxZuJ3hYTIbhLkH5PRwpldGTKYqVz0nzQ==
esbuild-windows-arm64@0.15.13:
version "0.15.13"
resolved "https://registry.yarnpkg.com/esbuild-windows-arm64/-/esbuild-windows-arm64-0.15.13.tgz#4ffd01b6b2888603f1584a2fe96b1f6a6f2b3dd8"
integrity sha512-3bv7tqntThQC9SWLRouMDmZnlOukBhOCTlkzNqzGCmrkCJI7io5LLjwJBOVY6kOUlIvdxbooNZwjtBvj+7uuVg==
esbuild@^0.14.47: esbuild@^0.14.47:
version "0.14.53" version "0.14.53"
resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.14.53.tgz#20b1007f686e8584f2a01a1bec5a37aac9498ce4" resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.14.53.tgz#20b1007f686e8584f2a01a1bec5a37aac9498ce4"
@ -1664,33 +1664,33 @@ esbuild@^0.14.47:
esbuild-windows-64 "0.14.53" esbuild-windows-64 "0.14.53"
esbuild-windows-arm64 "0.14.53" esbuild-windows-arm64 "0.14.53"
esbuild@^0.15.9: esbuild@^0.16.3:
version "0.15.13" version "0.16.13"
resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.15.13.tgz#7293480038feb2bafa91d3f6a20edab3ba6c108a" resolved "https://registry.npmmirror.com/esbuild/-/esbuild-0.16.13.tgz#83cd347c28221268bbfa0425db532d7d05f85b48"
integrity sha512-Cu3SC84oyzzhrK/YyN4iEVy2jZu5t2fz66HEOShHURcjSkOSAVL8C/gfUT+lDJxkVHpg8GZ10DD0rMHRPqMFaQ== integrity sha512-oYwFdSEIoKM1oYzyem1osgKJAvg5447XF+05ava21fOtilyb2HeQQh26/74K4WeAk5dZmj/Mx10zUqUnI14jhA==
optionalDependencies: optionalDependencies:
"@esbuild/android-arm" "0.15.13" "@esbuild/android-arm" "0.16.13"
"@esbuild/linux-loong64" "0.15.13" "@esbuild/android-arm64" "0.16.13"
esbuild-android-64 "0.15.13" "@esbuild/android-x64" "0.16.13"
esbuild-android-arm64 "0.15.13" "@esbuild/darwin-arm64" "0.16.13"
esbuild-darwin-64 "0.15.13" "@esbuild/darwin-x64" "0.16.13"
esbuild-darwin-arm64 "0.15.13" "@esbuild/freebsd-arm64" "0.16.13"
esbuild-freebsd-64 "0.15.13" "@esbuild/freebsd-x64" "0.16.13"
esbuild-freebsd-arm64 "0.15.13" "@esbuild/linux-arm" "0.16.13"
esbuild-linux-32 "0.15.13" "@esbuild/linux-arm64" "0.16.13"
esbuild-linux-64 "0.15.13" "@esbuild/linux-ia32" "0.16.13"
esbuild-linux-arm "0.15.13" "@esbuild/linux-loong64" "0.16.13"
esbuild-linux-arm64 "0.15.13" "@esbuild/linux-mips64el" "0.16.13"
esbuild-linux-mips64le "0.15.13" "@esbuild/linux-ppc64" "0.16.13"
esbuild-linux-ppc64le "0.15.13" "@esbuild/linux-riscv64" "0.16.13"
esbuild-linux-riscv64 "0.15.13" "@esbuild/linux-s390x" "0.16.13"
esbuild-linux-s390x "0.15.13" "@esbuild/linux-x64" "0.16.13"
esbuild-netbsd-64 "0.15.13" "@esbuild/netbsd-x64" "0.16.13"
esbuild-openbsd-64 "0.15.13" "@esbuild/openbsd-x64" "0.16.13"
esbuild-sunos-64 "0.15.13" "@esbuild/sunos-x64" "0.16.13"
esbuild-windows-32 "0.15.13" "@esbuild/win32-arm64" "0.16.13"
esbuild-windows-64 "0.15.13" "@esbuild/win32-ia32" "0.16.13"
esbuild-windows-arm64 "0.15.13" "@esbuild/win32-x64" "0.16.13"
escalade@^3.1.1: escalade@^3.1.1:
version "3.1.1" version "3.1.1"
@ -2553,10 +2553,10 @@ postcss@^8.1.10, postcss@^8.2.9, postcss@^8.4.14:
picocolors "^1.0.0" picocolors "^1.0.0"
source-map-js "^1.0.2" source-map-js "^1.0.2"
postcss@^8.4.18: postcss@^8.4.20:
version "8.4.19" version "8.4.20"
resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.19.tgz#61178e2add236b17351897c8bcc0b4c8ecab56fc" resolved "https://registry.npmmirror.com/postcss/-/postcss-8.4.20.tgz#64c52f509644cecad8567e949f4081d98349dc56"
integrity sha512-h+pbPsyhlYj6N2ozBmHhHrs9DzGmbaarbLvWipMRO7RLS+v4onj26MPFXA5OBYFxyqYhUJK456SwDcY9H2/zsA== integrity sha512-6Q04AXR1212bXr5fh03u8aAwbLxAQNGQ/Q1LNa0VfOI06ZAlhPHtQvE4OIdpj4kLThXilalPnmDSOD65DcHt+g==
dependencies: dependencies:
nanoid "^3.3.4" nanoid "^3.3.4"
picocolors "^1.0.0" picocolors "^1.0.0"
@ -2642,10 +2642,10 @@ rollup@^2.75.6:
optionalDependencies: optionalDependencies:
fsevents "~2.3.2" fsevents "~2.3.2"
rollup@^2.79.1: rollup@^3.7.0:
version "2.79.1" version "3.9.1"
resolved "https://registry.yarnpkg.com/rollup/-/rollup-2.79.1.tgz#bedee8faef7c9f93a2647ac0108748f497f081c7" resolved "https://registry.npmmirror.com/rollup/-/rollup-3.9.1.tgz#27501d3d026418765fe379d5620d25954ff2a011"
integrity sha512-uKxbd0IhMZOhjAiD5oAFp7BqvkA4Dv47qpOCtaNvng4HBwdbWtdOh8f5nZNuk2rp51PMGk3bzfWu5oayNEuYnw== integrity sha512-GswCYHXftN8ZKGVgQhTFUJB/NBXxrRGgO2NCy6E8s1rwEJ4Q9/VttNqcYfEvx4dTo4j58YqdC3OVztPzlKSX8w==
optionalDependencies: optionalDependencies:
fsevents "~2.3.2" fsevents "~2.3.2"
@ -2972,15 +2972,15 @@ vite@^3.0.4:
optionalDependencies: optionalDependencies:
fsevents "~2.3.2" fsevents "~2.3.2"
vite@^3.2.3: vite@^4.0.3:
version "3.2.3" version "4.0.3"
resolved "https://registry.yarnpkg.com/vite/-/vite-3.2.3.tgz#7a68d9ef73eff7ee6dc0718ad3507adfc86944a7" resolved "https://registry.npmmirror.com/vite/-/vite-4.0.3.tgz#de27ad3f263a03ae9419cdc8bc07721eadcba8b9"
integrity sha512-h8jl1TZ76eGs3o2dIBSsvXDLb1m/Ec1iej8ZMdz+PsaFUsftZeWe2CZOI3qogEsMNaywc17gu0q6cQDzh/weCQ== integrity sha512-HvuNv1RdE7deIfQb8mPk51UKjqptO/4RXZ5yXSAvurd5xOckwS/gg8h9Tky3uSbnjYTgUm0hVCet1cyhKd73ZA==
dependencies: dependencies:
esbuild "^0.15.9" esbuild "^0.16.3"
postcss "^8.4.18" postcss "^8.4.20"
resolve "^1.22.1" resolve "^1.22.1"
rollup "^2.79.1" rollup "^3.7.0"
optionalDependencies: optionalDependencies:
fsevents "~2.3.2" fsevents "~2.3.2"

6
go.mod
View file

@ -2,10 +2,11 @@ module github.com/0xJacky/Nginx-UI
go 1.19 go 1.19
replace github.com/tufanbarisyildirim/gonginx v0.0.0-20220829083426-44da4d61ef9a => github.com/0xJacky/gonginx v0.0.0-20230104051937-4c3a63627efb
require ( require (
github.com/creack/pty v1.1.18 github.com/creack/pty v1.1.18
github.com/dustin/go-humanize v1.0.0 github.com/dustin/go-humanize v1.0.0
github.com/emirpasic/gods v1.18.1
github.com/gin-contrib/static v0.0.1 github.com/gin-contrib/static v0.0.1
github.com/gin-gonic/gin v1.7.4 github.com/gin-gonic/gin v1.7.4
github.com/go-acme/lego/v4 v4.4.0 github.com/go-acme/lego/v4 v4.4.0
@ -16,9 +17,11 @@ require (
github.com/golang-jwt/jwt v3.2.2+incompatible github.com/golang-jwt/jwt v3.2.2+incompatible
github.com/google/uuid v1.1.1 github.com/google/uuid v1.1.1
github.com/gorilla/websocket v1.4.2 github.com/gorilla/websocket v1.4.2
github.com/hpcloud/tail v1.0.0
github.com/pkg/errors v0.9.1 github.com/pkg/errors v0.9.1
github.com/shirou/gopsutil/v3 v3.21.7 github.com/shirou/gopsutil/v3 v3.21.7
github.com/spf13/cast v1.3.1 github.com/spf13/cast v1.3.1
github.com/tufanbarisyildirim/gonginx v0.0.0-20220829083426-44da4d61ef9a
github.com/unknwon/com v1.0.1 github.com/unknwon/com v1.0.1
golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad
gopkg.in/ini.v1 v1.62.0 gopkg.in/ini.v1 v1.62.0
@ -32,7 +35,6 @@ require (
github.com/gin-contrib/sse v0.1.0 // indirect github.com/gin-contrib/sse v0.1.0 // indirect
github.com/go-ole/go-ole v1.2.5 // indirect github.com/go-ole/go-ole v1.2.5 // indirect
github.com/golang/protobuf v1.3.4 // indirect github.com/golang/protobuf v1.3.4 // indirect
github.com/hpcloud/tail v1.0.0 // indirect
github.com/jinzhu/inflection v1.0.0 // indirect github.com/jinzhu/inflection v1.0.0 // indirect
github.com/jinzhu/now v1.1.2 // indirect github.com/jinzhu/now v1.1.2 // indirect
github.com/json-iterator/go v1.1.9 // indirect github.com/json-iterator/go v1.1.9 // indirect

18
go.sum
View file

@ -23,6 +23,8 @@ cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0Zeo
cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk=
contrib.go.opencensus.io/exporter/ocagent v0.4.12/go.mod h1:450APlNTSR6FrvC3CTRqYosuDstRB9un7SOx2k/9ckA= contrib.go.opencensus.io/exporter/ocagent v0.4.12/go.mod h1:450APlNTSR6FrvC3CTRqYosuDstRB9un7SOx2k/9ckA=
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
github.com/0xJacky/gonginx v0.0.0-20230104051937-4c3a63627efb h1:UzbGgIvP2UXpqlPG0ylT8/y0TIl5tBvAIeI3OAChFHI=
github.com/0xJacky/gonginx v0.0.0-20230104051937-4c3a63627efb/go.mod h1:+uQMU+LMBHOQermcm/ICplG+r35Ypb6Up9iYKlvKuTE=
github.com/Azure/azure-sdk-for-go v32.4.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= github.com/Azure/azure-sdk-for-go v32.4.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc=
github.com/Azure/go-autorest/autorest v0.1.0/go.mod h1:AKyIcETwSUFxIcs/Wnq/C+kwCtlEYGUVd7FPNb2slmg= github.com/Azure/go-autorest/autorest v0.1.0/go.mod h1:AKyIcETwSUFxIcs/Wnq/C+kwCtlEYGUVd7FPNb2slmg=
github.com/Azure/go-autorest/autorest v0.9.0/go.mod h1:xyHB1BMZT0cuDHU7I0+g046+BFDTQ8rEZB0s4Yfa6bI= github.com/Azure/go-autorest/autorest v0.9.0/go.mod h1:xyHB1BMZT0cuDHU7I0+g046+BFDTQ8rEZB0s4Yfa6bI=
@ -97,14 +99,13 @@ 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-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/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/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/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/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= github.com/exoscale/egoscale v0.46.0/go.mod h1:mpEXBpROAa/2i5GC0r33rfxG+TxSEka11g1PIXt9+zc=
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M= github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
github.com/getkin/kin-openapi v0.13.0/go.mod h1:WGRs2ZMM1Q8LR1QBEwUxC6RJEfaBcD0s+pcEVXFuAjw= github.com/getkin/kin-openapi v0.13.0/go.mod h1:WGRs2ZMM1Q8LR1QBEwUxC6RJEfaBcD0s+pcEVXFuAjw=
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
@ -172,8 +173,10 @@ github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.4.0 h1:xsAVV57WRhGj6kEIi8ReJzQlHHqcBYCElAvkovg3B/4=
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.8 h1:e6P7q2lk1O+qJJb4BtCQXlK8vWEO8V1ZeuEdJNOqZyg=
github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/go-github/v32 v32.1.0/go.mod h1:rIEpZD9CTDQwDK9GDrtMTycQNA4JU3qBsCizh3q2WCI= github.com/google/go-github/v32 v32.1.0/go.mod h1:rIEpZD9CTDQwDK9GDrtMTycQNA4JU3qBsCizh3q2WCI=
github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
@ -446,6 +449,7 @@ github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ= github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ=
github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y=
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk=
go.opencensus.io v0.20.2/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= go.opencensus.io v0.20.2/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk=
@ -502,6 +506,7 @@ golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY=
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@ -529,6 +534,7 @@ golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLL
golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20210220033124-5f55cee0dc0d h1:1aflnvSoWWLI2k/dMUAl5lvU1YO4Mb4hz0gh+1rjcxU= golang.org/x/net v0.0.0-20210220033124-5f55cee0dc0d h1:1aflnvSoWWLI2k/dMUAl5lvU1YO4Mb4hz0gh+1rjcxU=
golang.org/x/net v0.0.0-20210220033124-5f55cee0dc0d/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210220033124-5f55cee0dc0d/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
@ -543,6 +549,7 @@ golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJ
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180622082034-63fc586f45fe/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180622082034-63fc586f45fe/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
@ -589,6 +596,7 @@ golang.org/x/sys v0.0.0-20200918174421-af09f7315aff/go.mod h1:h1NjWce9XRLGQEsW7w
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201110211018-35f3e6cf4a65/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201110211018-35f3e6cf4a65/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c h1:F1jZWGFhYfh0Ci55sIpILtKKK8p3i2/krTr0H1rg74I= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c h1:F1jZWGFhYfh0Ci55sIpILtKKK8p3i2/krTr0H1rg74I=
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
@ -641,9 +649,11 @@ golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapK
golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=
golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/api v0.3.1/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk= google.golang.org/api v0.3.1/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk=
google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M=
@ -725,6 +735,8 @@ gorm.io/driver/sqlite v1.1.4/go.mod h1:mJCeTFr7+crvS+TRnWc5Z3UvwxUN1BGBLMrf5LA9D
gorm.io/gorm v1.20.7/go.mod h1:0HFTzE/SqkGTzK6TlDPPQbAYCluiVvhzoA1+aVyzenw= gorm.io/gorm v1.20.7/go.mod h1:0HFTzE/SqkGTzK6TlDPPQbAYCluiVvhzoA1+aVyzenw=
gorm.io/gorm v1.21.14 h1:NAR9A/3SoyiPVHouW/rlpMUZvuQZ6Z6UYGz+2tosSQo= gorm.io/gorm v1.21.14 h1:NAR9A/3SoyiPVHouW/rlpMUZvuQZ6Z6UYGz+2tosSQo=
gorm.io/gorm v1.21.14/go.mod h1:F+OptMscr0P2F2qU97WT1WimdH9GaQPoDW7AYd5i2Y0= gorm.io/gorm v1.21.14/go.mod h1:F+OptMscr0P2F2qU97WT1WimdH9GaQPoDW7AYd5i2Y0=
gotest.tools/v3 v3.2.0 h1:I0DwBVMGAx26dttAj1BtJLAkVGncrkkUXfJLC4Flt/I=
gotest.tools/v3 v3.2.0/go.mod h1:Mcr9QNxkg0uMvy/YElmo4SpXgJKWgQvYrT7Kw5RzJ1A=
honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=

View file

@ -1,173 +1,184 @@
package api package api
import ( import (
"github.com/0xJacky/Nginx-UI/server/pkg/config_list" "github.com/0xJacky/Nginx-UI/server/pkg/config_list"
"github.com/0xJacky/Nginx-UI/server/pkg/nginx" "github.com/0xJacky/Nginx-UI/server/pkg/nginx"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
"log" "log"
"net/http" "net/http"
"os" "os"
"path/filepath" "path/filepath"
"strings" "strings"
) )
func GetConfigs(c *gin.Context) { func GetConfigs(c *gin.Context) {
orderBy := c.Query("order_by") orderBy := c.Query("order_by")
sort := c.DefaultQuery("sort", "desc") sort := c.DefaultQuery("sort", "desc")
dir := c.DefaultQuery("dir", "/") dir := c.DefaultQuery("dir", "/")
mySort := map[string]string{ mySort := map[string]string{
"name": "string", "name": "string",
"modify": "time", "modify": "time",
"is_dir": "bool", "is_dir": "bool",
} }
configFiles, err := os.ReadDir(nginx.GetNginxConfPath(dir)) configFiles, err := os.ReadDir(nginx.GetNginxConfPath(dir))
if err != nil { if err != nil {
ErrHandler(c, err) ErrHandler(c, err)
return return
} }
var configs []gin.H var configs []gin.H
for i := range configFiles { for i := range configFiles {
file := configFiles[i] file := configFiles[i]
fileInfo, _ := file.Info() fileInfo, _ := file.Info()
switch mode := fileInfo.Mode(); { switch mode := fileInfo.Mode(); {
case mode.IsRegular(): // regular file, not a hidden file case mode.IsRegular(): // regular file, not a hidden file
if "." == file.Name()[0:1] { if "." == file.Name()[0:1] {
continue continue
} }
case mode&os.ModeSymlink != 0: // is a symbol case mode&os.ModeSymlink != 0: // is a symbol
var targetPath string var targetPath string
targetPath, err = os.Readlink(nginx.GetNginxConfPath(file.Name())) targetPath, err = os.Readlink(nginx.GetNginxConfPath(file.Name()))
if err != nil { if err != nil {
log.Println("GetConfigs Read Symlink Error", targetPath, err) log.Println("GetConfigs Read Symlink Error", targetPath, err)
continue continue
} }
}
configs = append(configs, gin.H{ var targetInfo os.FileInfo
"name": file.Name(), targetInfo, err = os.Stat(targetPath)
"size": fileInfo.Size(), if err != nil {
"modify": fileInfo.ModTime(), log.Println("GetConfigs Stat Error", targetPath, err)
"is_dir": file.IsDir(), continue
}) }
} // but target file is not a dir
if targetInfo.IsDir() {
continue
}
}
configs = config_list.Sort(orderBy, sort, mySort[orderBy], configs) configs = append(configs, gin.H{
"name": file.Name(),
"size": fileInfo.Size(),
"modify": fileInfo.ModTime(),
"is_dir": file.IsDir(),
})
}
c.JSON(http.StatusOK, gin.H{ configs = config_list.Sort(orderBy, sort, mySort[orderBy], configs)
"data": configs,
}) c.JSON(http.StatusOK, gin.H{
"data": configs,
})
} }
func GetConfig(c *gin.Context) { func GetConfig(c *gin.Context) {
name := c.Param("name") name := c.Param("name")
path := filepath.Join(nginx.GetNginxConfPath("/"), name) path := filepath.Join(nginx.GetNginxConfPath("/"), name)
content, err := os.ReadFile(path) content, err := os.ReadFile(path)
if err != nil { if err != nil {
ErrHandler(c, err) ErrHandler(c, err)
return return
} }
c.JSON(http.StatusOK, gin.H{ c.JSON(http.StatusOK, gin.H{
"config": string(content), "config": string(content),
}) })
} }
type AddConfigJson struct { type AddConfigJson struct {
Name string `json:"name" binding:"required"` Name string `json:"name" binding:"required"`
Content string `json:"content" binding:"required"` Content string `json:"content" binding:"required"`
} }
func AddConfig(c *gin.Context) { func AddConfig(c *gin.Context) {
var request AddConfigJson var request AddConfigJson
err := c.BindJSON(&request) err := c.BindJSON(&request)
if err != nil { if err != nil {
ErrHandler(c, err) ErrHandler(c, err)
return return
} }
name := request.Name name := request.Name
content := request.Content content := request.Content
path := filepath.Join(nginx.GetNginxConfPath("/"), name) path := filepath.Join(nginx.GetNginxConfPath("/"), name)
if _, err = os.Stat(path); err == nil { if _, err = os.Stat(path); err == nil {
c.JSON(http.StatusNotAcceptable, gin.H{ c.JSON(http.StatusNotAcceptable, gin.H{
"message": "config exist", "message": "config exist",
}) })
return return
} }
if content != "" { if content != "" {
err = os.WriteFile(path, []byte(content), 0644) err = os.WriteFile(path, []byte(content), 0644)
if err != nil { if err != nil {
ErrHandler(c, err) ErrHandler(c, err)
return return
} }
} }
output := nginx.ReloadNginx() output := nginx.ReloadNginx()
if output != "" && strings.Contains(output, "error") { if output != "" && strings.Contains(output, "error") {
c.JSON(http.StatusInternalServerError, gin.H{ c.JSON(http.StatusInternalServerError, gin.H{
"message": output, "message": output,
}) })
return return
} }
c.JSON(http.StatusOK, gin.H{ c.JSON(http.StatusOK, gin.H{
"name": name, "name": name,
"content": content, "content": content,
}) })
} }
type EditConfigJson struct { type EditConfigJson struct {
Content string `json:"content" binding:"required"` Content string `json:"content" binding:"required"`
} }
func EditConfig(c *gin.Context) { func EditConfig(c *gin.Context) {
name := c.Param("name") name := c.Param("name")
var request EditConfigJson var request EditConfigJson
err := c.BindJSON(&request) err := c.BindJSON(&request)
if err != nil { if err != nil {
ErrHandler(c, err) ErrHandler(c, err)
return return
} }
path := filepath.Join(nginx.GetNginxConfPath("/"), name) path := filepath.Join(nginx.GetNginxConfPath("/"), name)
content := request.Content content := request.Content
origContent, err := os.ReadFile(path) origContent, err := os.ReadFile(path)
if err != nil { if err != nil {
ErrHandler(c, err) ErrHandler(c, err)
return return
} }
if content != "" && content != string(origContent) { if content != "" && content != string(origContent) {
// model.CreateBackup(path) // model.CreateBackup(path)
err = os.WriteFile(path, []byte(content), 0644) err = os.WriteFile(path, []byte(content), 0644)
if err != nil { if err != nil {
ErrHandler(c, err) ErrHandler(c, err)
return return
} }
} }
output := nginx.ReloadNginx() output := nginx.ReloadNginx()
if output != "" && strings.Contains(output, "error") { if output != "" && strings.Contains(output, "error") {
c.JSON(http.StatusInternalServerError, gin.H{ c.JSON(http.StatusInternalServerError, gin.H{
"message": output, "message": output,
}) })
return return
} }
GetConfig(c) GetConfig(c)
} }

View file

@ -1,381 +1,381 @@
package api package api
import ( import (
"github.com/0xJacky/Nginx-UI/server/model" "github.com/0xJacky/Nginx-UI/server/model"
"github.com/0xJacky/Nginx-UI/server/pkg/cert" "github.com/0xJacky/Nginx-UI/server/pkg/cert"
"github.com/0xJacky/Nginx-UI/server/pkg/config_list" "github.com/0xJacky/Nginx-UI/server/pkg/config_list"
"github.com/0xJacky/Nginx-UI/server/pkg/nginx" "github.com/0xJacky/Nginx-UI/server/pkg/nginx"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
"log" "log"
"net/http" "net/http"
"os" "os"
"path/filepath" "path/filepath"
"strings" "strings"
"time" "time"
) )
func GetDomains(c *gin.Context) { func GetDomains(c *gin.Context) {
name := c.Query("name") name := c.Query("name")
orderBy := c.Query("order_by") orderBy := c.Query("order_by")
sort := c.DefaultQuery("sort", "desc") sort := c.DefaultQuery("sort", "desc")
mySort := map[string]string{ mySort := map[string]string{
"enabled": "bool", "enabled": "bool",
"name": "string", "name": "string",
"modify": "time", "modify": "time",
} }
configFiles, err := os.ReadDir(nginx.GetNginxConfPath("sites-available")) configFiles, err := os.ReadDir(nginx.GetNginxConfPath("sites-available"))
if err != nil { if err != nil {
ErrHandler(c, err) ErrHandler(c, err)
return return
} }
enabledConfig, err := os.ReadDir(filepath.Join(nginx.GetNginxConfPath("sites-enabled"))) enabledConfig, err := os.ReadDir(filepath.Join(nginx.GetNginxConfPath("sites-enabled")))
if err != nil { if err != nil {
ErrHandler(c, err) ErrHandler(c, err)
return return
} }
enabledConfigMap := make(map[string]bool) enabledConfigMap := make(map[string]bool)
for i := range enabledConfig { for i := range enabledConfig {
enabledConfigMap[enabledConfig[i].Name()] = true enabledConfigMap[enabledConfig[i].Name()] = true
} }
var configs []gin.H var configs []gin.H
for i := range configFiles { for i := range configFiles {
file := configFiles[i] file := configFiles[i]
fileInfo, _ := file.Info() fileInfo, _ := file.Info()
if !file.IsDir() { if !file.IsDir() {
if name != "" && !strings.Contains(file.Name(), name) { if name != "" && !strings.Contains(file.Name(), name) {
continue continue
} }
configs = append(configs, gin.H{ configs = append(configs, gin.H{
"name": file.Name(), "name": file.Name(),
"size": fileInfo.Size(), "size": fileInfo.Size(),
"modify": fileInfo.ModTime(), "modify": fileInfo.ModTime(),
"enabled": enabledConfigMap[file.Name()], "enabled": enabledConfigMap[file.Name()],
}) })
} }
} }
configs = config_list.Sort(orderBy, sort, mySort[orderBy], configs) configs = config_list.Sort(orderBy, sort, mySort[orderBy], configs)
c.JSON(http.StatusOK, gin.H{ c.JSON(http.StatusOK, gin.H{
"data": configs, "data": configs,
}) })
} }
type CertificateInfo struct { type CertificateInfo struct {
SubjectName string `json:"subject_name"` SubjectName string `json:"subject_name"`
IssuerName string `json:"issuer_name"` IssuerName string `json:"issuer_name"`
NotAfter time.Time `json:"not_after"` NotAfter time.Time `json:"not_after"`
NotBefore time.Time `json:"not_before"` NotBefore time.Time `json:"not_before"`
} }
func GetDomain(c *gin.Context) { func GetDomain(c *gin.Context) {
rewriteName, ok := c.Get("rewriteConfigFileName") rewriteName, ok := c.Get("rewriteConfigFileName")
name := c.Param("name") name := c.Param("name")
// for modify filename // for modify filename
if ok { if ok {
name = rewriteName.(string) name = rewriteName.(string)
} }
path := filepath.Join(nginx.GetNginxConfPath("sites-available"), name) path := filepath.Join(nginx.GetNginxConfPath("sites-available"), name)
enabled := true enabled := true
if _, err := os.Stat(filepath.Join(nginx.GetNginxConfPath("sites-enabled"), name)); os.IsNotExist(err) { if _, err := os.Stat(filepath.Join(nginx.GetNginxConfPath("sites-enabled"), name)); os.IsNotExist(err) {
enabled = false enabled = false
} }
config, err := nginx.ParseNgxConfig(path) config, err := nginx.ParseNgxConfig(path)
if err != nil { if err != nil {
ErrHandler(c, err) ErrHandler(c, err)
return return
} }
certInfoMap := make(map[int]CertificateInfo) certInfoMap := make(map[int]CertificateInfo)
var serverName string var serverName string
for serverIdx, server := range config.Servers { for serverIdx, server := range config.Servers {
for _, directive := range server.Directives { for _, directive := range server.Directives {
if directive.Directive == "server_name" { if directive.Directive == "server_name" {
serverName = strings.ReplaceAll(directive.Params, " ", "_") serverName = strings.ReplaceAll(directive.Params, " ", "_")
continue continue
} }
if directive.Directive == "ssl_certificate" { if directive.Directive == "ssl_certificate" {
pubKey, err := cert.GetCertInfo(directive.Params) pubKey, err := cert.GetCertInfo(directive.Params)
if err != nil { if err != nil {
log.Println("Failed to get certificate information", err) log.Println("Failed to get certificate information", err)
break break
} }
certInfoMap[serverIdx] = CertificateInfo{ certInfoMap[serverIdx] = CertificateInfo{
SubjectName: pubKey.Subject.CommonName, SubjectName: pubKey.Subject.CommonName,
IssuerName: pubKey.Issuer.CommonName, IssuerName: pubKey.Issuer.CommonName,
NotAfter: pubKey.NotAfter, NotAfter: pubKey.NotAfter,
NotBefore: pubKey.NotBefore, NotBefore: pubKey.NotBefore,
} }
break break
} }
} }
} }
certModel, _ := model.FirstCert(serverName) certModel, _ := model.FirstCert(serverName)
c.JSON(http.StatusOK, gin.H{ c.JSON(http.StatusOK, gin.H{
"enabled": enabled, "enabled": enabled,
"name": name, "name": name,
"config": config.BuildConfig(), "config": config.FmtCode(),
"tokenized": config, "tokenized": config,
"auto_cert": certModel.AutoCert == model.AutoCertEnabled, "auto_cert": certModel.AutoCert == model.AutoCertEnabled,
"cert_info": certInfoMap, "cert_info": certInfoMap,
}) })
} }
func EditDomain(c *gin.Context) { func EditDomain(c *gin.Context) {
name := c.Param("name") name := c.Param("name")
if name == "" { if name == "" {
c.JSON(http.StatusNotAcceptable, gin.H{ c.JSON(http.StatusNotAcceptable, gin.H{
"message": "param name is empty", "message": "param name is empty",
}) })
return return
} }
var json struct { var json struct {
Name string `json:"name" binding:"required"` Name string `json:"name" binding:"required"`
Content string `json:"content"` Content string `json:"content"`
} }
if !BindAndValid(c, &json) { if !BindAndValid(c, &json) {
return return
} }
path := filepath.Join(nginx.GetNginxConfPath("sites-available"), name) path := filepath.Join(nginx.GetNginxConfPath("sites-available"), name)
err := os.WriteFile(path, []byte(json.Content), 0644) err := os.WriteFile(path, []byte(json.Content), 0644)
if err != nil { if err != nil {
ErrHandler(c, err) ErrHandler(c, err)
return return
} }
enabledConfigFilePath := filepath.Join(nginx.GetNginxConfPath("sites-enabled"), name) enabledConfigFilePath := filepath.Join(nginx.GetNginxConfPath("sites-enabled"), name)
// rename the config file if needed // rename the config file if needed
if name != json.Name { if name != json.Name {
newPath := filepath.Join(nginx.GetNginxConfPath("sites-available"), json.Name) newPath := filepath.Join(nginx.GetNginxConfPath("sites-available"), json.Name)
// recreate soft link // recreate soft link
log.Println(enabledConfigFilePath) log.Println(enabledConfigFilePath)
if _, err = os.Stat(enabledConfigFilePath); err == nil { if _, err = os.Stat(enabledConfigFilePath); err == nil {
log.Println(enabledConfigFilePath) log.Println(enabledConfigFilePath)
_ = os.Remove(enabledConfigFilePath) _ = os.Remove(enabledConfigFilePath)
enabledConfigFilePath = filepath.Join(nginx.GetNginxConfPath("sites-enabled"), json.Name) enabledConfigFilePath = filepath.Join(nginx.GetNginxConfPath("sites-enabled"), json.Name)
err = os.Symlink(newPath, enabledConfigFilePath) err = os.Symlink(newPath, enabledConfigFilePath)
if err != nil { if err != nil {
ErrHandler(c, err) ErrHandler(c, err)
return return
} }
} }
err = os.Rename(path, newPath) err = os.Rename(path, newPath)
if err != nil { if err != nil {
ErrHandler(c, err) ErrHandler(c, err)
return return
} }
name = json.Name name = json.Name
c.Set("rewriteConfigFileName", name) c.Set("rewriteConfigFileName", name)
} }
enabledConfigFilePath = filepath.Join(nginx.GetNginxConfPath("sites-enabled"), name) enabledConfigFilePath = filepath.Join(nginx.GetNginxConfPath("sites-enabled"), name)
if _, err = os.Stat(enabledConfigFilePath); err == nil { if _, err = os.Stat(enabledConfigFilePath); err == nil {
// Test nginx configuration // Test nginx configuration
err = nginx.TestNginxConf() err = nginx.TestNginxConf()
if err != nil { if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{ c.JSON(http.StatusInternalServerError, gin.H{
"message": err.Error(), "message": err.Error(),
}) })
return return
} }
output := nginx.ReloadNginx() output := nginx.ReloadNginx()
if output != "" && strings.Contains(output, "error") { if output != "" && strings.Contains(output, "error") {
c.JSON(http.StatusInternalServerError, gin.H{ c.JSON(http.StatusInternalServerError, gin.H{
"message": output, "message": output,
}) })
return return
} }
} }
GetDomain(c) GetDomain(c)
} }
func EnableDomain(c *gin.Context) { func EnableDomain(c *gin.Context) {
configFilePath := filepath.Join(nginx.GetNginxConfPath("sites-available"), c.Param("name")) configFilePath := filepath.Join(nginx.GetNginxConfPath("sites-available"), c.Param("name"))
enabledConfigFilePath := filepath.Join(nginx.GetNginxConfPath("sites-enabled"), c.Param("name")) enabledConfigFilePath := filepath.Join(nginx.GetNginxConfPath("sites-enabled"), c.Param("name"))
_, err := os.Stat(configFilePath) _, err := os.Stat(configFilePath)
if err != nil { if err != nil {
ErrHandler(c, err) ErrHandler(c, err)
return return
} }
if _, err = os.Stat(enabledConfigFilePath); os.IsNotExist(err) { if _, err = os.Stat(enabledConfigFilePath); os.IsNotExist(err) {
err = os.Symlink(configFilePath, enabledConfigFilePath) err = os.Symlink(configFilePath, enabledConfigFilePath)
if err != nil { if err != nil {
ErrHandler(c, err) ErrHandler(c, err)
return return
} }
} }
// Test nginx config, if not pass then rollback. // Test nginx config, if not pass then rollback.
err = nginx.TestNginxConf() err = nginx.TestNginxConf()
if err != nil { if err != nil {
_ = os.Remove(enabledConfigFilePath) _ = os.Remove(enabledConfigFilePath)
c.JSON(http.StatusInternalServerError, gin.H{ c.JSON(http.StatusInternalServerError, gin.H{
"message": err.Error(), "message": err.Error(),
}) })
return return
} }
output := nginx.ReloadNginx() output := nginx.ReloadNginx()
if output != "" && strings.Contains(output, "error") { if output != "" && strings.Contains(output, "error") {
c.JSON(http.StatusInternalServerError, gin.H{ c.JSON(http.StatusInternalServerError, gin.H{
"message": output, "message": output,
}) })
return return
} }
c.JSON(http.StatusOK, gin.H{ c.JSON(http.StatusOK, gin.H{
"message": "ok", "message": "ok",
}) })
} }
func DisableDomain(c *gin.Context) { func DisableDomain(c *gin.Context) {
enabledConfigFilePath := filepath.Join(nginx.GetNginxConfPath("sites-enabled"), c.Param("name")) enabledConfigFilePath := filepath.Join(nginx.GetNginxConfPath("sites-enabled"), c.Param("name"))
_, err := os.Stat(enabledConfigFilePath) _, err := os.Stat(enabledConfigFilePath)
if err != nil { if err != nil {
ErrHandler(c, err) ErrHandler(c, err)
return return
} }
err = os.Remove(enabledConfigFilePath) err = os.Remove(enabledConfigFilePath)
if err != nil { if err != nil {
ErrHandler(c, err) ErrHandler(c, err)
return return
} }
// delete auto cert record // delete auto cert record
certModel := model.Cert{Domain: c.Param("name")} certModel := model.Cert{Domain: c.Param("name")}
err = certModel.Remove() err = certModel.Remove()
if err != nil { if err != nil {
ErrHandler(c, err) ErrHandler(c, err)
return return
} }
output := nginx.ReloadNginx() output := nginx.ReloadNginx()
if output != "" { if output != "" {
c.JSON(http.StatusInternalServerError, gin.H{ c.JSON(http.StatusInternalServerError, gin.H{
"message": output, "message": output,
}) })
return return
} }
c.JSON(http.StatusOK, gin.H{ c.JSON(http.StatusOK, gin.H{
"message": "ok", "message": "ok",
}) })
} }
func DeleteDomain(c *gin.Context) { func DeleteDomain(c *gin.Context) {
var err error var err error
name := c.Param("name") name := c.Param("name")
availablePath := filepath.Join(nginx.GetNginxConfPath("sites-available"), name) availablePath := filepath.Join(nginx.GetNginxConfPath("sites-available"), name)
enabledPath := filepath.Join(nginx.GetNginxConfPath("sites-enabled"), name) enabledPath := filepath.Join(nginx.GetNginxConfPath("sites-enabled"), name)
if _, err = os.Stat(availablePath); os.IsNotExist(err) { if _, err = os.Stat(availablePath); os.IsNotExist(err) {
c.JSON(http.StatusNotFound, gin.H{ c.JSON(http.StatusNotFound, gin.H{
"message": "site not found", "message": "site not found",
}) })
return return
} }
if _, err = os.Stat(enabledPath); err == nil { if _, err = os.Stat(enabledPath); err == nil {
c.JSON(http.StatusNotAcceptable, gin.H{ c.JSON(http.StatusNotAcceptable, gin.H{
"message": "site is enabled", "message": "site is enabled",
}) })
return return
} }
certModel := model.Cert{Domain: name} certModel := model.Cert{Domain: name}
_ = certModel.Remove() _ = certModel.Remove()
err = os.Remove(availablePath) err = os.Remove(availablePath)
if err != nil { if err != nil {
ErrHandler(c, err) ErrHandler(c, err)
return return
} }
c.JSON(http.StatusOK, gin.H{ c.JSON(http.StatusOK, gin.H{
"message": "ok", "message": "ok",
}) })
} }
func AddDomainToAutoCert(c *gin.Context) { func AddDomainToAutoCert(c *gin.Context) {
domain := c.Param("domain") domain := c.Param("domain")
domain = strings.ReplaceAll(domain, " ", "_") domain = strings.ReplaceAll(domain, " ", "_")
certModel, err := model.FirstOrCreateCert(domain) certModel, err := model.FirstOrCreateCert(domain)
if err != nil { if err != nil {
ErrHandler(c, err) ErrHandler(c, err)
return return
} }
err = certModel.Updates(&model.Cert{ err = certModel.Updates(&model.Cert{
AutoCert: model.AutoCertEnabled, AutoCert: model.AutoCertEnabled,
}) })
if err != nil { if err != nil {
ErrHandler(c, err) ErrHandler(c, err)
return return
} }
c.JSON(http.StatusOK, certModel) c.JSON(http.StatusOK, certModel)
} }
func RemoveDomainFromAutoCert(c *gin.Context) { func RemoveDomainFromAutoCert(c *gin.Context) {
domain := c.Param("domain") domain := c.Param("domain")
domain = strings.ReplaceAll(domain, " ", "_") domain = strings.ReplaceAll(domain, " ", "_")
certModel := model.Cert{ certModel := model.Cert{
Domain: domain, Domain: domain,
} }
err := certModel.Updates(&model.Cert{ err := certModel.Updates(&model.Cert{
AutoCert: model.AutoCertDisabled, AutoCert: model.AutoCertDisabled,
}) })
if err != nil { if err != nil {
ErrHandler(c, err) ErrHandler(c, err)
return return
} }
c.JSON(http.StatusOK, nil) c.JSON(http.StatusOK, nil)
} }

View file

@ -1,15 +1,13 @@
package api package api
import ( import (
"bufio" "github.com/0xJacky/Nginx-UI/server/pkg/nginx"
nginx2 "github.com/0xJacky/Nginx-UI/server/pkg/nginx"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
"net/http" "net/http"
"strings"
) )
func BuildNginxConfig(c *gin.Context) { func BuildNginxConfig(c *gin.Context) {
var ngxConf nginx2.NgxConfig var ngxConf nginx.NgxConfig
if !BindAndValid(c, &ngxConf) { if !BindAndValid(c, &ngxConf) {
return return
} }
@ -28,14 +26,7 @@ func TokenizeNginxConfig(c *gin.Context) {
return return
} }
scanner := bufio.NewScanner(strings.NewReader(json.Content)) ngxConfig := nginx.ParseNgxConfigByContent(json.Content)
ngxConfig, err := nginx2.ParseNgxConfigByScanner("", scanner)
if err != nil {
ErrHandler(c, err)
return
}
c.JSON(http.StatusOK, ngxConfig) c.JSON(http.StatusOK, ngxConfig)

View file

@ -1,88 +1,90 @@
package nginx package nginx
import ( import (
"bufio" "bufio"
"fmt" "fmt"
"strings" "github.com/tufanbarisyildirim/gonginx"
"github.com/tufanbarisyildirim/gonginx/parser"
"strings"
) )
func buildComments(orig string, indent int) (content string) { func buildComments(orig string, indent int) (content string) {
scanner := bufio.NewScanner(strings.NewReader(orig)) scanner := bufio.NewScanner(strings.NewReader(orig))
for scanner.Scan() { for scanner.Scan() {
content += strings.Repeat("\t", indent) + "# " + scanner.Text() + "\n" content += strings.Repeat("\t", indent) + "# " + scanner.Text() + "\n"
} }
content = strings.TrimLeft(content, "\n") content = strings.TrimLeft(content, "\n")
return return
} }
func (c *NgxConfig) BuildConfig() (content string) { func (c *NgxConfig) BuildConfig() (content string) {
// Custom // Custom
if c.Custom != "" { if c.Custom != "" {
content += fmtCode(c.Custom) content += c.Custom
content += "\n\n" content += "\n\n"
} }
// Upstreams // Upstreams
for _, u := range c.Upstreams { for _, u := range c.Upstreams {
upstream := "" upstream := ""
var comments string var comments string
for _, directive := range u.Directives { for _, directive := range u.Directives {
if directive.Comments != "" { if directive.Comments != "" {
comments = buildComments(directive.Comments, 1) comments = buildComments(directive.Comments, 1)
} }
upstream += fmt.Sprintf("%s\t%s;\n", comments, directive.Orig()) upstream += fmt.Sprintf("%s\t%s;\n", comments, directive.Orig())
} }
comments = buildComments(u.Comments, 1) comments = buildComments(u.Comments, 1)
content += fmt.Sprintf("upstream %s {\n%s%s}\n\n", u.Name, comments, upstream) content += fmt.Sprintf("upstream %s {\n%s%s}\n\n", u.Name, comments, upstream)
} }
// Servers // Servers
for _, s := range c.Servers { for _, s := range c.Servers {
server := "" server := ""
// directives // directives
for _, directive := range s.Directives { for _, directive := range s.Directives {
var comments string var comments string
if directive.Comments != "" { if directive.Comments != "" {
comments = buildComments(directive.Comments, 1) comments = buildComments(directive.Comments, 1)
} }
if directive.Directive == If { if directive.Params != "" {
server += fmt.Sprintf("%s%s\n", comments, fmtCodeWithIndent(directive.Params, 1)) server += fmt.Sprintf("%s\t%s;\n", comments, directive.Orig())
} else if directive.Params != "" { }
server += fmt.Sprintf("%s\t%s;\n", comments, directive.Orig()) }
}
}
if len(s.Directives) > 0 { if len(s.Directives) > 0 {
server += "\n" server += "\n"
} }
// locations // locations
locations := "" locations := ""
for _, location := range s.Locations { for _, location := range s.Locations {
locationContent := "" locationContent := ""
scanner := bufio.NewScanner(strings.NewReader(location.Content)) scanner := bufio.NewScanner(strings.NewReader(location.Content))
for scanner.Scan() { for scanner.Scan() {
locationContent += "\t\t" + scanner.Text() + "\n" locationContent += "\t\t" + scanner.Text() + "\n"
} }
var comments string var comments string
if location.Comments != "" { if location.Comments != "" {
comments = buildComments(location.Comments, 1) comments = buildComments(location.Comments, 1)
} }
locations += fmt.Sprintf("%s\tlocation %s {\n%s\t}\n\n", comments, location.Path, locationContent) locations += fmt.Sprintf("%s\tlocation %s {\n%s\t}\n\n", comments, location.Path, locationContent)
} }
server += locations server += locations
var comments string var comments string
if s.Comments != "" { if s.Comments != "" {
comments = buildComments(s.Comments, 0) + "\n" comments = buildComments(s.Comments, 0) + "\n"
} }
content += fmt.Sprintf("%sserver {\n%s}\n\n", comments, server) content += fmt.Sprintf("%sserver {\n%s}\n\n", comments, server)
} }
p := parser.NewStringParser(content)
return config := p.Parse()
content = gonginx.DumpConfig(config, gonginx.IndentedStyle)
return
} }

View file

@ -0,0 +1,36 @@
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}
server {
listen 80;
listen [::]:80;
server_name blog.jackyu.cn test.jackyu.cn;
location /.well-known/acme-challenge {
proxy_set_header Host $host;
proxy_set_header X-Real_IP $remote_addr;
proxy_set_header X-Forwarded-For $remote_addr:$remote_port;
proxy_pass http://127.0.0.1:9180;
}
}
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name blog.jackyu.cn test.jackyu.cn;
ssl_certificate /etc/nginx/ssl/blog.jackyu.cn_test.jackyu.cn/fullchain.cer;
ssl_certificate_key /etc/nginx/ssl/blog.jackyu.cn_test.jackyu.cn/private.key;
include enable-php-8.conf;
location /.well-known/acme-challenge {
proxy_set_header Host $host;
proxy_set_header X-Real_IP $remote_addr;
proxy_set_header X-Forwarded-For $remote_addr:$remote_port;
proxy_pass http://127.0.0.1:9180;
}
}

View file

@ -1,49 +1,10 @@
package nginx package nginx
import ( import (
"bufio" "github.com/tufanbarisyildirim/gonginx"
"github.com/emirpasic/gods/stacks/linkedliststack"
"strings"
) )
func fmtCode(content string) (fmtContent string) { func (c *NgxConfig) FmtCode() (fmtContent string) {
fmtContent = fmtCodeWithIndent(content, 0) fmtContent = gonginx.DumpConfig(c.c, gonginx.IndentedStyle)
return return
}
func fmtCodeWithIndent(content string, indent int) (fmtContent string) {
/*
Format content
1. TrimSpace for each line
2. use stack to count how many \t should add
*/
stack := linkedliststack.New()
scanner := bufio.NewScanner(strings.NewReader(content))
for scanner.Scan() {
text := scanner.Text()
text = strings.TrimSpace(text)
before := stack.Size()
for _, char := range text {
matchParentheses(stack, char)
}
after := stack.Size()
fmtContent += strings.Repeat("\t", indent)
if before == after {
fmtContent += strings.Repeat("\t", stack.Size()) + text + "\n"
} else {
fmtContent += text + "\n"
}
}
fmtContent = strings.Trim(fmtContent, "\n")
return
} }

View file

@ -0,0 +1,49 @@
package nginx
import (
"fmt"
"github.com/tufanbarisyildirim/gonginx"
"github.com/tufanbarisyildirim/gonginx/parser"
"strings"
"testing"
)
func TestNgxConfParse(t *testing.T) {
p, err := parser.NewParser("conf/nextcloud_ngx.conf")
if err != nil {
fmt.Println(err)
return
}
n := p.Parse()
fn(n.Block, 0)
c, err := ParseNgxConfig("conf/nextcloud_ngx.conf")
if err != nil {
fmt.Println(err)
return
}
fmt.Println(c)
c, err = ParseNgxConfig("conf/test.conf")
if err != nil {
fmt.Println(err)
return
}
fmt.Println(c)
}
func fn(block gonginx.IBlock, deep int) {
if block == nil {
return
}
for _, v := range block.GetDirectives() {
if len(v.GetComment()) > 0 {
for _, c := range v.GetComment() {
fmt.Println(strings.Repeat("\t", deep), c)
}
}
fmt.Println(fmt.Sprintf("%s%s %s", strings.Repeat("\t", deep), v.GetName(), strings.Join(v.GetParameters(), " ")))
fn(v.GetBlock(), deep+1)
}
}

View file

@ -1,150 +1,158 @@
package nginx package nginx
import ( import (
"bufio"
"github.com/emirpasic/gods/stacks/linkedliststack"
"github.com/pkg/errors" "github.com/pkg/errors"
"os" "github.com/tufanbarisyildirim/gonginx"
"github.com/tufanbarisyildirim/gonginx/parser"
"strings" "strings"
"unicode"
) )
const ( const (
Server = "server" Server = "server"
Location = "location" Location = "location"
Upstream = "upstream" Upstream = "upstream"
CommentStart = "#"
Empty = ""
If = "if"
) )
func matchParentheses(stack *linkedliststack.Stack, v int32) { func (s *NgxServer) parseServer(directive gonginx.IDirective) {
if v == '{' { if directive.GetBlock() == nil {
stack.Push(v) return
} else if v == '}' { }
// stack is not empty and the top is == '{' for _, d := range directive.GetBlock().GetDirectives() {
if top, ok := stack.Peek(); ok && top == '{' { switch d.GetName() {
stack.Pop() case Location:
} else { location := &NgxLocation{
// fail Path: strings.Join(d.GetParameters(), " "),
stack.Push(v) Comments: buildComment(d.GetComment()),
}
location.parseLocation(d, 0)
s.Locations = append(s.Locations, location)
default:
dir := &NgxDirective{
Directive: d.GetName(),
Comments: buildComment(d.GetComment()),
}
dir.parseDirective(d, 0)
s.Directives = append(s.Directives, dir)
} }
} }
} }
func parseDirective(scanner *bufio.Scanner) (d NgxDirective) { func (l *NgxLocation) parseLocation(directive gonginx.IDirective, deep int) {
text := strings.TrimSpace(scanner.Text()) if directive.GetBlock() == nil {
// escape empty line or comment line
if len(text) < 1 {
return return
} }
for _, location := range directive.GetBlock().GetDirectives() {
if text[0] == '#' { if len(location.GetComment()) > 0 {
d.Directive = "#" for _, c := range location.GetComment() {
d.Params = strings.TrimLeft(text, "#") l.Content += strings.Repeat("\t", deep) + c + "\n"
return
}
if len(text) > 1 {
sep := len(text) - 1
for k, v := range text {
if unicode.IsSpace(v) {
sep = k
break
} }
} }
l.Content += strings.Repeat("\t", deep) + location.GetName() + " " + strings.Join(location.GetParameters(), " ") + ";\n"
d.Directive = text[0:sep] l.parseLocation(location, deep+1)
d.Params = text[sep:]
} else {
d.Directive = text
return
} }
}
stack := linkedliststack.New() func (d *NgxDirective) parseDirective(directive gonginx.IDirective, deep int) {
if directive.GetBlock() != nil {
if d.Directive == Server || d.Directive == Upstream || d.Directive == Location || d.Directive == If { d.Params += directive.GetName() + " "
// { } in one line d.Directive = ""
// location = /.well-known/carddav { return 301 /remote.php/dav/; } }
if strings.Contains(d.Params, "{") { d.Params += strings.Join(directive.GetParameters(), " ")
for _, v := range d.Params { if directive.GetBlock() != nil {
matchParentheses(stack, v) d.Params += " {\n"
} for _, location := range directive.GetBlock().GetDirectives() {
if len(location.GetComment()) > 0 {
if stack.Empty() { for _, c := range location.GetComment() {
return d.Params += strings.Repeat("\t", deep) + c + "\n"
}
}
// 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() { d.Params += strings.Repeat("\t", deep+1) + location.GetName() + " " +
break strings.Join(location.GetParameters(), " ") + ";\n"
// d.parseDirective(location, deep+1)
if location.GetBlock() == nil {
continue
}
for _, v := range location.GetBlock().GetDirectives() {
d.parseDirective(v, deep+1)
} }
} }
d.Params += "}\n"
return
} }
d.Params = strings.TrimSpace(d.Params) }
func (u *NgxUpstream) parseUpstream(directive gonginx.IDirective) {
if directive.GetBlock() == nil {
return
}
for _, us := range directive.GetBlock().GetDirectives() {
d := &NgxDirective{
Directive: us.GetName(),
Params: strings.Join(us.GetParameters(), " "),
Comments: buildComment(us.GetComment()),
}
u.Directives = append(u.Directives, d)
}
}
func (c *NgxConfig) parseCustom(directive gonginx.IDirective) {
if directive.GetBlock() == nil {
return
}
c.Custom += "{\n"
for _, v := range directive.GetBlock().GetDirectives() {
c.Custom += strings.Join(v.GetComment(), "\n") + "\n" +
v.GetName() + " " + strings.Join(v.GetParameters(), " ") + ";\n"
}
c.Custom += "}\n"
}
func buildComment(c []string) string {
return strings.ReplaceAll(strings.Join(c, "\n"), "#", "")
}
func parse(block gonginx.IBlock, ngxConfig *NgxConfig) {
if block == nil {
return
}
for _, v := range block.GetDirectives() {
comments := buildComment(v.GetComment())
switch v.GetName() {
case Server:
server := NewNgxServer()
server.Comments = comments
server.parseServer(v)
ngxConfig.Servers = append(ngxConfig.Servers, server)
case Upstream:
upstream := &NgxUpstream{}
upstream.Comments = comments
upstream.parseUpstream(v)
ngxConfig.Upstreams = append(ngxConfig.Upstreams, upstream)
default:
ngxConfig.Custom += strings.Join(v.GetComment(), "\n") + "\n" +
v.GetName() + " " + strings.Join(v.GetParameters(), " ") + "\n"
ngxConfig.parseCustom(v)
}
}
}
func ParseNgxConfigByContent(content string) (ngxConfig *NgxConfig) {
p := parser.NewStringParser(content)
c := p.Parse()
ngxConfig = NewNgxConfig("")
ngxConfig.c = c
parse(c.Block, ngxConfig)
return return
} }
func ParseNgxConfigByScanner(filename string, scanner *bufio.Scanner) (c *NgxConfig, err error) { func ParseNgxConfig(filename string) (ngxConfig *NgxConfig, err error) {
c = NewNgxConfig(filename) p, err := parser.NewParser(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)
case Empty:
continue
default:
c.Custom += d.Orig() + "\n"
}
}
if err = scanner.Err(); err != nil {
return nil, errors.Wrap(err, "error scanner in ParseNgxConfig")
}
// Attach the rest of the comments to the last server
if len(c.Servers) > 0 {
c.Servers[len(c.Servers)-1].Comments += c.commentQueue.DequeueAllComments()
}
return c, nil
}
func ParseNgxConfig(filename string) (c *NgxConfig, err error) {
file, err := os.Open(filename)
if err != nil { if err != nil {
return nil, errors.Wrap(err, "error open file in ParseNgxConfig") return nil, errors.Wrap(err, "error ParseNgxConfig")
} }
defer file.Close() c := p.Parse()
ngxConfig = NewNgxConfig(filename)
scanner := bufio.NewScanner(file) ngxConfig.c = c
parse(c.Block, ngxConfig)
return ParseNgxConfigByScanner(filename, scanner) return
} }

View file

@ -1,125 +0,0 @@
package nginx
import (
"bufio"
"regexp"
"strings"
"unicode"
)
func (c *NgxConfig) parseServer(scanner *bufio.Scanner) {
server := NewNgxServer()
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 the rest of the comments to the last location
if len(server.Locations) > 0 {
server.Locations[len(server.Locations)-1].Comments += server.commentQueue.DequeueAllComments()
}
// 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{}
for scanner.Scan() {
d := NgxDirective{}
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 = append(upstream.Directives, &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, "#")
if d.Directive == If {
d.Params = "if " + d.Params
d.Params = fmtCode(d.Params)
s.Directives = append(s.Directives, &d)
return
}
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 = append(s.Directives, &d)
}
}
}
}
}
func (s *NgxServer) parseLocation(str string) {
path, content, _ := strings.Cut(str, "{")
path = strings.TrimSpace(path)
content = strings.TrimSpace(content)
content = strings.Trim(content, "}")
content = fmtCode(content)
location := &NgxLocation{
Path: path,
Content: content,
}
location.Comments = s.commentQueue.DequeueAllComments()
s.Locations = append(s.Locations, location)
}

View file

@ -1,27 +1,22 @@
package nginx package nginx
import ( import (
"github.com/emirpasic/gods/queues/linkedlistqueue" "github.com/tufanbarisyildirim/gonginx"
"strings" "strings"
) )
type CommentQueue struct {
*linkedlistqueue.Queue
}
type NgxConfig struct { type NgxConfig struct {
FileName string `json:"file_name"` FileName string `json:"file_name"`
Upstreams []*NgxUpstream `json:"upstreams"` Upstreams []*NgxUpstream `json:"upstreams"`
Servers []*NgxServer `json:"servers"` Servers []*NgxServer `json:"servers"`
Custom string `json:"custom"` Custom string `json:"custom"`
commentQueue *CommentQueue c *gonginx.Config
} }
type NgxServer struct { type NgxServer struct {
Directives []*NgxDirective `json:"directives"` Directives []*NgxDirective `json:"directives"`
Locations []*NgxLocation `json:"locations"` Locations []*NgxLocation `json:"locations"`
Comments string `json:"comments"` Comments string `json:"comments"`
commentQueue *CommentQueue
} }
type NgxUpstream struct { type NgxUpstream struct {
@ -42,18 +37,6 @@ type NgxLocation struct {
Comments string `json:"comments"` 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 { func (d *NgxDirective) Orig() string {
return d.Directive + " " + d.Params return d.Directive + " " + d.Params
} }
@ -65,16 +48,14 @@ func (d *NgxDirective) TrimParams() {
func NewNgxServer() *NgxServer { func NewNgxServer() *NgxServer {
return &NgxServer{ return &NgxServer{
Locations: make([]*NgxLocation, 0), Locations: make([]*NgxLocation, 0),
Directives: make([]*NgxDirective, 0), Directives: make([]*NgxDirective, 0),
commentQueue: &CommentQueue{linkedlistqueue.New()},
} }
} }
func NewNgxConfig(filename string) *NgxConfig { func NewNgxConfig(filename string) *NgxConfig {
return &NgxConfig{ return &NgxConfig{
FileName: filename, FileName: filename,
commentQueue: &CommentQueue{linkedlistqueue.New()}, Upstreams: make([]*NgxUpstream, 0),
Upstreams: make([]*NgxUpstream, 0),
} }
} }

View file

@ -1,42 +0,0 @@
package test
import (
"fmt"
"github.com/0xJacky/Nginx-UI/server/pkg/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("==========================")
}
}
}