mirror of
https://github.com/0xJacky/nginx-ui.git
synced 2025-05-12 10:55:51 +02:00
parent
4a3e32a921
commit
a5b9bb88d6
18 changed files with 622 additions and 295 deletions
5
frontend/src/api/cert.ts
Normal file
5
frontend/src/api/cert.ts
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
import Curd from '@/api/curd'
|
||||||
|
|
||||||
|
const cert = new Curd('/cert')
|
||||||
|
|
||||||
|
export default cert
|
|
@ -15,11 +15,11 @@ class Domain extends Curd {
|
||||||
}
|
}
|
||||||
|
|
||||||
add_auto_cert(domain: string) {
|
add_auto_cert(domain: string) {
|
||||||
return http.post('cert/' + domain)
|
return http.post('auto_cert/' + domain)
|
||||||
}
|
}
|
||||||
|
|
||||||
remove_auto_cert(domain: string) {
|
remove_auto_cert(domain: string) {
|
||||||
return http.delete('cert/' + domain)
|
return http.delete('auto_cert/' + domain)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -17,7 +17,8 @@ msgstr "About"
|
||||||
msgid "Access Logs"
|
msgid "Access Logs"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/views/domain/DomainList.vue:47 src/views/user/User.vue:43
|
#: src/views/config/config.ts:36 src/views/domain/DomainList.vue:47
|
||||||
|
#: src/views/user/User.vue:43
|
||||||
msgid "Action"
|
msgid "Action"
|
||||||
msgstr "Action"
|
msgstr "Action"
|
||||||
|
|
||||||
|
@ -205,6 +206,10 @@ msgstr ""
|
||||||
msgid "Development Mode"
|
msgid "Development Mode"
|
||||||
msgstr "Development Mode"
|
msgstr "Development Mode"
|
||||||
|
|
||||||
|
#: src/views/config/config.ts:20
|
||||||
|
msgid "Dir"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: src/views/domain/ngx_conf/directive/DirectiveAdd.vue:20
|
#: src/views/domain/ngx_conf/directive/DirectiveAdd.vue:20
|
||||||
msgid "Directive"
|
msgid "Directive"
|
||||||
msgstr "Directive"
|
msgstr "Directive"
|
||||||
|
@ -308,6 +313,10 @@ msgstr "Failed to enable %{msg}"
|
||||||
msgid "Failed to get certificate information"
|
msgid "Failed to get certificate information"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/views/config/config.ts:22
|
||||||
|
msgid "File"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: src/views/other/Error.vue:3 src/views/other/Error.vue:4
|
#: src/views/other/Error.vue:3 src/views/other/Error.vue:4
|
||||||
msgid "File Not Found"
|
msgid "File Not Found"
|
||||||
msgstr "File Not Found"
|
msgstr "File Not Found"
|
||||||
|
@ -444,7 +453,8 @@ msgstr "Modify Config"
|
||||||
msgid "Modify Config"
|
msgid "Modify Config"
|
||||||
msgstr "Modify Config"
|
msgstr "Modify Config"
|
||||||
|
|
||||||
#: src/views/domain/DomainEdit.vue:36 src/views/domain/DomainList.vue:15
|
#: src/views/config/config.ts:9 src/views/domain/DomainEdit.vue:36
|
||||||
|
#: src/views/domain/DomainList.vue:15
|
||||||
msgid "Name"
|
msgid "Name"
|
||||||
msgstr "Name"
|
msgstr "Name"
|
||||||
|
|
||||||
|
@ -730,7 +740,12 @@ msgstr ""
|
||||||
msgid "Theme"
|
msgid "Theme"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/views/domain/DomainList.vue:41 src/views/user/User.vue:37
|
#: src/language/constants.ts:23 src/views/config/config.ts:14
|
||||||
|
msgid "Type"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/views/config/config.ts:29 src/views/domain/DomainList.vue:41
|
||||||
|
#: src/views/user/User.vue:37
|
||||||
msgid "Updated at"
|
msgid "Updated at"
|
||||||
msgstr "Updated at"
|
msgstr "Updated at"
|
||||||
|
|
||||||
|
|
|
@ -11,6 +11,7 @@ msgstr ""
|
||||||
msgid "Access Logs"
|
msgid "Access Logs"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/views/config/config.ts:36
|
||||||
#: src/views/domain/DomainList.vue:47
|
#: src/views/domain/DomainList.vue:47
|
||||||
#: src/views/user/User.vue:43
|
#: src/views/user/User.vue:43
|
||||||
msgid "Action"
|
msgid "Action"
|
||||||
|
@ -203,6 +204,10 @@ msgstr ""
|
||||||
msgid "Development Mode"
|
msgid "Development Mode"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/views/config/config.ts:20
|
||||||
|
msgid "Dir"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: src/views/domain/ngx_conf/directive/DirectiveAdd.vue:20
|
#: src/views/domain/ngx_conf/directive/DirectiveAdd.vue:20
|
||||||
msgid "Directive"
|
msgid "Directive"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
@ -320,6 +325,10 @@ msgstr ""
|
||||||
msgid "Failed to get certificate information"
|
msgid "Failed to get certificate information"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/views/config/config.ts:22
|
||||||
|
msgid "File"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: src/views/other/Error.vue:3
|
#: src/views/other/Error.vue:3
|
||||||
#: src/views/other/Error.vue:4
|
#: src/views/other/Error.vue:4
|
||||||
msgid "File Not Found"
|
msgid "File Not Found"
|
||||||
|
@ -456,6 +465,7 @@ msgstr ""
|
||||||
msgid "Modify Config"
|
msgid "Modify Config"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/views/config/config.ts:9
|
||||||
#: src/views/domain/DomainEdit.vue:36
|
#: src/views/domain/DomainEdit.vue:36
|
||||||
#: src/views/domain/DomainList.vue:15
|
#: src/views/domain/DomainList.vue:15
|
||||||
msgid "Name"
|
msgid "Name"
|
||||||
|
@ -747,6 +757,12 @@ msgstr ""
|
||||||
msgid "Theme"
|
msgid "Theme"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/language/constants.ts:23
|
||||||
|
#: src/views/config/config.ts:14
|
||||||
|
msgid "Type"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/views/config/config.ts:29
|
||||||
#: src/views/domain/DomainList.vue:41
|
#: src/views/domain/DomainList.vue:41
|
||||||
#: src/views/user/User.vue:37
|
#: src/views/user/User.vue:37
|
||||||
msgid "Updated at"
|
msgid "Updated at"
|
||||||
|
|
File diff suppressed because one or more lines are too long
Binary file not shown.
|
@ -20,7 +20,8 @@ msgstr "关于"
|
||||||
msgid "Access Logs"
|
msgid "Access Logs"
|
||||||
msgstr "访问日志"
|
msgstr "访问日志"
|
||||||
|
|
||||||
#: src/views/domain/DomainList.vue:47 src/views/user/User.vue:43
|
#: src/views/config/config.ts:36 src/views/domain/DomainList.vue:47
|
||||||
|
#: src/views/user/User.vue:43
|
||||||
msgid "Action"
|
msgid "Action"
|
||||||
msgstr "操作"
|
msgstr "操作"
|
||||||
|
|
||||||
|
@ -204,6 +205,10 @@ msgstr "删除站点: %{site_name}"
|
||||||
msgid "Development Mode"
|
msgid "Development Mode"
|
||||||
msgstr "开发模式"
|
msgstr "开发模式"
|
||||||
|
|
||||||
|
#: src/views/config/config.ts:20
|
||||||
|
msgid "Dir"
|
||||||
|
msgstr "目录"
|
||||||
|
|
||||||
#: src/views/domain/ngx_conf/directive/DirectiveAdd.vue:20
|
#: src/views/domain/ngx_conf/directive/DirectiveAdd.vue:20
|
||||||
msgid "Directive"
|
msgid "Directive"
|
||||||
msgstr "指令"
|
msgstr "指令"
|
||||||
|
@ -307,6 +312,10 @@ msgstr "启用失败 %{msg}"
|
||||||
msgid "Failed to get certificate information"
|
msgid "Failed to get certificate information"
|
||||||
msgstr "获取证书信息失败"
|
msgstr "获取证书信息失败"
|
||||||
|
|
||||||
|
#: src/views/config/config.ts:22
|
||||||
|
msgid "File"
|
||||||
|
msgstr "文件"
|
||||||
|
|
||||||
#: src/views/other/Error.vue:3 src/views/other/Error.vue:4
|
#: src/views/other/Error.vue:3 src/views/other/Error.vue:4
|
||||||
msgid "File Not Found"
|
msgid "File Not Found"
|
||||||
msgstr "未找到文件"
|
msgstr "未找到文件"
|
||||||
|
@ -440,7 +449,8 @@ msgstr "修改"
|
||||||
msgid "Modify Config"
|
msgid "Modify Config"
|
||||||
msgstr "修改配置文件"
|
msgstr "修改配置文件"
|
||||||
|
|
||||||
#: src/views/domain/DomainEdit.vue:36 src/views/domain/DomainList.vue:15
|
#: src/views/config/config.ts:9 src/views/domain/DomainEdit.vue:36
|
||||||
|
#: src/views/domain/DomainList.vue:15
|
||||||
msgid "Name"
|
msgid "Name"
|
||||||
msgstr "名称"
|
msgstr "名称"
|
||||||
|
|
||||||
|
@ -717,7 +727,12 @@ msgstr "用户名或密码错误"
|
||||||
msgid "Theme"
|
msgid "Theme"
|
||||||
msgstr "主题"
|
msgstr "主题"
|
||||||
|
|
||||||
#: src/views/domain/DomainList.vue:41 src/views/user/User.vue:37
|
#: src/language/constants.ts:23 src/views/config/config.ts:14
|
||||||
|
msgid "Type"
|
||||||
|
msgstr "类型"
|
||||||
|
|
||||||
|
#: src/views/config/config.ts:29 src/views/domain/DomainList.vue:41
|
||||||
|
#: src/views/user/User.vue:37
|
||||||
msgid "Updated at"
|
msgid "Updated at"
|
||||||
msgstr "修改时间"
|
msgstr "修改时间"
|
||||||
|
|
||||||
|
|
|
@ -21,7 +21,8 @@ msgstr "關於"
|
||||||
msgid "Access Logs"
|
msgid "Access Logs"
|
||||||
msgstr "訪問日誌"
|
msgstr "訪問日誌"
|
||||||
|
|
||||||
#: src/views/domain/DomainList.vue:47 src/views/user/User.vue:43
|
#: src/views/config/config.ts:36 src/views/domain/DomainList.vue:47
|
||||||
|
#: src/views/user/User.vue:43
|
||||||
msgid "Action"
|
msgid "Action"
|
||||||
msgstr "操作"
|
msgstr "操作"
|
||||||
|
|
||||||
|
@ -205,6 +206,10 @@ msgstr "刪除站點:%{site_name}"
|
||||||
msgid "Development Mode"
|
msgid "Development Mode"
|
||||||
msgstr "開發模式"
|
msgstr "開發模式"
|
||||||
|
|
||||||
|
#: src/views/config/config.ts:20
|
||||||
|
msgid "Dir"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: src/views/domain/ngx_conf/directive/DirectiveAdd.vue:20
|
#: src/views/domain/ngx_conf/directive/DirectiveAdd.vue:20
|
||||||
msgid "Directive"
|
msgid "Directive"
|
||||||
msgstr "指令"
|
msgstr "指令"
|
||||||
|
@ -308,6 +313,10 @@ msgstr "啟用失敗 %{msg}"
|
||||||
msgid "Failed to get certificate information"
|
msgid "Failed to get certificate information"
|
||||||
msgstr "獲取證書信息失敗"
|
msgstr "獲取證書信息失敗"
|
||||||
|
|
||||||
|
#: src/views/config/config.ts:22
|
||||||
|
msgid "File"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: src/views/other/Error.vue:3 src/views/other/Error.vue:4
|
#: src/views/other/Error.vue:3 src/views/other/Error.vue:4
|
||||||
msgid "File Not Found"
|
msgid "File Not Found"
|
||||||
msgstr "未找到檔案"
|
msgstr "未找到檔案"
|
||||||
|
@ -443,7 +452,8 @@ msgstr "修改"
|
||||||
msgid "Modify Config"
|
msgid "Modify Config"
|
||||||
msgstr "修改配置"
|
msgstr "修改配置"
|
||||||
|
|
||||||
#: src/views/domain/DomainEdit.vue:36 src/views/domain/DomainList.vue:15
|
#: src/views/config/config.ts:9 src/views/domain/DomainEdit.vue:36
|
||||||
|
#: src/views/domain/DomainList.vue:15
|
||||||
msgid "Name"
|
msgid "Name"
|
||||||
msgstr "名稱"
|
msgstr "名稱"
|
||||||
|
|
||||||
|
@ -724,7 +734,12 @@ msgstr "用戶名或密碼不正確"
|
||||||
msgid "Theme"
|
msgid "Theme"
|
||||||
msgstr "外觀樣式"
|
msgstr "外觀樣式"
|
||||||
|
|
||||||
#: src/views/domain/DomainList.vue:41 src/views/user/User.vue:37
|
#: src/language/constants.ts:23 src/views/config/config.ts:14
|
||||||
|
msgid "Type"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/views/config/config.ts:29 src/views/domain/DomainList.vue:41
|
||||||
|
#: src/views/user/User.vue:37
|
||||||
msgid "Updated at"
|
msgid "Updated at"
|
||||||
msgstr "修改時間"
|
msgstr "修改時間"
|
||||||
|
|
||||||
|
|
|
@ -10,7 +10,8 @@ import {
|
||||||
InfoCircleOutlined,
|
InfoCircleOutlined,
|
||||||
UserOutlined,
|
UserOutlined,
|
||||||
FileTextOutlined,
|
FileTextOutlined,
|
||||||
SettingOutlined
|
SettingOutlined,
|
||||||
|
SafetyCertificateOutlined
|
||||||
} from '@ant-design/icons-vue'
|
} from '@ant-design/icons-vue'
|
||||||
|
|
||||||
const {$gettext} = gettext
|
const {$gettext} = gettext
|
||||||
|
@ -91,6 +92,14 @@ export const routes = [
|
||||||
hiddenInSidebar: true
|
hiddenInSidebar: true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path: 'cert',
|
||||||
|
name: () => $gettext('Certification'),
|
||||||
|
component: () => import('@/views/cert/Cert.vue'),
|
||||||
|
meta: {
|
||||||
|
icon: SafetyCertificateOutlined
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
path: 'terminal',
|
path: 'terminal',
|
||||||
name: () => $gettext('Terminal'),
|
name: () => $gettext('Terminal'),
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
{"version":"1.7.0","build_id":62,"total_build":132}
|
{"version":"1.7.0","build_id":63,"total_build":133}
|
88
frontend/src/views/cert/Cert.vue
Normal file
88
frontend/src/views/cert/Cert.vue
Normal file
|
@ -0,0 +1,88 @@
|
||||||
|
<script setup lang="tsx">
|
||||||
|
import {useGettext} from 'vue3-gettext'
|
||||||
|
import {input} from '@/components/StdDataEntry'
|
||||||
|
import {customRender, datetime} from '@/components/StdDataDisplay/StdTableTransformer'
|
||||||
|
import {h} from 'vue'
|
||||||
|
import {Badge} from 'ant-design-vue'
|
||||||
|
import cert from '@/api/cert'
|
||||||
|
import StdCurd from '@/components/StdDataDisplay/StdCurd.vue'
|
||||||
|
|
||||||
|
const {$gettext} = useGettext()
|
||||||
|
|
||||||
|
const columns = [{
|
||||||
|
title: () => $gettext('Name'),
|
||||||
|
dataIndex: 'name',
|
||||||
|
sorter: true,
|
||||||
|
pithy: true,
|
||||||
|
customRender: (args: customRender) => {
|
||||||
|
const {text, record} = args
|
||||||
|
if (!text) {
|
||||||
|
return h('div', record.domain)
|
||||||
|
}
|
||||||
|
return h('div', text)
|
||||||
|
},
|
||||||
|
edit: {
|
||||||
|
type: input
|
||||||
|
},
|
||||||
|
search: true
|
||||||
|
}, {
|
||||||
|
title: () => $gettext('Domain'),
|
||||||
|
dataIndex: 'domain',
|
||||||
|
sorter: true,
|
||||||
|
pithy: true,
|
||||||
|
edit: {
|
||||||
|
type: input
|
||||||
|
},
|
||||||
|
search: true
|
||||||
|
}, {
|
||||||
|
title: () => $gettext('Auto Cert'),
|
||||||
|
dataIndex: 'auto_cert',
|
||||||
|
customRender: (args: customRender) => {
|
||||||
|
const template: any = []
|
||||||
|
const {text, column} = args
|
||||||
|
if (text === true || text > 0) {
|
||||||
|
template.push(<Badge status="success"/>)
|
||||||
|
template.push($gettext('Enabled'))
|
||||||
|
} else {
|
||||||
|
template.push(<Badge status="error"/>)
|
||||||
|
template.push($gettext('Disabled'))
|
||||||
|
}
|
||||||
|
return h('div', template)
|
||||||
|
},
|
||||||
|
sorter: true,
|
||||||
|
pithy: true
|
||||||
|
}, {
|
||||||
|
title: () => $gettext('SSL Certificate Path'),
|
||||||
|
dataIndex: 'ssl_certificate_path',
|
||||||
|
edit: {
|
||||||
|
type: input
|
||||||
|
},
|
||||||
|
display: false
|
||||||
|
}, {
|
||||||
|
title: () => $gettext('SSL Certificate Key Path'),
|
||||||
|
dataIndex: 'ssl_certificate_key_path',
|
||||||
|
edit: {
|
||||||
|
type: input
|
||||||
|
},
|
||||||
|
display: false
|
||||||
|
}, {
|
||||||
|
title: () => $gettext('Updated at'),
|
||||||
|
dataIndex: 'updated_at',
|
||||||
|
customRender: datetime,
|
||||||
|
sorter: true,
|
||||||
|
pithy: true
|
||||||
|
}, {
|
||||||
|
title: () => $gettext('Action'),
|
||||||
|
dataIndex: 'action'
|
||||||
|
}]
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<std-curd :title="$gettext('Certification')" :api="cert" :columns="columns"
|
||||||
|
row-key="name"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style lang="less" scoped>
|
||||||
|
|
||||||
|
</style>
|
|
@ -3,7 +3,6 @@ import gettext from '@/gettext'
|
||||||
|
|
||||||
const {$gettext} = gettext
|
const {$gettext} = gettext
|
||||||
|
|
||||||
import {Badge} from 'ant-design-vue'
|
|
||||||
import {h} from 'vue'
|
import {h} from 'vue'
|
||||||
|
|
||||||
const configColumns = [{
|
const configColumns = [{
|
11
frontend/src/views/template/Template.vue
Normal file
11
frontend/src/views/template/Template.vue
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
<script setup lang="ts">
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style lang="less" scoped>
|
||||||
|
|
||||||
|
</style>
|
|
@ -1 +1 @@
|
||||||
{"version":"1.7.0","build_id":62,"total_build":132}
|
{"version":"1.7.0","build_id":63,"total_build":133}
|
|
@ -6,6 +6,7 @@ import (
|
||||||
"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"
|
||||||
"github.com/gorilla/websocket"
|
"github.com/gorilla/websocket"
|
||||||
|
"github.com/spf13/cast"
|
||||||
"log"
|
"log"
|
||||||
"net/http"
|
"net/http"
|
||||||
"strings"
|
"strings"
|
||||||
|
@ -117,7 +118,8 @@ func IssueCert(c *gin.Context) {
|
||||||
}
|
}
|
||||||
|
|
||||||
err = certModel.Updates(&model.Cert{
|
err = certModel.Updates(&model.Cert{
|
||||||
SSLCertificatePath: sslCertificatePath,
|
SSLCertificatePath: sslCertificatePath,
|
||||||
|
SSLCertificateKeyPath: sslCertificateKeyPath,
|
||||||
})
|
})
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -137,3 +139,108 @@ func IssueCert(c *gin.Context) {
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func GetCertList(c *gin.Context) {
|
||||||
|
certList := model.GetCertList(c.Query("name"), c.Query("domain"))
|
||||||
|
|
||||||
|
c.JSON(http.StatusOK, gin.H{
|
||||||
|
"data": certList,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetCert(c *gin.Context) {
|
||||||
|
certModel, err := model.FirstCertByID(cast.ToInt(c.Param("id")))
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
ErrHandler(c, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
c.JSON(http.StatusOK, certModel)
|
||||||
|
}
|
||||||
|
|
||||||
|
func AddCert(c *gin.Context) {
|
||||||
|
var json struct {
|
||||||
|
Name string `json:"name" binding:"required"`
|
||||||
|
Domain string `json:"domain" binding:"required"`
|
||||||
|
SSLCertificatePath string `json:"ssl_certificate_path" binding:"required"`
|
||||||
|
SSLCertificateKeyPath string `json:"ssl_certificate_key_path" binding:"required"`
|
||||||
|
}
|
||||||
|
if !BindAndValid(c, &json) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
certModel, err := model.FirstOrCreateCert(json.Domain)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
ErrHandler(c, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
err = certModel.Updates(&model.Cert{
|
||||||
|
Name: json.Name,
|
||||||
|
Domain: json.Domain,
|
||||||
|
SSLCertificatePath: json.SSLCertificatePath,
|
||||||
|
SSLCertificateKeyPath: json.SSLCertificateKeyPath,
|
||||||
|
})
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
ErrHandler(c, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
c.JSON(http.StatusOK, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
func ModifyCert(c *gin.Context) {
|
||||||
|
id := cast.ToInt(c.Param("id"))
|
||||||
|
certModel, err := model.FirstCertByID(id)
|
||||||
|
|
||||||
|
var json struct {
|
||||||
|
Name string `json:"name" binding:"required"`
|
||||||
|
Domain string `json:"domain" binding:"required"`
|
||||||
|
SSLCertificatePath string `json:"ssl_certificate_path" binding:"required"`
|
||||||
|
SSLCertificateKeyPath string `json:"ssl_certificate_key_path" binding:"required"`
|
||||||
|
}
|
||||||
|
|
||||||
|
if !BindAndValid(c, &json) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
ErrHandler(c, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
err = certModel.Updates(&model.Cert{
|
||||||
|
Name: json.Name,
|
||||||
|
Domain: json.Domain,
|
||||||
|
SSLCertificatePath: json.SSLCertificatePath,
|
||||||
|
SSLCertificateKeyPath: json.SSLCertificateKeyPath,
|
||||||
|
})
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
ErrHandler(c, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
c.JSON(http.StatusOK, certModel)
|
||||||
|
}
|
||||||
|
|
||||||
|
func RemoveCert(c *gin.Context) {
|
||||||
|
id := cast.ToInt(c.Param("id"))
|
||||||
|
certModel, err := model.FirstCertByID(id)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
ErrHandler(c, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
err = certModel.Remove()
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
ErrHandler(c, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
c.JSON(http.StatusOK, nil)
|
||||||
|
}
|
||||||
|
|
|
@ -1,365 +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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = 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.BuildConfig(),
|
||||||
"tokenized": config,
|
"tokenized": config,
|
||||||
"auto_cert": err == nil,
|
"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, " ", "_")
|
||||||
|
certModel, err := model.FirstOrCreateCert(domain)
|
||||||
|
|
||||||
certModel, err := model.FirstOrCreateCert(domain)
|
if err != nil {
|
||||||
if err != nil {
|
ErrHandler(c, err)
|
||||||
ErrHandler(c, err)
|
return
|
||||||
return
|
}
|
||||||
}
|
|
||||||
c.JSON(http.StatusOK, certModel)
|
err = certModel.Updates(&model.Cert{
|
||||||
|
AutoCert: model.AutoCertEnabled,
|
||||||
|
})
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
ErrHandler(c, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
c.JSON(http.StatusOK, certModel)
|
||||||
}
|
}
|
||||||
|
|
||||||
func RemoveDomainFromAutoCert(c *gin.Context) {
|
func RemoveDomainFromAutoCert(c *gin.Context) {
|
||||||
certModel := model.Cert{
|
domain := c.Param("domain")
|
||||||
Domain: c.Param("domain"),
|
domain = strings.ReplaceAll(domain, " ", "_")
|
||||||
}
|
certModel := model.Cert{
|
||||||
err := certModel.Remove()
|
Domain: domain,
|
||||||
|
}
|
||||||
|
|
||||||
if err != nil {
|
err := certModel.Updates(&model.Cert{
|
||||||
ErrHandler(c, err)
|
AutoCert: model.AutoCertDisabled,
|
||||||
return
|
})
|
||||||
}
|
|
||||||
c.JSON(http.StatusOK, nil)
|
if err != nil {
|
||||||
|
ErrHandler(c, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
c.JSON(http.StatusOK, nil)
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,10 +6,18 @@ import (
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
AutoCertEnabled = 1
|
||||||
|
AutoCertDisabled = -1
|
||||||
|
)
|
||||||
|
|
||||||
type Cert struct {
|
type Cert struct {
|
||||||
Model
|
Model
|
||||||
Domain string `json:"domain"`
|
Name string `json:"name"`
|
||||||
SSLCertificatePath string `json:"ssl_certificate_path"`
|
Domain string `json:"domain"`
|
||||||
|
SSLCertificatePath string `json:"ssl_certificate_path"`
|
||||||
|
SSLCertificateKeyPath string `json:"ssl_certificate_key_path"`
|
||||||
|
AutoCert int `json:"auto_cert"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func FirstCert(domain string) (c Cert, err error) {
|
func FirstCert(domain string) (c Cert, err error) {
|
||||||
|
@ -27,7 +35,7 @@ func FirstOrCreateCert(domain string) (c Cert, err error) {
|
||||||
|
|
||||||
func GetAutoCertList() (c []Cert) {
|
func GetAutoCertList() (c []Cert) {
|
||||||
var t []Cert
|
var t []Cert
|
||||||
db.Find(&t)
|
db.Where("auto_cert", AutoCertEnabled).Find(&t)
|
||||||
|
|
||||||
// check if this domain is enabled
|
// check if this domain is enabled
|
||||||
enabledConfig, err := os.ReadDir(filepath.Join(nginx.GetNginxConfPath("sites-enabled")))
|
enabledConfig, err := os.ReadDir(filepath.Join(nginx.GetNginxConfPath("sites-enabled")))
|
||||||
|
@ -50,6 +58,24 @@ func GetAutoCertList() (c []Cert) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func GetCertList(name, domain string) (c []Cert) {
|
||||||
|
tx := db
|
||||||
|
if name != "" {
|
||||||
|
tx = tx.Where("name LIKE ? or domain LIKE ?", "%"+name+"%", "%"+name+"%")
|
||||||
|
}
|
||||||
|
if domain != "" {
|
||||||
|
tx = tx.Where("domain LIKE ?", "%"+domain+"%")
|
||||||
|
}
|
||||||
|
tx.Find(&c)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func FirstCertByID(id int) (c Cert, err error) {
|
||||||
|
err = db.First(&c, id).Error
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
func (c *Cert) Updates(n *Cert) error {
|
func (c *Cert) Updates(n *Cert) error {
|
||||||
return db.Model(c).Updates(n).Error
|
return db.Model(c).Updates(n).Error
|
||||||
}
|
}
|
||||||
|
|
|
@ -77,10 +77,15 @@ func InitRouter() *gin.Engine {
|
||||||
|
|
||||||
g.GET("cert/issue", api.IssueCert)
|
g.GET("cert/issue", api.IssueCert)
|
||||||
|
|
||||||
|
g.GET("certs", api.GetCertList)
|
||||||
|
g.GET("cert/:id", api.GetCert)
|
||||||
|
g.POST("cert", api.AddCert)
|
||||||
|
g.POST("cert/:id", api.ModifyCert)
|
||||||
|
g.DELETE("cert/:id", api.RemoveCert)
|
||||||
// Add domain to auto-renew cert list
|
// Add domain to auto-renew cert list
|
||||||
g.POST("cert/:domain", api.AddDomainToAutoCert)
|
g.POST("auto_cert/:domain", api.AddDomainToAutoCert)
|
||||||
// Delete domain from auto-renew cert list
|
// Delete domain from auto-renew cert list
|
||||||
g.DELETE("cert/:domain", api.RemoveDomainFromAutoCert)
|
g.DELETE("auto_cert/:domain", api.RemoveDomainFromAutoCert)
|
||||||
|
|
||||||
// pty
|
// pty
|
||||||
g.GET("pty", api.Pty)
|
g.GET("pty", api.Pty)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue