This commit is contained in:
0xJacky 2021-10-18 23:13:47 +08:00
parent 953f943e01
commit 27c4b82d54
22 changed files with 97 additions and 85 deletions

View file

@ -1 +1 @@
<!DOCTYPE html><html lang=""><head><meta charset="utf-8"><meta content="IE=edge" http-equiv="X-UA-Compatible"><meta content="width=device-width,initial-scale=1,user-scalable=0" name="viewport"><link href="/favicon.ico" rel="icon"><title>Nginx UI</title><link href="/js/chunk-006e4cbc.ce4defda.js" rel="prefetch"><link href="/js/chunk-1188de6e.f8e092e0.js" rel="prefetch"><link href="/js/chunk-15551262.4339ed58.js" rel="prefetch"><link href="/js/chunk-1e5147a5.3620bb79.js" rel="prefetch"><link href="/js/chunk-23e3da44.bae4ce87.js" rel="prefetch"><link href="/js/chunk-2b94df79.445ebac6.js" rel="prefetch"><link href="/js/chunk-2d0cf277.c3db42df.js" rel="prefetch"><link href="/js/chunk-32df5a7d.cdbdd8b4.js" rel="prefetch"><link href="/js/chunk-59b694c3.ef41aa76.js" rel="prefetch"><link href="/js/chunk-62217c82.cc165e2d.js" rel="prefetch"><link href="/js/chunk-680936db.547a4157.js" rel="prefetch"><link href="/js/chunk-7723cf62.c3f452ca.js" rel="prefetch"><link href="/js/chunk-96068e84.ce69e34f.js" rel="prefetch"><link href="/js/chunk-ddbf168e.82ea029a.js" rel="prefetch"><link href="/js/chunk-e0ad5fdc.44fe5a47.js" rel="prefetch"><link href="/js/chunk-vendors.4df0321b.js" rel="modulepreload" as="script"><link href="/js/index.8876c5f8.js" rel="modulepreload" as="script"></head><body><noscript><strong>We're sorry but Nginx UI doesn't work properly without JavaScript enabled. Please enable it to continue.</strong></noscript><div id="app"></div><script type="module" src="/js/chunk-vendors.4df0321b.js"></script><script type="module" src="/js/index.8876c5f8.js"></script><script>!function(){var e=document,t=e.createElement("script");if(!("noModule"in t)&&"onbeforeload"in t){var n=!1;e.addEventListener("beforeload",function(e){if(e.target===t)n=!0;else if(!e.target.hasAttribute("nomodule")||!n)return;e.preventDefault()},!0),t.type="module",t.src=".",e.head.appendChild(t),t.remove()}}();</script><script src="/js/chunk-vendors-legacy.4df0321b.js" nomodule></script><script src="/js/index-legacy.d32207d3.js" nomodule></script></body></html>
<!DOCTYPE html><html lang=""><head><meta charset="utf-8"><meta content="IE=edge" http-equiv="X-UA-Compatible"><meta content="width=device-width,initial-scale=1,user-scalable=0" name="viewport"><link href="/favicon.ico" rel="icon"><title>Nginx UI</title><link href="/js/chunk-006e4cbc.ce4defda.js" rel="prefetch"><link href="/js/chunk-1188de6e.f8e092e0.js" rel="prefetch"><link href="/js/chunk-15551262.4339ed58.js" rel="prefetch"><link href="/js/chunk-1e5147a5.3620bb79.js" rel="prefetch"><link href="/js/chunk-23e3da44.bae4ce87.js" rel="prefetch"><link href="/js/chunk-2b94df79.2bf29671.js" rel="prefetch"><link href="/js/chunk-2d0cf277.c3db42df.js" rel="prefetch"><link href="/js/chunk-32df5a7d.cdbdd8b4.js" rel="prefetch"><link href="/js/chunk-59b694c3.ef41aa76.js" rel="prefetch"><link href="/js/chunk-5f8bd6de.b088830d.js" rel="prefetch"><link href="/js/chunk-680936db.547a4157.js" rel="prefetch"><link href="/js/chunk-7723cf62.c3f452ca.js" rel="prefetch"><link href="/js/chunk-96068e84.05f16d69.js" rel="prefetch"><link href="/js/chunk-ddbf168e.82ea029a.js" rel="prefetch"><link href="/js/chunk-e0ad5fdc.44fe5a47.js" rel="prefetch"><link href="/js/chunk-vendors.b74315d6.js" rel="modulepreload" as="script"><link href="/js/index.fa8b2c24.js" rel="modulepreload" as="script"></head><body><noscript><strong>We're sorry but Nginx UI doesn't work properly without JavaScript enabled. Please enable it to continue.</strong></noscript><div id="app"></div><script type="module" src="/js/chunk-vendors.b74315d6.js"></script><script type="module" src="/js/index.fa8b2c24.js"></script><script>!function(){var e=document,t=e.createElement("script");if(!("noModule"in t)&&"onbeforeload"in t){var n=!1;e.addEventListener("beforeload",function(e){if(e.target===t)n=!0;else if(!e.target.hasAttribute("nomodule")||!n)return;e.preventDefault()},!0),t.type="module",t.src=".",e.head.appendChild(t),t.remove()}}();</script><script src="/js/chunk-vendors-legacy.b74315d6.js" nomodule></script><script src="/js/index-legacy.e8aba462.js" nomodule></script></body></html>

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -1 +1 @@
(window["webpackJsonp"]=window["webpackJsonp"]||[]).push([["chunk-96068e84"],{"0d92":function(e,t,a){"use strict";a("e6a6")},"7c22":function(e,t,a){var n=a("24fb");t=n(!1),t.push([e.i,".egg[data-v-0db462a3]{padding:10px 0}.ant-btn[data-v-0db462a3]{margin:10px 10px 0 0}",""]),e.exports=t},e6a6:function(e,t,a){var n=a("7c22");n.__esModule&&(n=n.default),"string"===typeof n&&(n=[[e.i,n,""]]),n.locals&&(e.exports=n.locals);var r=a("499e").default;r("1fb1813a",n,!0,{sourceMap:!1,shadowMode:!1})},f820:function(e,t,a){"use strict";a.r(t);var n=function(){var e=this,t=e.$createElement,a=e._self._c||t;return a("a-card",[a("h2",[e._v("Nginx UI")]),a("p",[e._v("Yet another WebUI for Nginx")]),a("p",[e._v("Version: "+e._s(e.version)+" ("+e._s(e.build_id)+")")]),a("h3",[e._v("项目组")]),a("p",[e._v("Designer"),a("a",{attrs:{href:"https://jackyu.cn/"}},[e._v("@0xJacky")])]),a("h3",[e._v("技术栈")]),a("p",[e._v("Go")]),a("p",[e._v("Gin")]),a("p",[e._v("Vue")]),a("p",[e._v("Websocket")]),a("h3",[e._v("开源协议")]),a("p",[e._v("GNU General Public License v2.0")]),a("p",[e._v("Copyright © 2020 - "+e._s(e.this_year)+" 0xJacky ")])])},r=[],s=a("1da1"),i=(a("96cf"),{name:"About",data:function(){var e,t=new Date;return{this_year:t.getFullYear(),version:"1.0.0",build_id:null!==(e="15")&&void 0!==e?e:"开发模式",api_root:"/api"}},methods:{changeUserPower:function(e){var t=this;return Object(s["a"])(regeneratorRuntime.mark((function a(){return regeneratorRuntime.wrap((function(a){while(1)switch(a.prev=a.next){case 0:return a.next=2,t.$store.dispatch("update_mock_user",{power:e});case 2:return a.next=4,t.$api.user.info();case 4:return a.next=6,t.$message.success("修改成功");case 6:case"end":return a.stop()}}),a)})))()}}}),o=i,c=(a("0d92"),a("2877")),u=Object(c["a"])(o,n,r,!1,null,"0db462a3",null);t["default"]=u.exports}}]);
(window["webpackJsonp"]=window["webpackJsonp"]||[]).push([["chunk-96068e84"],{"0d92":function(e,t,a){"use strict";a("e6a6")},"7c22":function(e,t,a){var n=a("24fb");t=n(!1),t.push([e.i,".egg[data-v-0db462a3]{padding:10px 0}.ant-btn[data-v-0db462a3]{margin:10px 10px 0 0}",""]),e.exports=t},e6a6:function(e,t,a){var n=a("7c22");n.__esModule&&(n=n.default),"string"===typeof n&&(n=[[e.i,n,""]]),n.locals&&(e.exports=n.locals);var r=a("499e").default;r("1fb1813a",n,!0,{sourceMap:!1,shadowMode:!1})},f820:function(e,t,a){"use strict";a.r(t);var n=function(){var e=this,t=e.$createElement,a=e._self._c||t;return a("a-card",[a("h2",[e._v("Nginx UI")]),a("p",[e._v("Yet another WebUI for Nginx")]),a("p",[e._v("Version: "+e._s(e.version)+" ("+e._s(e.build_id)+")")]),a("h3",[e._v("项目组")]),a("p",[e._v("Designer"),a("a",{attrs:{href:"https://jackyu.cn/"}},[e._v("@0xJacky")])]),a("h3",[e._v("技术栈")]),a("p",[e._v("Go")]),a("p",[e._v("Gin")]),a("p",[e._v("Vue")]),a("p",[e._v("Websocket")]),a("h3",[e._v("开源协议")]),a("p",[e._v("GNU General Public License v2.0")]),a("p",[e._v("Copyright © 2020 - "+e._s(e.this_year)+" 0xJacky ")])])},r=[],s=a("1da1"),i=(a("96cf"),{name:"About",data:function(){var e,t=new Date;return{this_year:t.getFullYear(),version:"1.0.0",build_id:null!==(e="16")&&void 0!==e?e:"开发模式",api_root:"/api"}},methods:{changeUserPower:function(e){var t=this;return Object(s["a"])(regeneratorRuntime.mark((function a(){return regeneratorRuntime.wrap((function(a){while(1)switch(a.prev=a.next){case 0:return a.next=2,t.$store.dispatch("update_mock_user",{power:e});case 2:return a.next=4,t.$api.user.info();case 4:return a.next=6,t.$message.success("修改成功");case 6:case"end":return a.stop()}}),a)})))()}}}),o=i,c=(a("0d92"),a("2877")),u=Object(c["a"])(o,n,r,!1,null,"0db462a3",null);t["default"]=u.exports}}]);

View file

@ -1 +1 @@
(window["webpackJsonp"]=window["webpackJsonp"]||[]).push([["chunk-96068e84"],{"0d92":function(e,t,a){"use strict";a("e6a6")},"7c22":function(e,t,a){var n=a("24fb");t=n(!1),t.push([e.i,".egg[data-v-0db462a3]{padding:10px 0}.ant-btn[data-v-0db462a3]{margin:10px 10px 0 0}",""]),e.exports=t},e6a6:function(e,t,a){var n=a("7c22");n.__esModule&&(n=n.default),"string"===typeof n&&(n=[[e.i,n,""]]),n.locals&&(e.exports=n.locals);var r=a("499e").default;r("1fb1813a",n,!0,{sourceMap:!1,shadowMode:!1})},f820:function(e,t,a){"use strict";a.r(t);var n=function(){var e=this,t=e.$createElement,a=e._self._c||t;return a("a-card",[a("h2",[e._v("Nginx UI")]),a("p",[e._v("Yet another WebUI for Nginx")]),a("p",[e._v("Version: "+e._s(e.version)+" ("+e._s(e.build_id)+")")]),a("h3",[e._v("项目组")]),a("p",[e._v("Designer"),a("a",{attrs:{href:"https://jackyu.cn/"}},[e._v("@0xJacky")])]),a("h3",[e._v("技术栈")]),a("p",[e._v("Go")]),a("p",[e._v("Gin")]),a("p",[e._v("Vue")]),a("p",[e._v("Websocket")]),a("h3",[e._v("开源协议")]),a("p",[e._v("GNU General Public License v2.0")]),a("p",[e._v("Copyright © 2020 - "+e._s(e.this_year)+" 0xJacky ")])])},r=[],s=a("1da1"),i=(a("96cf"),{name:"About",data:function(){var e,t=new Date;return{this_year:t.getFullYear(),version:"1.0.0",build_id:null!==(e="15")&&void 0!==e?e:"开发模式",api_root:"/api"}},methods:{changeUserPower:function(e){var t=this;return Object(s["a"])(regeneratorRuntime.mark((function a(){return regeneratorRuntime.wrap((function(a){while(1)switch(a.prev=a.next){case 0:return a.next=2,t.$store.dispatch("update_mock_user",{power:e});case 2:return a.next=4,t.$api.user.info();case 4:return a.next=6,t.$message.success("修改成功");case 6:case"end":return a.stop()}}),a)})))()}}}),o=i,c=(a("0d92"),a("2877")),u=Object(c["a"])(o,n,r,!1,null,"0db462a3",null);t["default"]=u.exports}}]);
(window["webpackJsonp"]=window["webpackJsonp"]||[]).push([["chunk-96068e84"],{"0d92":function(e,t,a){"use strict";a("e6a6")},"7c22":function(e,t,a){var n=a("24fb");t=n(!1),t.push([e.i,".egg[data-v-0db462a3]{padding:10px 0}.ant-btn[data-v-0db462a3]{margin:10px 10px 0 0}",""]),e.exports=t},e6a6:function(e,t,a){var n=a("7c22");n.__esModule&&(n=n.default),"string"===typeof n&&(n=[[e.i,n,""]]),n.locals&&(e.exports=n.locals);var r=a("499e").default;r("1fb1813a",n,!0,{sourceMap:!1,shadowMode:!1})},f820:function(e,t,a){"use strict";a.r(t);var n=function(){var e=this,t=e.$createElement,a=e._self._c||t;return a("a-card",[a("h2",[e._v("Nginx UI")]),a("p",[e._v("Yet another WebUI for Nginx")]),a("p",[e._v("Version: "+e._s(e.version)+" ("+e._s(e.build_id)+")")]),a("h3",[e._v("项目组")]),a("p",[e._v("Designer"),a("a",{attrs:{href:"https://jackyu.cn/"}},[e._v("@0xJacky")])]),a("h3",[e._v("技术栈")]),a("p",[e._v("Go")]),a("p",[e._v("Gin")]),a("p",[e._v("Vue")]),a("p",[e._v("Websocket")]),a("h3",[e._v("开源协议")]),a("p",[e._v("GNU General Public License v2.0")]),a("p",[e._v("Copyright © 2020 - "+e._s(e.this_year)+" 0xJacky ")])])},r=[],s=a("1da1"),i=(a("96cf"),{name:"About",data:function(){var e,t=new Date;return{this_year:t.getFullYear(),version:"1.0.0",build_id:null!==(e="16")&&void 0!==e?e:"开发模式",api_root:"/api"}},methods:{changeUserPower:function(e){var t=this;return Object(s["a"])(regeneratorRuntime.mark((function a(){return regeneratorRuntime.wrap((function(a){while(1)switch(a.prev=a.next){case 0:return a.next=2,t.$store.dispatch("update_mock_user",{power:e});case 2:return a.next=4,t.$api.user.info();case 4:return a.next=6,t.$message.success("修改成功");case 6:case"end":return a.stop()}}),a)})))()}}}),o=i,c=(a("0d92"),a("2877")),u=Object(c["a"])(o,n,r,!1,null,"0db462a3",null);t["default"]=u.exports}}]);

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -1 +1 @@
{"version":"1.0.0","build_id":11,"total_build":15}
{"version":"1.0.0","build_id":12,"total_build":16}

View file

@ -3,7 +3,7 @@
<a-collapse :bordered="false" default-active-key="1">
<a-collapse-panel key="1" :header="name ? '编辑站点:' + name : '添加站点'">
<p>您的配置文件中应当有对应的字段时下列表单中的设置才能生效配置文件名称创建后不可修改</p>
<std-data-entry :data-list="columns" v-model="config" @change_support_ssl="change_support_ssl"/>
<std-data-entry :data-list="columns" v-model="config" />
<cert-info :domain="name" ref="cert-info" v-if="name"/>
<br/>
<a-space>
@ -53,7 +53,8 @@ export default {
support_ssl: false
},
configText: "",
ws: null
ws: null,
ok: false
}
},
watch: {
@ -65,6 +66,9 @@ export default {
this.unparse()
},
deep: true
},
'config.support_ssl'() {
if (this.ok) this.change_support_ssl()
}
},
created() {
@ -80,7 +84,9 @@ export default {
if (this.name) {
this.$api.domain.get(this.name).then(r => {
this.configText = r.config
this.parse(r)
this.parse(r).then(()=>{
this.ok = true
})
}).catch(r => {
console.log(r)
this.$message.error("服务器错误")
@ -99,7 +105,7 @@ export default {
this.get_template()
}
},
parse(r) {
async parse(r) {
const text = r.config
const reg = {
http_listen_port: /listen[\s](.*);/i,
@ -126,7 +132,7 @@ export default {
this.config.support_ssl = true
}
},
unparse() {
async unparse() {
let text = this.configText
// http_listen_port: /listen (.*);/i,
// https_listen_port: /listen (.*) ssl/i,
@ -182,7 +188,9 @@ export default {
this.$api.domain.save(this.name ? this.name : this.config.name, {content: this.configText}).then(r => {
this.parse(r)
this.$message.success("保存成功")
this.$refs["cert-info"].get()
if (this.name) {
this.$refs["cert-info"].get()
}
}).catch(r => {
console.log(r)
this.$message.error("保存错误" + r.message !== undefined ? " " + r.message : null, 10)

View file

@ -1 +1 @@
{"version":"1.0.0","build_id":11,"total_build":15}
{"version":"1.0.0","build_id":12,"total_build":16}

View file

@ -18,7 +18,7 @@ module.exports = {
},
},
devServer: {
proxy: 'https://nginx.jackyu.cn/api'
proxy: 'https://hangzhou.jackyu.cn/api'
},
productionSourceMap: false,

View file

@ -1,15 +1,42 @@
package api
import (
"github.com/gin-gonic/gin"
"log"
"bytes"
"encoding/json"
"github.com/gin-gonic/gin"
"github.com/gin-gonic/gin/binding"
"github.com/go-playground/locales/zh"
"log"
"net/http"
"regexp"
"strings"
ut "github.com/go-playground/universal-translator"
val "github.com/go-playground/validator/v10"
val "github.com/go-playground/validator/v10"
zhTranslations "github.com/go-playground/validator/v10/translations/zh"
)
type JsonSnakeCase struct {
Value interface{}
}
func (c JsonSnakeCase) MarshalJSON() ([]byte, error) {
// Regexp definitions
var keyMatchRegex = regexp.MustCompile(`\"(\w+)\":`)
var wordBarrierRegex = regexp.MustCompile(`(\w)([A-Z])`)
marshalled, err := json.Marshal(c.Value)
converted := keyMatchRegex.ReplaceAllFunc(
marshalled,
func(match []byte) []byte {
return bytes.ToLower(wordBarrierRegex.ReplaceAll(
match,
[]byte(`${1}_${2}`),
))
},
)
return converted, err
}
func ErrorHandler(c *gin.Context, err error) {
log.Println(err)
c.JSON(http.StatusInternalServerError, gin.H{
@ -22,29 +49,41 @@ type ValidError struct {
Message string
}
type ValidErrors gin.H
func BindAndValid(c *gin.Context, v interface{}) (bool, ValidErrors) {
errs := make(ValidErrors)
err := c.ShouldBind(v)
if err != nil {
func BindAndValid(c *gin.Context, v interface{}) bool {
errs := make(map[string]string)
err := c.ShouldBindJSON(v)
if err != nil {
log.Println(err)
v := c.Value("trans")
trans, _ := v.(ut.Translator)
uni := ut.New(zh.New())
trans, _ := uni.GetTranslator("zh")
v, ok := binding.Validator.Engine().(*val.Validate)
verrs, ok := err.(val.ValidationErrors)
if !ok {
return false, errs
}
if ok {
_ = zhTranslations.RegisterDefaultTranslations(v, trans)
}
for key, value := range verrs.Translate(trans) {
k := strings.Split(key, ".")
sub := strings.ToLower(k[1])
errs[sub] = value
}
verrs, ok := err.(val.ValidationErrors)
if !ok {
log.Println(verrs)
c.JSON(http.StatusNotAcceptable, gin.H{
"message": "请求参数错误",
"code": http.StatusNotAcceptable,
})
return false
}
return false, errs
}
for key, value := range verrs.Translate(trans) {
errs[key[strings.Index(key, ".")+1:]] = value
}
return true, nil
c.JSON(http.StatusNotAcceptable, gin.H{
"errors": JsonSnakeCase{errs},
"message": "请求参数错误",
"code": http.StatusNotAcceptable,
})
return false
}
return true
}

View file

@ -15,11 +15,8 @@ type LoginUser struct {
func Login(c *gin.Context) {
var user LoginUser
ok, verrs := BindAndValid(c, &user)
ok := BindAndValid(c, &user)
if !ok {
c.JSON(http.StatusNotAcceptable, gin.H{
"errors": verrs,
})
return
}

View file

@ -15,30 +15,6 @@ import (
func CertInfo(c *gin.Context) {
domain := c.Param("domain")
/*sslCertificatePath := tool.GetNginxConfPath("ssl/" + domain +"/fullchain.cer")
content, err := ioutil.ReadFile(sslCertificatePath)
if err != nil {
ErrorHandler(c, err)
return
}
certDERBlock, _ := pem.Decode(content)
if certDERBlock == nil {
ErrorHandler(c, errors.New("pem decode error"))
return
}
var key *x509.Certificate
key, err = x509.ParseCertificate(certDERBlock.Bytes)
if err != nil {
ErrorHandler(c, err)
return
}*/
ts := &http.Transport{
TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
}

View file

@ -40,11 +40,8 @@ func InstallNginxUI(c *gin.Context) {
return
}
var json InstallJson
ok, verrs := BindAndValid(c, &json)
ok := BindAndValid(c, &json)
if !ok {
c.JSON(http.StatusNotAcceptable, gin.H{
"errors": verrs,
})
return
}

View file

@ -45,11 +45,8 @@ type UserJson struct {
func AddUser(c *gin.Context) {
var json UserJson
ok, verrs := BindAndValid(c, &json)
ok := BindAndValid(c, &json)
if !ok {
c.JSON(http.StatusNotAcceptable, gin.H{
"errors": verrs,
})
return
}
curd := model.NewCurd(&model.Auth{})
@ -79,11 +76,9 @@ func AddUser(c *gin.Context) {
func EditUser(c *gin.Context) {
var json UserJson
ok, verrs := BindAndValid(c, &json)
ok := BindAndValid(c, &json)
if !ok {
c.JSON(http.StatusNotAcceptable, gin.H{
"errors": verrs,
})
return
}
curd := model.NewCurd(&model.Auth{})